forge-sql-orm 2.0.12 → 2.0.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.
@@ -1,74 +1,72 @@
1
- import {MySqlRemoteDatabase} from "drizzle-orm/mysql-proxy";
2
- import type {SelectedFields} from "drizzle-orm/mysql-core/query-builders/select.types";
3
- import {applyFromDriverTransform, mapSelectFieldsWithAlias} from "../../..";
4
- import {MySqlSelectBuilder} from "drizzle-orm/mysql-core";
5
- import {MySqlRemotePreparedQueryHKT} from "drizzle-orm/mysql-proxy";
1
+ import { MySqlRemoteDatabase } from "drizzle-orm/mysql-proxy";
2
+ import type { SelectedFields } from "drizzle-orm/mysql-core/query-builders/select.types";
3
+ import { applyFromDriverTransform, mapSelectFieldsWithAlias } from "../../..";
4
+ import { MySqlSelectBuilder } from "drizzle-orm/mysql-core";
5
+ import { MySqlRemotePreparedQueryHKT } from "drizzle-orm/mysql-proxy";
6
6
 
7
7
  function createAliasedSelectBuilder<TSelection extends SelectedFields>(
8
- db: MySqlRemoteDatabase<any>,
9
- fields: TSelection,
10
- selectFn: (selections: any) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>
8
+ db: MySqlRemoteDatabase<any>,
9
+ fields: TSelection,
10
+ selectFn: (selections: any) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>,
11
11
  ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT> {
12
- const { selections, aliasMap } = mapSelectFieldsWithAlias(fields);
13
- const builder = selectFn(selections);
12
+ const { selections, aliasMap } = mapSelectFieldsWithAlias(fields);
13
+ const builder = selectFn(selections);
14
14
 
15
- const wrapBuilder = (rawBuilder: any): any => {
16
- return new Proxy(rawBuilder, {
17
- get(target, prop, receiver) {
18
- if (prop === 'execute') {
19
- return async (...args: any[]) => {
20
- const rows = await target.execute(...args);
21
- return applyFromDriverTransform(rows, selections, aliasMap);
22
- };
23
- }
15
+ const wrapBuilder = (rawBuilder: any): any => {
16
+ return new Proxy(rawBuilder, {
17
+ get(target, prop, receiver) {
18
+ if (prop === "execute") {
19
+ return async (...args: any[]) => {
20
+ const rows = await target.execute(...args);
21
+ return applyFromDriverTransform(rows, selections, aliasMap);
22
+ };
23
+ }
24
24
 
25
- if (prop === 'then') {
26
- return (onfulfilled: any, onrejected: any) =>
27
- target.execute().then(
28
- (rows: unknown[]) => {
29
- const transformed = applyFromDriverTransform(rows, selections, aliasMap);
30
- return onfulfilled?.(transformed);
31
- },
32
- onrejected,
33
- );
34
- }
25
+ if (prop === "then") {
26
+ return (onfulfilled: any, onrejected: any) =>
27
+ target.execute().then((rows: unknown[]) => {
28
+ const transformed = applyFromDriverTransform(rows, selections, aliasMap);
29
+ return onfulfilled?.(transformed);
30
+ }, onrejected);
31
+ }
35
32
 
36
- const value = Reflect.get(target, prop, receiver);
33
+ const value = Reflect.get(target, prop, receiver);
37
34
 
38
- if (typeof value === 'function') {
39
- return (...args: any[]) => {
40
- const result = value.apply(target, args);
35
+ if (typeof value === "function") {
36
+ return (...args: any[]) => {
37
+ const result = value.apply(target, args);
41
38
 
42
- if (typeof result === 'object' && result !== null && 'execute' in result) {
43
- return wrapBuilder(result);
44
- }
39
+ if (typeof result === "object" && result !== null && "execute" in result) {
40
+ return wrapBuilder(result);
41
+ }
45
42
 
46
- return result;
47
- };
48
- }
43
+ return result;
44
+ };
45
+ }
49
46
 
50
- return value;
51
- },
52
- });
53
- };
47
+ return value;
48
+ },
49
+ });
50
+ };
54
51
 
55
- return wrapBuilder(builder);
52
+ return wrapBuilder(builder);
56
53
  }
57
54
 
58
55
  export function patchDbWithSelectAliased(db: MySqlRemoteDatabase<any>): MySqlRemoteDatabase<any> & {
59
- selectAliased:<TSelection extends SelectedFields>(
60
- fields: TSelection,
61
- )=> MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>,
62
- selectAliasedDistinct:<TSelection extends SelectedFields>(
63
- fields: TSelection,
64
- )=> MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT> } {
65
- db.selectAliased = function <TSelection extends SelectedFields>(fields: TSelection) {
66
- return createAliasedSelectBuilder(db, fields, (selections) => db.select(selections));
67
- };
56
+ selectAliased: <TSelection extends SelectedFields>(
57
+ fields: TSelection,
58
+ ) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
59
+ selectAliasedDistinct: <TSelection extends SelectedFields>(
60
+ fields: TSelection,
61
+ ) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
62
+ } {
63
+ db.selectAliased = function <TSelection extends SelectedFields>(fields: TSelection) {
64
+ return createAliasedSelectBuilder(db, fields, (selections) => db.select(selections));
65
+ };
68
66
 
69
- db.selectAliasedDistinct = function <TSelection extends SelectedFields>(fields: TSelection) {
70
- return createAliasedSelectBuilder(db, fields, (selections) => db.selectDistinct(selections));
71
- };
67
+ db.selectAliasedDistinct = function <TSelection extends SelectedFields>(fields: TSelection) {
68
+ return createAliasedSelectBuilder(db, fields, (selections) => db.selectDistinct(selections));
69
+ };
72
70
 
73
- return db;
74
- }
71
+ return db;
72
+ }
@@ -1,14 +1,14 @@
1
- import { SelectedFields } from 'drizzle-orm';
2
- import {MySqlSelectBuilder} from "drizzle-orm/mysql-core";
3
- import {MySqlRemotePreparedQueryHKT} from "drizzle-orm/mysql-proxy";
1
+ import { SelectedFields } from "drizzle-orm";
2
+ import { MySqlSelectBuilder } from "drizzle-orm/mysql-core";
3
+ import { MySqlRemotePreparedQueryHKT } from "drizzle-orm/mysql-proxy";
4
4
 
