forge-sql-orm 2.1.12 → 2.1.14

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 (79) hide show
  1. package/README.md +922 -549
  2. package/dist/core/ForgeSQLAnalyseOperations.d.ts.map +1 -1
  3. package/dist/core/ForgeSQLAnalyseOperations.js +257 -0
  4. package/dist/core/ForgeSQLAnalyseOperations.js.map +1 -0
  5. package/dist/core/ForgeSQLCacheOperations.js +172 -0
  6. package/dist/core/ForgeSQLCacheOperations.js.map +1 -0
  7. package/dist/core/ForgeSQLCrudOperations.js +349 -0
  8. package/dist/core/ForgeSQLCrudOperations.js.map +1 -0
  9. package/dist/core/ForgeSQLORM.d.ts +29 -1
  10. package/dist/core/ForgeSQLORM.d.ts.map +1 -1
  11. package/dist/core/ForgeSQLORM.js +1252 -0
  12. package/dist/core/ForgeSQLORM.js.map +1 -0
  13. package/dist/core/ForgeSQLQueryBuilder.d.ts +179 -1
  14. package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
  15. package/dist/core/ForgeSQLQueryBuilder.js +77 -0
  16. package/dist/core/ForgeSQLQueryBuilder.js.map +1 -0
  17. package/dist/core/ForgeSQLSelectOperations.js +81 -0
  18. package/dist/core/ForgeSQLSelectOperations.js.map +1 -0
  19. package/dist/core/Rovo.d.ts +116 -0
  20. package/dist/core/Rovo.d.ts.map +1 -0
  21. package/dist/core/Rovo.js +647 -0
  22. package/dist/core/Rovo.js.map +1 -0
  23. package/dist/core/SystemTables.js +258 -0
  24. package/dist/core/SystemTables.js.map +1 -0
  25. package/dist/index.js +30 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -1
  28. package/dist/lib/drizzle/extensions/additionalActions.js +527 -0
  29. package/dist/lib/drizzle/extensions/additionalActions.js.map +1 -0
  30. package/dist/utils/cacheContextUtils.d.ts.map +1 -1
  31. package/dist/utils/cacheContextUtils.js +198 -0
  32. package/dist/utils/cacheContextUtils.js.map +1 -0
  33. package/dist/utils/cacheUtils.d.ts.map +1 -1
  34. package/dist/utils/cacheUtils.js +383 -0
  35. package/dist/utils/cacheUtils.js.map +1 -0
  36. package/dist/utils/forgeDriver.d.ts.map +1 -1
  37. package/dist/utils/forgeDriver.js +139 -0
  38. package/dist/utils/forgeDriver.js.map +1 -0
  39. package/dist/utils/forgeDriverProxy.js +68 -0
  40. package/dist/utils/forgeDriverProxy.js.map +1 -0
  41. package/dist/utils/metadataContextUtils.d.ts.map +1 -1
  42. package/dist/utils/metadataContextUtils.js +26 -0
  43. package/dist/utils/metadataContextUtils.js.map +1 -0
  44. package/dist/utils/requestTypeContextUtils.js +10 -0
  45. package/dist/utils/requestTypeContextUtils.js.map +1 -0
  46. package/dist/utils/sqlHints.js +52 -0
  47. package/dist/utils/sqlHints.js.map +1 -0
  48. package/dist/utils/sqlUtils.d.ts.map +1 -1
  49. package/dist/utils/sqlUtils.js +590 -0
  50. package/dist/utils/sqlUtils.js.map +1 -0
  51. package/dist/webtriggers/applyMigrationsWebTrigger.js +77 -0
  52. package/dist/webtriggers/applyMigrationsWebTrigger.js.map +1 -0
  53. package/dist/webtriggers/clearCacheSchedulerTrigger.js +83 -0
  54. package/dist/webtriggers/clearCacheSchedulerTrigger.js.map +1 -0
  55. package/dist/webtriggers/dropMigrationWebTrigger.js +54 -0
  56. package/dist/webtriggers/dropMigrationWebTrigger.js.map +1 -0
  57. package/dist/webtriggers/dropTablesMigrationWebTrigger.js +54 -0
  58. package/dist/webtriggers/dropTablesMigrationWebTrigger.js.map +1 -0
  59. package/dist/webtriggers/fetchSchemaWebTrigger.js +82 -0
  60. package/dist/webtriggers/fetchSchemaWebTrigger.js.map +1 -0
  61. package/dist/webtriggers/index.js +40 -0
  62. package/dist/webtriggers/index.js.map +1 -0
  63. package/dist/webtriggers/slowQuerySchedulerTrigger.js +80 -0
  64. package/dist/webtriggers/slowQuerySchedulerTrigger.js.map +1 -0
  65. package/package.json +31 -25
  66. package/src/core/ForgeSQLAnalyseOperations.ts +3 -2
  67. package/src/core/ForgeSQLORM.ts +64 -0
  68. package/src/core/ForgeSQLQueryBuilder.ts +200 -1
  69. package/src/core/Rovo.ts +765 -0
  70. package/src/lib/drizzle/extensions/additionalActions.ts +11 -0
  71. package/src/utils/cacheContextUtils.ts +9 -6
  72. package/src/utils/cacheUtils.ts +6 -4
  73. package/src/utils/forgeDriver.ts +3 -7
  74. package/src/utils/metadataContextUtils.ts +1 -3
  75. package/src/utils/sqlUtils.ts +33 -34
  76. package/dist/ForgeSQLORM.js +0 -3922
  77. package/dist/ForgeSQLORM.js.map +0 -1
  78. package/dist/ForgeSQLORM.mjs +0 -3905
  79. package/dist/ForgeSQLORM.mjs.map +0 -1
