@carno.js/orm 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/LICENSE +674 -0
  2. package/dist/SqlBuilder.d.ts +103 -0
  3. package/dist/SqlBuilder.js +618 -0
  4. package/dist/cache/cache-key-generator.d.ts +13 -0
  5. package/dist/cache/cache-key-generator.js +66 -0
  6. package/dist/cache/query-cache-manager.d.ts +14 -0
  7. package/dist/cache/query-cache-manager.js +44 -0
  8. package/dist/common/email.vo.d.ts +4 -0
  9. package/dist/common/email.vo.js +11 -0
  10. package/dist/common/uuid.d.ts +4 -0
  11. package/dist/common/uuid.js +10 -0
  12. package/dist/common/value-object.d.ts +95 -0
  13. package/dist/common/value-object.js +99 -0
  14. package/dist/constants.d.ts +6 -0
  15. package/dist/constants.js +9 -0
  16. package/dist/decorators/computed.decorator.d.ts +1 -0
  17. package/dist/decorators/computed.decorator.js +12 -0
  18. package/dist/decorators/entity.decorator.d.ts +3 -0
  19. package/dist/decorators/entity.decorator.js +12 -0
  20. package/dist/decorators/enum.decorator.d.ts +2 -0
  21. package/dist/decorators/enum.decorator.js +16 -0
  22. package/dist/decorators/event-hook.decorator.d.ts +4 -0
  23. package/dist/decorators/event-hook.decorator.js +31 -0
  24. package/dist/decorators/index.decorator.d.ts +17 -0
  25. package/dist/decorators/index.decorator.js +36 -0
  26. package/dist/decorators/one-many.decorator.d.ts +6 -0
  27. package/dist/decorators/one-many.decorator.js +42 -0
  28. package/dist/decorators/primary-key.decorator.d.ts +2 -0
  29. package/dist/decorators/primary-key.decorator.js +8 -0
  30. package/dist/decorators/property.decorator.d.ts +24 -0
  31. package/dist/decorators/property.decorator.js +44 -0
  32. package/dist/decorators/unique.decorator.d.ts +9 -0
  33. package/dist/decorators/unique.decorator.js +44 -0
  34. package/dist/domain/base-entity.d.ts +57 -0
  35. package/dist/domain/base-entity.js +198 -0
  36. package/dist/domain/collection.d.ts +6 -0
  37. package/dist/domain/collection.js +15 -0
  38. package/dist/domain/entities.d.ts +49 -0
  39. package/dist/domain/entities.js +259 -0
  40. package/dist/domain/reference.d.ts +86 -0
  41. package/dist/domain/reference.js +86 -0
  42. package/dist/driver/bun-driver.base.d.ts +72 -0
  43. package/dist/driver/bun-driver.base.js +270 -0
  44. package/dist/driver/bun-mysql.driver.d.ts +53 -0
  45. package/dist/driver/bun-mysql.driver.js +256 -0
  46. package/dist/driver/bun-pg.driver.d.ts +52 -0
  47. package/dist/driver/bun-pg.driver.js +263 -0
  48. package/dist/driver/driver.interface.d.ts +333 -0
  49. package/dist/driver/driver.interface.js +2 -0
  50. package/dist/entry.d.ts +2 -0
  51. package/dist/entry.js +13 -0
  52. package/dist/identity-map/entity-key-generator.d.ts +10 -0
  53. package/dist/identity-map/entity-key-generator.js +45 -0
  54. package/dist/identity-map/entity-registry.d.ts +11 -0
  55. package/dist/identity-map/entity-registry.js +41 -0
  56. package/dist/identity-map/identity-map-context.d.ts +9 -0
  57. package/dist/identity-map/identity-map-context.js +22 -0
  58. package/dist/identity-map/identity-map-integration.d.ts +5 -0
  59. package/dist/identity-map/identity-map-integration.js +37 -0
  60. package/dist/identity-map/identity-map.d.ts +11 -0
  61. package/dist/identity-map/identity-map.js +35 -0
  62. package/dist/identity-map/index.d.ts +5 -0
  63. package/dist/identity-map/index.js +14 -0
  64. package/dist/index.d.ts +28 -0
  65. package/dist/index.js +48 -0
  66. package/dist/middleware/identity-map.middleware.d.ts +4 -0
  67. package/dist/middleware/identity-map.middleware.js +22 -0
  68. package/dist/orm-session-context.d.ts +16 -0
  69. package/dist/orm-session-context.js +22 -0
  70. package/dist/orm.d.ts +20 -0
  71. package/dist/orm.js +69 -0
  72. package/dist/orm.service.d.ts +13 -0
  73. package/dist/orm.service.js +361 -0
  74. package/dist/query/index-condition-builder.d.ts +41 -0
  75. package/dist/query/index-condition-builder.js +235 -0
  76. package/dist/query/model-transformer.d.ts +27 -0
  77. package/dist/query/model-transformer.js +201 -0
  78. package/dist/query/sql-column-manager.d.ts +28 -0
  79. package/dist/query/sql-column-manager.js +157 -0
  80. package/dist/query/sql-condition-builder.d.ts +51 -0
  81. package/dist/query/sql-condition-builder.js +264 -0
  82. package/dist/query/sql-join-manager.d.ts +39 -0
  83. package/dist/query/sql-join-manager.js +242 -0
  84. package/dist/query/sql-subquery-builder.d.ts +20 -0
  85. package/dist/query/sql-subquery-builder.js +119 -0
  86. package/dist/repository/Repository.d.ts +121 -0
  87. package/dist/repository/Repository.js +174 -0
  88. package/dist/testing/index.d.ts +1 -0
  89. package/dist/testing/index.js +17 -0
  90. package/dist/testing/with-database.d.ts +20 -0
  91. package/dist/testing/with-database.js +311 -0
  92. package/dist/transaction/transaction-context.d.ts +10 -0
  93. package/dist/transaction/transaction-context.js +19 -0
  94. package/dist/utils/value-processor.d.ts +14 -0
  95. package/dist/utils/value-processor.js +94 -0
  96. package/dist/utils.d.ts +3 -0
  97. package/dist/utils.js +24 -0
  98. package/package.json +59 -0