5
- declare module 'drizzle-orm/mysql-proxy' {
6
- interface MySqlRemoteDatabase<> {
7
- selectAliased<TSelection extends SelectedFields>(
8
- fields: TSelection,
9
- ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
10
- selectAliasedDistinct<TSelection extends SelectedFields>(
11
- fields: TSelection,
12
- ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
13
- }
14
- }
5
+ declare module "drizzle-orm/mysql-proxy" {
6
+ interface MySqlRemoteDatabase<> {
7
+ selectAliased<TSelection extends SelectedFields>(
8
+ fields: TSelection,
9
+ ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
10
+ selectAliasedDistinct<TSelection extends SelectedFields>(
11
+ fields: TSelection,
12
+ ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
13
+ }
14
+ }
@@ -1,6 +1,6 @@
1
1
  import moment from "moment";
2
- import {AnyColumn, Column, isTable, SQL, sql, StringChunk} from "drizzle-orm";
3
- import {AnyMySqlTable, MySqlCustomColumn} from "drizzle-orm/mysql-core/index";
2
+ import { AnyColumn, Column, isTable, SQL, sql, StringChunk } from "drizzle-orm";
3
+ import { AnyMySqlTable, MySqlCustomColumn } from "drizzle-orm/mysql-core/index";
4
4
  import { PrimaryKeyBuilder } from "drizzle-orm/mysql-core/primary-keys";
5
5
  import { AnyIndexBuilder } from "drizzle-orm/mysql-core/indexes";
6
6
  import { CheckBuilder } from "drizzle-orm/mysql-core/checks";
@@ -8,8 +8,7 @@ import { ForeignKeyBuilder } from "drizzle-orm/mysql-core/foreign-keys";
8
8
  import { UniqueConstraintBuilder } from "drizzle-orm/mysql-core/unique-constraint";
9
9
  import type { SelectedFields } from "drizzle-orm/mysql-core/query-builders/select.types";
10
10
  import { MySqlTable } from "drizzle-orm/mysql-core";
11
- import { getTableName } from "drizzle-orm/table";
12
- import {isSQLWrapper} from "drizzle-orm/sql/sql";
11
+ import { isSQLWrapper } from "drizzle-orm/sql/sql";
13
12
 
14
13
  /**
15
14
  * Interface representing table metadata information
@@ -48,11 +47,11 @@ interface ConfigBuilderData {
48
47
  * @returns Date object
49
48
  */
50
49
  export const parseDateTime = (value: string, format: string): Date => {
51
- const m = moment(value, format, true);
52
- if (!m.isValid()) {
53
- return moment(value).toDate();
54
- }
55
- return m.toDate();
50
+ const m = moment(value, format, true);
51
+ if (!m.isValid()) {
52
+ return moment(value).toDate();
53
+ }
54
+ return m.toDate();
56
55
  };
57
56
 
58
57
  /**
@@ -61,8 +60,8 @@ export const parseDateTime = (value: string, format: string): Date => {
61
60
  * @returns The extracted alias or the original query if no alias found
62
61
  */
63
62
  export function extractAlias(query: string): string {
64
- const match = query.match(/\bas\s+(['"`]?)([\w*]+)\1$/i);
65
- return match ? match[2] : query;
63
+ const match = query.match(/\bas\s+(['"`]?)([\w*]+)\1$/i);
64
+ return match ? match[2] : query;
66
65
  }
67
66
 
68
67
  /**
@@ -189,8 +188,8 @@ export function getTableMetadata(table: AnyMySqlTable): MetadataInfo {
189
188
  builders.foreignKeys = processForeignKeys(table, foreignKeysSymbol, extraSymbol);
190
189
 
191
190
  // Process extra configuration if available
192
- if (extraSymbol) {
193
- // @ts-ignore
191
+ if (extraSymbol) {
192
+ // @ts-ignore
194
193
  const extraConfigBuilder = table[extraSymbol];
195
194
  if (extraConfigBuilder && typeof extraConfigBuilder === "function") {
196
195
  const configBuilderData = extraConfigBuilder(table);
@@ -231,7 +230,7 @@ export function getTableMetadata(table: AnyMySqlTable): MetadataInfo {
231
230
  }
232
231
  }
233
232
 
234
- return {
233
+ return {
235
234
  tableName: nameSymbol ? (table as any)[nameSymbol] : "",
236
235
  columns: columnsSymbol ? ((table as any)[columnsSymbol] as Record<string, AnyColumn>) : {},
237
236
  ...builders,
@@ -261,15 +260,15 @@ export function generateDropTableStatements(tables: AnyMySqlTable[]): string[] {
261
260
 
262
261
  type AliasColumnMap = Record<string, AnyColumn>;
263
262
 
264
- function mapSelectTableToAlias(table: MySqlTable, aliasMap: AliasColumnMap): any {
263
+ function mapSelectTableToAlias(table: MySqlTable,uniqPrefix:string, aliasMap: AliasColumnMap): any {
265
264
  const { columns, tableName } = getTableMetadata(table);
266
265
  const selectionsTableFields: Record<string, unknown> = {};
267
266
  Object.keys(columns).forEach((name) => {
268
267
  const column = columns[name] as AnyColumn;
269
- const uniqName = `a_${tableName}_${column.name}`;
268
+ const uniqName = `a_${uniqPrefix}_${tableName}_${column.name}`.toLowerCase();
270
269
  const fieldAlias = sql.raw(uniqName);
271
270
  selectionsTableFields[name] = sql`${column} as \`${fieldAlias}\``;
272
- aliasMap[uniqName]= column;
271
+ aliasMap[uniqName] = column;
273
272
  });
274
273
  return selectionsTableFields;
275
274
  }
@@ -278,13 +277,19 @@ function isDrizzleColumn(column: any): boolean {
278
277
  return column && typeof column === "object" && "table" in column;
279
278
  }
280
279
 
281
- export function mapSelectAllFieldsToAlias(selections: any, name: string, fields: any, aliasMap: AliasColumnMap): any {
280
+ export function mapSelectAllFieldsToAlias(
281
+ selections: any,
282
+ name: string,
283
+ uniqName:string,
284
+ fields: any,
285
+ aliasMap: AliasColumnMap,
286
+ ): any {
282
287
  if (isTable(fields)) {
283
- selections[name] = mapSelectTableToAlias(fields as MySqlTable, aliasMap);
288
+ selections[name] = mapSelectTableToAlias(fields as MySqlTable, uniqName, aliasMap);
284
289
  } else if (isDrizzleColumn(fields)) {
285
290
  const column = fields as Column;
286
- const uniqName = `a_${getTableName(column.table)}_${column.name}`;
287
- let aliasName = sql.raw(uniqName);
291
+ const uniqAliasName = `a_${uniqName}_${column.name}`.toLowerCase();
292
+ let aliasName = sql.raw(uniqAliasName);
288
293
  selections[name] = sql`${column} as \`${aliasName}\``;
289
294
  aliasMap[uniqName] = column;
290
295
  } else if (isSQLWrapper(fields)) {
@@ -292,7 +297,7 @@ export function mapSelectAllFieldsToAlias(selections: any, name: string, fields:
292
297
  } else {
293
298
  const innerSelections: any = {};
294
299
  Object.entries(fields).forEach(([iname, ifields]) => {
295
- mapSelectAllFieldsToAlias(innerSelections, iname, ifields, aliasMap);
300
+ mapSelectAllFieldsToAlias(innerSelections, iname, `${uniqName}_${iname}`, ifields, aliasMap);
296
301
  });
297
302
  selections[name] = innerSelections;
298
303
  }
@@ -307,40 +312,41 @@ export function mapSelectFieldsWithAlias<TSelection extends SelectedFields>(
307
312
  const aliasMap: AliasColumnMap = {};
308
313
  const selections: any = {};
309
314
  Object.entries(fields).forEach(([name, fields]) => {
310
- mapSelectAllFieldsToAlias(selections, name, fields, aliasMap);
315
+ mapSelectAllFieldsToAlias(selections, name,name, fields, aliasMap);
311
316
  });
312
- return {selections, aliasMap};
317
+ return { selections, aliasMap };
313
318
  }
314
319
 
315
-
316
-
317
- function getAliasFromDrizzleAlias(value: unknown): string|undefined {
318
- const isSQL = value !== null &&
319
- typeof value === 'object' &&
320
- isSQLWrapper(value) && 'queryChunks' in value;
321
- if (isSQL){
322
- const sql = value as SQL;
320
+ function getAliasFromDrizzleAlias(value: unknown): string | undefined {
321
+ const isSQL =
322
+ value !== null && typeof value === "object" && isSQLWrapper(value) && "queryChunks" in value;
323
+ if (isSQL) {
324
+ const sql = value as SQL;
323
325
  const queryChunks = sql.queryChunks;
324
- if (queryChunks.length>3){
325
- const aliasNameChunk = queryChunks[queryChunks.length-2];
326
- if (isSQLWrapper(aliasNameChunk) && 'queryChunks' in aliasNameChunk){
327
- const aliasNameChunkSql = aliasNameChunk as SQL;
326
+ if (queryChunks.length > 3) {
327
+ const aliasNameChunk = queryChunks[queryChunks.length - 2];
328
+ if (isSQLWrapper(aliasNameChunk) && "queryChunks" in aliasNameChunk) {
329
+ const aliasNameChunkSql = aliasNameChunk as SQL;
328
330
  if (aliasNameChunkSql && aliasNameChunkSql.queryChunks.length === 1) {
329
331
  const queryChunksStringChunc = aliasNameChunkSql.queryChunks[0];
330
- if (queryChunksStringChunc && 'value' in queryChunksStringChunc) {
332
+ if (queryChunksStringChunc && "value" in queryChunksStringChunc) {
331
333
  const values = (queryChunksStringChunc as StringChunk).value;
332
- if (values && values.length===1){
333
- return values[0]
334
+ if (values && values.length === 1) {
335
+ return values[0];
334
336
  }
335
337
  }
336
338
  }
337
339
  }
338
340
  }
339
341
  }
340
- return undefined
342
+ return undefined;
341
343
  }
342
344
 
343
- function transformValue(value: unknown, alias: string, aliasMap: Record<string, AnyColumn>): unknown {
345
+ function transformValue(
346
+ value: unknown,
347
+ alias: string,
348
+ aliasMap: Record<string, AnyColumn>,
349
+ ): unknown {
344
350
  const column = aliasMap[alias];
345
351
  if (!column) return value;
346
352
 
@@ -353,16 +359,24 @@ function transformValue(value: unknown, alias: string, aliasMap: Record<string,
353
359
  return value;
354
360
  }
355
361
 
356
- function transformObject(obj: Record<string, unknown>, selections: Record<string, unknown>, aliasMap: Record<string, AnyColumn>): Record<string, unknown> {
362
+ function transformObject(
363
+ obj: Record<string, unknown>,
364
+ selections: Record<string, unknown>,
365
+ aliasMap: Record<string, AnyColumn>,
366
+ ): Record<string, unknown> {
357
367
  const result: Record<string, unknown> = {};
358
368
 
359
369
  for (const [key, value] of Object.entries(obj)) {
360
370
  const selection = selections[key];
361
371
  const alias = getAliasFromDrizzleAlias(selection);
362
372
  if (alias && aliasMap[alias]) {
363
- result[key] = transformValue(value, alias, aliasMap);
364
- } else if (selection && typeof selection === 'object' && !isSQLWrapper(selection)) {
365
- result[key] = transformObject(value as Record<string, unknown>, selection as Record<string, unknown>, aliasMap);
373
+ result[key] = transformValue(value, alias, aliasMap);
374
+ } else if (selection && typeof selection === "object" && !isSQLWrapper(selection)) {
375
+ result[key] = transformObject(
376
+ value as Record<string, unknown>,
377
+ selection as Record<string, unknown>,
378
+ aliasMap,
379
+ );
366
380
  } else {
367
381
  result[key] = value;
368
382
  }
@@ -374,9 +388,44 @@ function transformObject(obj: Record<string, unknown>, selections: Record<string
374
388
  export function applyFromDriverTransform<T, TSelection>(
375
389
  rows: T[],
376
390
  selections: TSelection,
377
- aliasMap: Record<string, AnyColumn>
391
+ aliasMap: Record<string, AnyColumn>,
378
392
  ): T[] {
379
393
  return rows.map((row) => {
380
- return transformObject(row as Record<string, unknown>, selections as Record<string, unknown>, aliasMap) as T;
394
+ const transformed = transformObject(
395
+ row as Record<string, unknown>,
396
+ selections as Record<string, unknown>,
397
+ aliasMap,
398
+ ) as Record<string, unknown>;
399
+
400
+ return processNullBranches(transformed) as unknown as T;
381
401
  });
382
402
  }
403
+
404
+ function processNullBranches(obj: Record<string, unknown>): Record<string, unknown> | null {
405
+ if (obj === null || typeof obj !== 'object' || obj===undefined) {
406
+ return obj;
407
+ }
408
+
409
+ const result: Record<string, unknown> = {};
410
+ let allNull = true;
411
+
412
+ for (const [key, value] of Object.entries(obj)) {
413
+ if (value === null || value===undefined) {
414
+ result[key] = null;
415
+ continue;
416
+ }
417
+
418
+ if (typeof value === 'object' && (value !== null || value !== undefined) ) {
419
+ const processed = processNullBranches(value as Record<string, unknown>);
420
+ result[key] = processed;
421
+ if (processed !== null) {
422
+ allNull = false;
423
+ }
424
+ } else {
425
+ result[key] = value;
426
+ allNull = false;
427
+ }
428
+ }
429
+
430
+ return allNull ? null : result;
431
+ }