@@ -593,6 +593,17 @@ function createAliasedSelectBuilder<TSelection extends SelectedFields>(
593
593
  }
594
594
  };
595
595
  }
596
+ if (prop === "catch") {
597
+ return (onrejected: any) => (receiver as any).then(undefined, onrejected);
598
+ }
599
+
600
+ if (prop === "finally") {
601
+ return (onfinally: any) =>
602
+ (receiver as any).then(
603
+ (value: any) => Promise.resolve(value).finally(onfinally),
604
+ (reason: any) => Promise.reject(reason).finally(onfinally),
605
+ );
606
+ }
596
607
 
597
608
  const value = Reflect.get(target, prop, receiver);
598
609
 
@@ -159,10 +159,11 @@ export async function getQueryLocalCacheQuery<
159
159
  } else {
160
160
  sql = query as { toSQL: () => Query };
161
161
  }
162
- const key = hashKey(sql.toSQL());
163
- if (context.cache[key] && context.cache[key].sql === sql.toSQL().sql.toLowerCase()) {
162
+ const toSQL = sql.toSQL();
163
+ const key = hashKey(toSQL);
164
+ if (context.cache[key] && context.cache[key].sql === toSQL.sql.toLowerCase()) {
164
165
  if (options.logCache) {
165
- const q = sql.toSQL();
166
+ const q = toSQL;
166
167
  // eslint-disable-next-line no-console
167
168
  console.debug(
168
169
  `[forge-sql-orm][local-cache][HIT] Returned cached result. sql="${q.sql}", params=${JSON.stringify(q.params)}`,
@@ -201,12 +202,14 @@ export async function evictLocalCacheQuery<T extends AnyMySqlTable>(
201
202
  const tableName = getTableName(table);
202
203
  const searchString = options.cacheWrapTable ? `\`${tableName}\`` : tableName;
203
204
  const keyToEvicts: string[] = [];
204
- Object.keys(context.cache).forEach((key) => {
205
+ for (const key of Object.keys(context.cache)) {
205
206
  if (context.cache[key].sql.includes(searchString)) {
206
207
  keyToEvicts.push(key);
207
208
  }
208
- });
209
- keyToEvicts.forEach((key) => delete context.cache[key]);
209
+ }
210
+ for (const key of keyToEvicts) {
211
+ delete context.cache[key];
212
+ }
210
213
  }
211
214
  }
212
215
 
@@ -1,5 +1,5 @@
1
1
  import { DateTime } from "luxon";
2
- import * as crypto from "crypto";
2
+ import * as crypto from "node:crypto";
3
3
  import { Query } from "drizzle-orm";
4
4
  import { AnyMySqlTable } from "drizzle-orm/mysql-core";
5
5
  import { getTableName } from "drizzle-orm/table";
@@ -65,7 +65,9 @@ function extractBacktickedValues(sql: string): string {
65
65
  }
66
66
 
67
67
  // Sort to ensure consistent order for the same input
68
- return Array.from(matches).sort().join(",");
68
+ return Array.from(matches)
69
+ .sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base", numeric: true }))
70
+ .join(",");
69
71
  }
70
72
 
71
73
  /**
@@ -95,9 +97,9 @@ async function deleteCacheEntriesInBatches(
95
97
  for (let i = 0; i < results.length; i += CACHE_CONSTANTS.BATCH_SIZE) {
96
98
  const batch = results.slice(i, i + CACHE_CONSTANTS.BATCH_SIZE);
97
99
  let transactionBuilder = kvs.transact();
98
- batch.forEach((result) => {
100
+ for (const result of batch) {
99
101
  transactionBuilder = transactionBuilder.delete(result.key, { entityName: cacheEntityName });
100
- });
102
+ }
101
103
  await transactionBuilder.execute();
102
104
  }
103
105
  }
@@ -92,7 +92,7 @@ async function processDDLResult(method: QueryMethod, result: any): Promise<Forge
92
92
  }
93
93
 
94
94
  if (isUpdateQueryResponse(result.rows)) {
95
- const oneRow = result.rows as any;
95
+ const oneRow = result.rows;
96
96
  return { ...oneRow, rows: [oneRow] };
97
97
  }
98
98
 
@@ -145,12 +145,8 @@ async function processAllMethod(query: string, params: unknown[]): Promise<Forge
145
145
  await sqlStatement.bindParams(...params);
146
146
  }
147
147
 
148
- const result = (await withTimeout(
149
- sqlStatement.execute(),
150
- timeoutMessage,
151
- timeoutMs,
152
- )) as ForgeSQLResult;
153
- await saveMetaDataToContext(result.metadata);
148
+ const result = await withTimeout(sqlStatement.execute(), timeoutMessage, timeoutMs);
149
+ await saveMetaDataToContext(result.metadata as ForgeSQLMetadata);
154
150
 
155
151
  if (!result.rows) {
156
152
  return { rows: [] };
@@ -16,9 +16,7 @@ export async function saveMetaDataToContext(metadata?: ForgeSQLMetadata): Promis
16
16
  const context = metadataQueryContext.getStore();
17
17
  if (context) {
18
18
  context.printQueriesWithPlan = async () => {
19
- if (process.env.NODE_ENV !== "test") {
20
- await new Promise((r) => setTimeout(r, 200));
21
- }
19
+ await new Promise((r) => setTimeout(r, 200));
22
20
  await printQueriesWithPlan(context.forgeSQLORM, Date.now() - context.beginTime.getTime());
23
21
  };
24
22
  if (metadata) {
@@ -93,7 +93,7 @@ export const parseDateTime = (value: string | Date, format: string): Date => {
93
93
  }
94
94
  }
95
95
  // 4. Ensure the result is a valid Date object
96
- if (isNaN(result.getTime())) {
96
+ if (Number.isNaN(result.getTime())) {
97
97
  result = new Date(value);
98
98
  }
99
99
  return result;
@@ -127,7 +127,7 @@ export function formatDateTime(
127
127
  }
128
128
  if (!dt?.isValid) {
129
129
  const parsed = Number(value);
130
- if (!isNaN(parsed)) {
130
+ if (!Number.isNaN(parsed)) {
131
131
  dt = DateTime.fromMillis(parsed);
132
132
  }
133
133
  }
@@ -183,17 +183,15 @@ export function getPrimaryKeys<T extends AnyMySqlTable>(table: T): [string, AnyC
183
183
  // Collect all primary key columns from all primary key builders
184
184
  const primaryKeyColumns = new Set<[string, AnyColumn]>();
185
185
 
186
- primaryKeys.forEach((primaryKeyBuilder) => {
186
+ for (const primaryKeyBuilder of primaryKeys) {
187
187
  // Get primary key columns from each builder
188
- Object.entries(columns)
189
- .filter(([, column]) => {
190
- // @ts-ignore - PrimaryKeyBuilder has internal columns property
191
- return primaryKeyBuilder.columns.includes(column);
192
- })
193
- .forEach(([name, column]) => {
194
- primaryKeyColumns.add([name, column]);
195
- });
196
- });
188
+ for (const [name, column1] of Object.entries(columns).filter(([, column]) => {
189
+ // @ts-ignore - PrimaryKeyBuilder has internal columns property
190
+ return primaryKeyBuilder.columns.includes(column);
191
+ })) {
192
+ primaryKeyColumns.add([name, column1]);
193
+ }
194
+ }
197
195
 
198
196
  return Array.from(primaryKeyColumns);
199
197
  }
@@ -220,12 +218,12 @@ function processForeignKeys(
220
218
  // @ts-ignore
221
219
  const fkArray: any[] = table[foreignKeysSymbol];
222
220
  if (fkArray) {
223
- fkArray.forEach((fk) => {
221
+ for (const fk of fkArray) {
224
222
  if (fk.reference) {
225
223
  const item = fk.reference(fk);
226
224
  foreignKeys.push(item);
227
225
  }
228
- });
226
+ }
229
227
  }
230
228
  }
231
229
 
@@ -242,14 +240,14 @@ function processForeignKeys(
242
240
  (item) => (item as ConfigBuilderData).value ?? item,
243
241
  );
244
242
 
245
- configBuilders.forEach((builder) => {
246
- if (!builder?.constructor) return;
243
+ for (const builder of configBuilders) {
244
+ if (!builder?.constructor) continue;
247
245
 
248
246
  const builderName = builder.constructor.name.toLowerCase();
249
247
  if (builderName.includes("foreignkeybuilder")) {
250
248
  foreignKeys.push(builder);
251
249
  }
252
- });
250
+ }
253
251
  }
254
252
  }
255
253
  }
@@ -297,8 +295,8 @@ export function getTableMetadata(table: AnyMySqlTable): MetadataInfo {
297
295
  );
298
296
 
299
297
  // Process each builder
300
- configBuilders.forEach((builder) => {
301
- if (!builder?.constructor) return;
298
+ for (const builder of configBuilders) {
299
+ if (!builder?.constructor) continue;
302
300
 
303
301
  const builderName = builder.constructor.name.toLowerCase();
304
302
 
@@ -320,7 +318,7 @@ export function getTableMetadata(table: AnyMySqlTable): MetadataInfo {
320
318
 
321
319
  // Always add to extras array
322
320
  builders.extras.push(builder);
323
- });
321
+ }
324
322
  }
325
323
  }
326
324
  }
@@ -352,14 +350,14 @@ export function generateDropTableStatements(
352
350
  console.warn('No drop operations requested: both "table" and "sequence" options are false');
353
351
  return [];
354
352
  }
355
- tables.forEach((tableName) => {
353
+ for (const tableName of tables) {
356
354
  if (validOptions.table) {
357
355
  dropStatements.push(`DROP TABLE IF EXISTS \`${tableName}\`;`);
358
356
  }
359
357
  if (validOptions.sequence) {
360
358
  dropStatements.push(`DROP SEQUENCE IF EXISTS \`${tableName}\`;`);
361
359
  }
362
- });
360
+ }
363
361
 
364
362
  return dropStatements;
365
363
  }
@@ -373,13 +371,13 @@ function mapSelectTableToAlias(
373
371
  ): any {
374
372
  const { columns, tableName } = getTableMetadata(table);
375
373
  const selectionsTableFields: Record<string, unknown> = {};
376
- Object.keys(columns).forEach((name) => {
374
+ for (const name of Object.keys(columns)) {
377
375
  const column = columns[name] as AnyColumn;
378
376
  const uniqName = `a_${uniqPrefix}_${tableName}_${column.name}`.toLowerCase();
379
377
  const fieldAlias = sql.raw(uniqName);
380
378
  selectionsTableFields[name] = sql`${column} as \`${fieldAlias}\``;
381
379
  aliasMap[uniqName] = column;
382
- });
380
+ }
383
381
  return selectionsTableFields;
384
382
  }
385
383
 
@@ -406,9 +404,9 @@ export function mapSelectAllFieldsToAlias(
406
404
  selections[name] = fields;
407
405
  } else {
408
406
  const innerSelections: any = {};
409
- Object.entries(fields).forEach(([iname, ifields]) => {
407
+ for (const [iname, ifields] of Object.entries(fields)) {
410
408
  mapSelectAllFieldsToAlias(innerSelections, iname, `${uniqName}_${iname}`, ifields, aliasMap);
411
- });
409
+ }
412
410
  selections[name] = innerSelections;
413
411
  }
414
412
  return selections;
@@ -421,9 +419,10 @@ export function mapSelectFieldsWithAlias<TSelection extends SelectedFields>(
421
419
  }
422
420
  const aliasMap: AliasColumnMap = {};
423
421
  const selections: any = {};
424
- Object.entries(fields).forEach(([name, fields]) => {
425
- mapSelectAllFieldsToAlias(selections, name, name, fields, aliasMap);
426
- });
422
+ for (let i = 0; i < Object.entries(fields).length; i++) {
423
+ const [name, fields1] = Object.entries(fields)[i];
424
+ mapSelectAllFieldsToAlias(selections, name, name, fields1, aliasMap);
425
+ }
427
426
  return { selections, aliasMap };
428
427
  }
429
428
 
@@ -546,7 +545,7 @@ function processNullBranches(obj: Record<string, unknown>): Record<string, unkno
546
545
  }
547
546
 
548
547
  export function formatLimitOffset(limitOrOffset: number): number {
549
- if (typeof limitOrOffset !== "number" || isNaN(limitOrOffset)) {
548
+ if (typeof limitOrOffset !== "number" || Number.isNaN(limitOrOffset)) {
550
549
  throw new Error("limitOrOffset must be a valid number");
551
550
  }
552
551
  return sql.raw(`${limitOrOffset}`) as unknown as number;
@@ -628,7 +627,7 @@ export async function printQueriesWithPlan(
628
627
  timeoutMs + 200,
629
628
  );
630
629
 
631
- results.forEach((result) => {
630
+ for (const result of results) {
632
631
  // Average execution time (convert from nanoseconds to milliseconds)
633
632
  const avgTimeMs = Number(result.avgLatency) / 1_000_000;
634
633
  const avgMemMB = Number(result.avgMem) / 1_000_000;
@@ -638,7 +637,7 @@ export async function printQueriesWithPlan(
638
637
  console.warn(
639
638
  `SQL: ${result.digestText} | Memory: ${avgMemMB.toFixed(2)} MB | Time: ${avgTimeMs.toFixed(2)} ms | stmtType: ${result.stmtType} | Executions: ${result.execCount}\n Plan:${result.plan}`,
640
639
  );
641
- });
640
+ }
642
641
  } catch (error) {
643
642
  // eslint-disable-next-line no-console
644
643
  console.debug(
@@ -714,7 +713,7 @@ export async function slowQueryPerHours(
714
713
  timeoutMs,
715
714
  );
716
715
  const response: string[] = [];
717
- results.forEach((result) => {
716
+ for (const result of results) {
718
717
  // Convert memory from bytes to MB and handle null values
719
718
  const memMaxMB = result.memMax ? Number(result.memMax) / 1_000_000 : 0;
720
719
 
@@ -723,7 +722,7 @@ export async function slowQueryPerHours(
723
722
  // 1. Query info: SQL, memory, time, executions
724
723
  // eslint-disable-next-line no-console
725
724
  console.warn(message);
726
- });
725
+ }
727
726
  return response;
728
727
  } catch (error) {
729
728
  // eslint-disable-next-line no-console