@@ -0,0 +1,618 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SqlBuilder = void 0;
4
+ const entities_1 = require("./domain/entities");
5
+ const orm_1 = require("./orm");
6
+ const value_processor_1 = require("./utils/value-processor");
7
+ const sql_condition_builder_1 = require("./query/sql-condition-builder");
8
+ const sql_subquery_builder_1 = require("./query/sql-subquery-builder");
9
+ const model_transformer_1 = require("./query/model-transformer");
10
+ const sql_column_manager_1 = require("./query/sql-column-manager");
11
+ const sql_join_manager_1 = require("./query/sql-join-manager");
12
+ class SqlBuilder {
13
+ constructor(model) {
14
+ this.statements = {};
15
+ this.aliases = new Set();
16
+ this.updatedColumns = [];
17
+ this.originalColumns = [];
18
+ const orm = orm_1.Orm.getInstance();
19
+ this.driver = orm.driverInstance;
20
+ this.logger = orm.logger;
21
+ this.entityStorage = entities_1.EntityStorage.getInstance();
22
+ this.initializeCacheManager();
23
+ this.getEntity(model);
24
+ this.statements.hooks = this.entity.hooks;
25
+ this.modelTransformer = new model_transformer_1.ModelTransformer(this.entityStorage);
26
+ this.columnManager = new sql_column_manager_1.SqlColumnManager(this.entityStorage, this.statements, this.entity);
27
+ const applyJoinWrapper = (relationship, value, alias) => {
28
+ return this.joinManager.applyJoin(relationship, value, alias);
29
+ };
30
+ this.conditionBuilder = new sql_condition_builder_1.SqlConditionBuilder(this.entityStorage, applyJoinWrapper, this.statements);
31
+ const subqueryBuilder = new sql_subquery_builder_1.SqlSubqueryBuilder(this.entityStorage, () => this.conditionBuilder);
32
+ this.conditionBuilder.setSubqueryBuilder(subqueryBuilder);
33
+ this.joinManager = new sql_join_manager_1.SqlJoinManager(this.entityStorage, this.statements, this.entity, this.model, this.driver, this.logger, this.conditionBuilder, this.columnManager, this.modelTransformer, () => this.originalColumns, this.getAlias.bind(this));
34
+ }
35
+ initializeCacheManager() {
36
+ try {
37
+ const orm = orm_1.Orm.getInstance();
38
+ this.cacheManager = orm.queryCacheManager;
39
+ }
40
+ catch (error) {
41
+ this.cacheManager = undefined;
42
+ }
43
+ }
44
+ select(columns) {
45
+ const tableName = this.entity.tableName || this.model.name.toLowerCase();
46
+ const schema = this.entity.schema || 'public';
47
+ this.statements.statement = 'select';
48
+ this.statements.columns = columns;
49
+ this.originalColumns = columns || [];
50
+ this.statements.alias = this.getAlias(tableName);
51
+ this.statements.table = `"${schema}"."${tableName}"`;
52
+ return this;
53
+ }
54
+ setStrategy(strategy = 'joined') {
55
+ this.statements.strategy = strategy;
56
+ return this;
57
+ }
58
+ setInstance(instance) {
59
+ this.statements.instance = instance;
60
+ return this;
61
+ }
62
+ insert(values) {
63
+ const { tableName, schema } = this.getTableName();
64
+ const processedValues = value_processor_1.ValueProcessor.processForInsert(values, this.entity);
65
+ this.statements.statement = 'insert';
66
+ this.statements.instance = value_processor_1.ValueProcessor.createInstance(processedValues, this.model, 'insert');
67
+ this.statements.alias = this.getAlias(tableName);
68
+ this.statements.table = `"${schema}"."${tableName}"`;
69
+ this.statements.values = this.withUpdatedValues(this.withDefaultValues(processedValues, this.entity), this.entity);
70
+ this.reflectToValues();
71
+ return this;
72
+ }
73
+ update(values) {
74
+ const { tableName, schema } = this.getTableName();
75
+ const processedValues = value_processor_1.ValueProcessor.processForUpdate(values, this.entity);
76
+ this.statements.statement = 'update';
77
+ this.statements.alias = this.getAlias(tableName);
78
+ this.statements.table = `${schema}.${tableName}`;
79
+ this.statements.values = this.withUpdatedValues(processedValues, this.entity);
80
+ this.statements.instance = value_processor_1.ValueProcessor.createInstance(processedValues, this.model, 'update');
81
+ return this;
82
+ }
83
+ delete() {
84
+ const { tableName, schema } = this.getTableName();
85
+ this.statements.statement = 'delete';
86
+ this.statements.alias = this.getAlias(tableName);
87
+ this.statements.table = `${schema}.${tableName}`;
88
+ return this;
89
+ }
90
+ where(where) {
91
+ if (!where || Object.keys(where).length === 0) {
92
+ return this;
93
+ }
94
+ const newWhere = {};
95
+ for (const key in where) {
96
+ if (where[key] instanceof Object) {
97
+ newWhere[key] = where[key];
98
+ continue;
99
+ }
100
+ newWhere[value_processor_1.ValueProcessor.getColumnName(key, this.entity)] = where[key];
101
+ }
102
+ where = newWhere;
103
+ this.statements.where = this.conditionBuilder.build(where, this.statements.alias, this.model);
104
+ return this;
105
+ }
106
+ orderBy(orderBy) {
107
+ if (!orderBy) {
108
+ return this;
109
+ }
110
+ this.statements.orderBy = this.objectToStringMap(orderBy);
111
+ return this;
112
+ }
113
+ limit(limit) {
114
+ this.statements.limit = limit;
115
+ return this;
116
+ }
117
+ offset(offset) {
118
+ this.statements.offset = offset;
119
+ return this;
120
+ }
121
+ cache(cache) {
122
+ this.statements.cache = cache;
123
+ return this;
124
+ }
125
+ load(load) {
126
+ load?.forEach(relationshipPath => {
127
+ this.joinManager.addJoinForRelationshipPath(relationshipPath);
128
+ });
129
+ if (this.statements.join) {
130
+ this.statements.join = this.statements.join?.reverse();
131
+ }
132
+ if (this.statements.selectJoin) {
133
+ this.statements.selectJoin = this.statements.selectJoin?.reverse();
134
+ }
135
+ return this;
136
+ }
137
+ count() {
138
+ const { tableName, schema } = this.getTableName();
139
+ this.statements.statement = 'count';
140
+ this.statements.alias = this.getAlias(tableName);
141
+ this.statements.table = `"${schema}"."${tableName}"`;
142
+ return this;
143
+ }
144
+ getPrimaryKeyColumnName(entity) {
145
+ // Lógica para obter o nome da coluna de chave primária da entidade
146
+ // Aqui você pode substituir por sua própria lógica, dependendo da estrutura do seu projeto
147
+ // Por exemplo, se a chave primária for sempre 'id', você pode retornar 'id'.
148
+ // Se a lógica for mais complexa, você pode adicionar um método na classe Options para obter a chave primária.
149
+ return 'id';
150
+ }
151
+ shouldUseCache() {
152
+ if (this.statements.statement !== 'select') {
153
+ return false;
154
+ }
155
+ if (this.statements.cache instanceof Date) {
156
+ return this.statements.cache.getTime() > Date.now();
157
+ }
158
+ return this.statements.cache !== undefined;
159
+ }
160
+ getCacheTtl() {
161
+ if (this.statements.cache === true) {
162
+ return undefined;
163
+ }
164
+ if (this.statements.cache instanceof Date) {
165
+ const diff = this.statements.cache.getTime() - Date.now();
166
+ return diff > 0 ? diff : 0;
167
+ }
168
+ return this.statements.cache;
169
+ }
170
+ async getCachedResult() {
171
+ if (!this.cacheManager) {
172
+ return undefined;
173
+ }
174
+ return this.cacheManager.get(this.statements);
175
+ }
176
+ async setCachedResult(result) {
177
+ if (!this.cacheManager) {
178
+ return;
179
+ }
180
+ const ttl = this.getCacheTtl();
181
+ if (ttl === 0) {
182
+ return;
183
+ }
184
+ await this.cacheManager.set(this.statements, result, ttl);
185
+ }
186
+ async execute() {
187
+ this.prepareColumns();
188
+ this.statements.join = this.statements.join?.reverse();
189
+ if (this.shouldUseCache()) {
190
+ const cached = await this.getCachedResult();
191
+ if (cached) {
192
+ return cached;
193
+ }
194
+ }
195
+ this.beforeHooks();
196
+ const result = await this.driver.executeStatement(this.statements);
197
+ this.logExecution(result);
198
+ if (this.shouldUseCache()) {
199
+ await this.setCachedResult(result);
200
+ }
201
+ return result;
202
+ }
203
+ isWriteOperation() {
204
+ const writeOps = ['insert', 'update', 'delete'];
205
+ return writeOps.includes(this.statements.statement || '');
206
+ }
207
+ async invalidateCache() {
208
+ if (!this.cacheManager) {
209
+ return;
210
+ }
211
+ await this.cacheManager.invalidate(this.statements);
212
+ }
213
+ prepareColumns() {
214
+ if (!this.statements.columns) {
215
+ this.statements.columns = this.columnManager.generateColumns(this.model, this.updatedColumns);
216
+ return;
217
+ }
218
+ this.statements.columns = [
219
+ ...this.columnManager.processUserColumns(this.statements.columns),
220
+ ...this.updatedColumns
221
+ ];
222
+ }
223
+ beforeHooks() {
224
+ if (this.statements.statement === 'update') {
225
+ this.callHook('beforeUpdate', this.statements.instance);
226
+ return;
227
+ }
228
+ if (this.statements.statement === 'insert') {
229
+ this.callHook('beforeCreate');
230
+ return;
231
+ }
232
+ }
233
+ afterHooks(model) {
234
+ if (this.statements.statement === 'update') {
235
+ this.callHook('afterUpdate', this.statements.instance);
236
+ return;
237
+ }
238
+ if (this.statements.statement === 'insert') {
239
+ this.callHook('afterCreate', model);
240
+ return;
241
+ }
242
+ }
243
+ async executeAndReturnFirst() {
244
+ const hasOneToManyJoinedJoin = this.hasOneToManyJoinedJoin();
245
+ if (!hasOneToManyJoinedJoin) {
246
+ this.statements.limit = 1;
247
+ }
248
+ const result = await this.execute();
249
+ if (result.query.rows.length === 0) {
250
+ return undefined;
251
+ }
252
+ if (hasOneToManyJoinedJoin) {
253
+ return this.processOneToManyJoinedResult(result.query.rows);
254
+ }
255
+ const entities = result.query.rows[0];
256
+ const model = await this.modelTransformer.transform(this.model, this.statements, entities);
257
+ this.afterHooks(model);
258
+ await this.joinManager.handleSelectJoin(entities, model);
259
+ return model;
260
+ }
261
+ async executeAndReturnFirstOrFail() {
262
+ const hasOneToManyJoinedJoin = this.hasOneToManyJoinedJoin();
263
+ if (!hasOneToManyJoinedJoin) {
264
+ this.statements.limit = 1;
265
+ }
266
+ const result = await this.execute();
267
+ if (result.query.rows.length === 0) {
268
+ throw new Error('Result not found');
269
+ }
270
+ if (hasOneToManyJoinedJoin) {
271
+ const model = await this.processOneToManyJoinedResult(result.query.rows);
272
+ if (!model) {
273
+ throw new Error('Result not found');
274
+ }
275
+ return model;
276
+ }
277
+ const entities = result.query.rows[0];
278
+ const model = await this.modelTransformer.transform(this.model, this.statements, entities);
279
+ this.afterHooks(model);
280
+ await this.joinManager.handleSelectJoin(entities, model);
281
+ return model;
282
+ }
283
+ async executeAndReturnAll() {
284
+ const result = await this.execute();
285
+ if (result.query.rows.length === 0) {
286
+ return [];
287
+ }
288
+ const rows = result.query.rows;
289
+ const hasOneToManyJoinedJoin = this.hasOneToManyJoinedJoin();
290
+ if (hasOneToManyJoinedJoin) {
291
+ return this.processAllOneToManyJoinedResults(rows);
292
+ }
293
+ const results = [];
294
+ for (const row of rows) {
295
+ const models = this.modelTransformer.transform(this.model, this.statements, row);
296
+ this.afterHooks(models);
297
+ await this.joinManager.handleSelectJoin(row, models);
298
+ results.push(models);
299
+ }
300
+ return results;
301
+ }
302
+ hasOneToManyJoinedJoin() {
303
+ if (!this.statements.join || this.statements.join.length === 0) {
304
+ return false;
305
+ }
306
+ if (this.statements.strategy !== 'joined') {
307
+ return false;
308
+ }
309
+ return this.statements.join.some(join => {
310
+ const originEntity = this.getOriginEntityForJoin(join);
311
+ if (!originEntity) {
312
+ return false;
313
+ }
314
+ const relationship = originEntity.relations.find(rel => rel.propertyKey === join.joinProperty);
315
+ return relationship?.relation === 'one-to-many';
316
+ });
317
+ }
318
+ getOriginEntityForJoin(join) {
319
+ const rootAlias = this.statements.alias;
320
+ if (join.originAlias === rootAlias) {
321
+ return this.entity;
322
+ }
323
+ const parentJoin = this.statements.join.find(j => j.joinAlias === join.originAlias);
324
+ if (parentJoin && parentJoin.joinEntity) {
325
+ return this.entityStorage.get(parentJoin.joinEntity);
326
+ }
327
+ return null;
328
+ }
329
+ findNestedModel(model, targetAlias) {
330
+ if (!this.statements.join) {
331
+ return null;
332
+ }
333
+ for (const join of this.statements.join) {
334
+ if (join.joinAlias === targetAlias) {
335
+ const parentModel = join.originAlias === this.statements.alias
336
+ ? model
337
+ : this.findNestedModel(model, join.originAlias);
338
+ return parentModel?.[join.joinProperty];
339
+ }
340
+ }
341
+ return null;
342
+ }
343
+ async processOneToManyJoinedResult(rows) {
344
+ const primaryKey = this.getPrimaryKeyName();
345
+ const alias = this.statements.alias;
346
+ const primaryKeyColumn = `${alias}_${primaryKey}`;
347
+ const firstRowPrimaryKeyValue = rows[0][primaryKeyColumn];
348
+ const relatedRows = rows.filter(row => row[primaryKeyColumn] === firstRowPrimaryKeyValue);
349
+ const model = this.modelTransformer.transform(this.model, this.statements, relatedRows[0]);
350
+ this.afterHooks(model);
351
+ this.attachOneToManyRelations(model, relatedRows);
352
+ return model;
353
+ }
354
+ async processAllOneToManyJoinedResults(rows) {
355
+ const primaryKey = this.getPrimaryKeyName();
356
+ const alias = this.statements.alias;
357
+ const primaryKeyColumn = `${alias}_${primaryKey}`;
358
+ const groupedRows = new Map();
359
+ for (const row of rows) {
360
+ const pkValue = row[primaryKeyColumn];
361
+ if (!groupedRows.has(pkValue)) {
362
+ groupedRows.set(pkValue, []);
363
+ }
364
+ groupedRows.get(pkValue).push(row);
365
+ }
366
+ const results = [];
367
+ for (const [, relatedRows] of groupedRows) {
368
+ const model = this.modelTransformer.transform(this.model, this.statements, relatedRows[0]);
369
+ this.afterHooks(model);
370
+ this.attachOneToManyRelations(model, relatedRows);
371
+ results.push(model);
372
+ }
373
+ return results;
374
+ }
375
+ attachOneToManyRelations(model, rows) {
376
+ if (!this.statements.join) {
377
+ return;
378
+ }
379
+ for (const join of this.statements.join) {
380
+ const originEntity = this.getOriginEntityForJoin(join);
381
+ if (!originEntity) {
382
+ continue;
383
+ }
384
+ const relationship = originEntity.relations.find(rel => rel.propertyKey === join.joinProperty);
385
+ if (relationship?.relation === 'one-to-many') {
386
+ const joinedModels = rows.map(row => this.modelTransformer.transform(join.joinEntity, { alias: join.joinAlias }, row));
387
+ const uniqueModels = this.removeDuplicatesByPrimaryKey(joinedModels, join.joinEntity);
388
+ const targetModel = join.originAlias === this.statements.alias
389
+ ? model
390
+ : this.findNestedModel(model, join.originAlias);
391
+ if (targetModel) {
392
+ targetModel[join.joinProperty] = uniqueModels;
393
+ }
394
+ }
395
+ }
396
+ }
397
+ removeDuplicatesByPrimaryKey(models, entityClass) {
398
+ const entity = this.entityStorage.get(entityClass);
399
+ if (!entity) {
400
+ return models;
401
+ }
402
+ const primaryKey = this.getPrimaryKeyNameForEntity(entity);
403
+ const seen = new Set();
404
+ const unique = [];
405
+ for (const model of models) {
406
+ const id = model[primaryKey];
407
+ if (id && !seen.has(id)) {
408
+ seen.add(id);
409
+ unique.push(model);
410
+ }
411
+ }
412
+ return unique;
413
+ }
414
+ getPrimaryKeyName() {
415
+ return this.getPrimaryKeyNameForEntity(this.entity);
416
+ }
417
+ getPrimaryKeyNameForEntity(entity) {
418
+ for (const prop in entity.properties) {
419
+ if (entity.properties[prop].options.isPrimary) {
420
+ return prop;
421
+ }
422
+ }
423
+ return 'id';
424
+ }
425
+ async executeCount() {
426
+ const result = await this.execute();
427
+ if (result.query.rows.length === 0) {
428
+ return 0;
429
+ }
430
+ return parseInt(result.query.rows[0].count);
431
+ }
432
+ logExecution(result) {
433
+ this.logger.debug(`SQL: ${result.sql} [${Date.now() - result.startTime}ms]`);
434
+ }
435
+ async inTransaction(callback) {
436
+ return await this.driver.transaction(async (tx) => {
437
+ // @ts-ignore
438
+ return await callback(this);
439
+ });
440
+ }
441
+ objectToStringMap(obj, parentKey = '') {
442
+ return Object.keys(obj)
443
+ .filter(key => obj.hasOwnProperty(key))
444
+ .flatMap(key => this.mapObjectKey(obj, key, parentKey));
445
+ }
446
+ mapObjectKey(obj, key, parentKey) {
447
+ const fullKey = parentKey ? `${parentKey}.${key}` : key;
448
+ if (this.isNestedObject(obj[key])) {
449
+ return this.objectToStringMap(obj[key], fullKey);
450
+ }
451
+ if (parentKey) {
452
+ const columnPath = this.buildColumnPath(fullKey);
453
+ return [`${this.columnManager.discoverAlias(columnPath, true)} ${obj[key]}`];
454
+ }
455
+ const columnName = value_processor_1.ValueProcessor.getColumnName(key, this.entity);
456
+ return [`${this.columnManager.discoverAlias(columnName, true)} ${obj[key]}`];
457
+ }
458
+ isNestedObject(value) {
459
+ return typeof value === 'object' && value !== null;
460
+ }
461
+ buildColumnPath(path) {
462
+ const segments = this.splitPath(path);
463
+ const entity = this.resolvePathEntity(segments.parents);
464
+ const column = this.resolveColumn(segments.column, entity);
465
+ return this.joinSegments(segments.parents, column);
466
+ }
467
+ splitPath(path) {
468
+ const parts = path.split('.');
469
+ const column = parts.pop() ?? path;
470
+ return { parents: parts, column };
471
+ }
472
+ resolvePathEntity(parents) {
473
+ let current = this.entity;
474
+ for (const relation of parents) {
475
+ current = this.nextEntity(current, relation);
476
+ }
477
+ return current;
478
+ }
479
+ nextEntity(entity, relation) {
480
+ const relations = entity.relations ?? [];
481
+ const meta = relations.find(rel => rel.propertyKey === relation);
482
+ if (!meta) {
483
+ throw new Error(`Relationship "${relation}" not found for ORDER BY path`);
484
+ }
485
+ const next = this.entityStorage.get(meta.entity());
486
+ if (!next) {
487
+ throw new Error(`Entity metadata not found for relation "${relation}"`);
488
+ }
489
+ return next;
490
+ }
491
+ resolveColumn(column, entity) {
492
+ return value_processor_1.ValueProcessor.getColumnName(column, entity);
493
+ }
494
+ joinSegments(parents, column) {
495
+ if (parents.length === 0) {
496
+ return column;
497
+ }
498
+ return `${parents.join('.')}.${column}`;
499
+ }
500
+ getTableName() {
501
+ const tableName = this.entity.tableName || this.model.name.toLowerCase();
502
+ const schema = this.entity.schema || 'public';
503
+ return { tableName, schema };
504
+ }
505
+ t(value) {
506
+ return (typeof value === 'string') ? `'${value}'` : value;
507
+ }
508
+ // private conditionLogicalOperatorToSql<T extends typeof BaseEntity>(conditions: Condition<T>[], operator: 'AND' | 'OR'): string {
509
+ // const sqlParts = conditions.map(cond => this.conditionToSql(cond));
510
+ // return this.addLogicalOperatorToSql(sqlParts, operator);
511
+ // }
512
+ getEntity(model) {
513
+ const entity = this.entityStorage.get(model);
514
+ this.model = model;
515
+ if (!entity) {
516
+ throw new Error('Entity not found');
517
+ }
518
+ this.entity = entity;
519
+ }
520
+ /**
521
+ * Retrieves an alias for a given table name.
522
+ *
523
+ * @param {string} tableName - The name of the table.
524
+ * @private
525
+ * @returns {string} - The alias for the table name.
526
+ */
527
+ getAlias(tableName) {
528
+ const baseAlias = tableName.split('').shift() || '';
529
+ const uniqueAlias = this.generateUniqueAlias(baseAlias);
530
+ this.aliases.add(uniqueAlias);
531
+ return uniqueAlias;
532
+ }
533
+ generateUniqueAlias(baseAlias) {
534
+ let counter = 1;
535
+ let candidate = `${baseAlias}${counter}`;
536
+ while (this.aliases.has(candidate)) {
537
+ counter++;
538
+ candidate = `${baseAlias}${counter}`;
539
+ }
540
+ return candidate;
541
+ }
542
+ withDefaultValues(values, entityOptions) {
543
+ this.applyDefaultProperties(values, entityOptions);
544
+ this.applyOnInsertProperties(values, entityOptions);
545
+ return values;
546
+ }
547
+ applyDefaultProperties(values, entityOptions) {
548
+ const defaultProperties = Object.entries(entityOptions.properties).filter(([_, value]) => value.options.default);
549
+ for (const [key, property] of defaultProperties) {
550
+ this.setDefaultValue(values, key, property);
551
+ }
552
+ }
553
+ setDefaultValue(values, key, property) {
554
+ const columnName = property.options.columnName;
555
+ if (typeof values[columnName] !== 'undefined')
556
+ return;
557
+ values[columnName] = typeof property.options.default === 'function'
558
+ ? property.options.default()
559
+ : property.options.default;
560
+ }
561
+ applyOnInsertProperties(values, entityOptions) {
562
+ const properties = Object.entries(entityOptions.properties).filter(([_, value]) => value.options.onInsert);
563
+ properties.forEach(([key, property]) => this.applyOnInsert(values, key, property));
564
+ }
565
+ applyOnInsert(values, key, property) {
566
+ const columnName = property.options.columnName;
567
+ values[columnName] = property.options.onInsert();
568
+ this.updatedColumns.push(`${this.statements.alias}."${columnName}" as "${this.statements.alias}_${columnName}"`);
569
+ }
570
+ withUpdatedValues(values, entityOptions) {
571
+ const properties = Object.entries(entityOptions.properties).filter(([_, value]) => value.options.onUpdate);
572
+ properties.forEach(([key, property]) => this.applyOnUpdate(values, property));
573
+ return values;
574
+ }
575
+ applyOnUpdate(values, property) {
576
+ const columnName = property.options.columnName;
577
+ values[columnName] = property.options.onUpdate();
578
+ this.updatedColumns.push(`${this.statements.alias}."${columnName}" as "${this.statements.alias}_${columnName}"`);
579
+ }
580
+ callHook(type, model) {
581
+ const hooks = this.statements.hooks?.filter(hook => hook.type === type) || [];
582
+ const instance = model || this.statements.instance;
583
+ hooks.forEach(hook => this.executeHook(hook, instance, !model));
584
+ }
585
+ executeHook(hook, instance, shouldReflect) {
586
+ instance[hook.propertyName]();
587
+ if (shouldReflect)
588
+ this.reflectToValues();
589
+ }
590
+ reflectToValues() {
591
+ for (const key in this.statements.instance) {
592
+ if (this.shouldSkipKey(key))
593
+ continue;
594
+ this.reflectKey(key);
595
+ }
596
+ }
597
+ shouldSkipKey(key) {
598
+ return key.startsWith('$') || key.startsWith('_');
599
+ }
600
+ reflectKey(key) {
601
+ if (this.entity.properties[key]) {
602
+ this.reflectProperty(key);
603
+ return;
604
+ }
605
+ this.reflectRelation(key);
606
+ }
607
+ reflectProperty(key) {
608
+ const columnName = this.entity.properties[key].options.columnName;
609
+ this.statements.values[columnName] = this.statements.instance[key];
610
+ }
611
+ reflectRelation(key) {
612
+ const rel = this.entity.relations.find(rel => rel.propertyKey === key);
613
+ if (rel) {
614
+ this.statements.values[rel.columnName] = this.statements.instance[key];
615
+ }
616
+ }
617
+ }
618
+ exports.SqlBuilder = SqlBuilder;
@@ -0,0 +1,13 @@
1
+ import { Statement } from '../driver/driver.interface';
2
+ export declare class CacheKeyGenerator {
3
+ generate(statement: Statement<any>): string;
4
+ private buildKeyParts;
5
+ private addTableName;
6
+ private addColumns;
7
+ private addWhere;
8
+ private addOrderBy;
9
+ private addLimits;
10
+ private addJoins;
11
+ private combineKeyParts;
12
+ private hashKey;
13
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CacheKeyGenerator = void 0;
4
+ const crypto_1 = require("crypto");
5
+ class CacheKeyGenerator {
6
+ generate(statement) {
7
+ const parts = this.buildKeyParts(statement);
8
+ const combined = this.combineKeyParts(parts);
9
+ return this.hashKey(combined);
10
+ }
11
+ buildKeyParts(statement) {
12
+ const parts = [];
13
+ this.addTableName(parts, statement);
14
+ this.addColumns(parts, statement);
15
+ this.addWhere(parts, statement);
16
+ this.addOrderBy(parts, statement);
17
+ this.addLimits(parts, statement);
18
+ this.addJoins(parts, statement);
19
+ return parts;
20
+ }
21
+ addTableName(parts, statement) {
22
+ if (statement.table) {
23
+ parts.push(`table:${statement.table}`);
24
+ }
25
+ }
26
+ addColumns(parts, statement) {
27
+ if (statement.columns?.length) {
28
+ parts.push(`cols:${statement.columns.join(',')}`);
29
+ }
30
+ }
31
+ addWhere(parts, statement) {
32
+ if (statement.where) {
33
+ parts.push(`where:${statement.where}`);
34
+ }
35
+ }
36
+ addOrderBy(parts, statement) {
37
+ if (statement.orderBy?.length) {
38
+ parts.push(`order:${statement.orderBy.join(',')}`);
39
+ }
40
+ }
41
+ addLimits(parts, statement) {
42
+ if (statement.limit !== undefined) {
43
+ parts.push(`limit:${statement.limit}`);
44
+ }
45
+ if (statement.offset !== undefined) {
46
+ parts.push(`offset:${statement.offset}`);
47
+ }
48
+ }
49
+ addJoins(parts, statement) {
50
+ if (statement.join?.length) {
51
+ const joinStr = statement.join
52
+ .map((j) => `${j.joinTable}:${j.type}:${j.on}`)
53
+ .join('|');
54
+ parts.push(`join:${joinStr}`);
55
+ }
56
+ }
57
+ combineKeyParts(parts) {
58
+ return parts.join('::');
59
+ }
60
+ hashKey(key) {
61
+ return (0, crypto_1.createHash)('md5')
62
+ .update(key)
63
+ .digest('hex');
64
+ }
65
+ }
66
+ exports.CacheKeyGenerator = CacheKeyGenerator;