@simplysm/orm-common 13.0.28 → 13.0.30

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 (90) hide show
  1. package/README.md +210 -3
  2. package/dist/create-db-context.d.ts.map +1 -1
  3. package/dist/create-db-context.js +7 -2
  4. package/dist/create-db-context.js.map +1 -1
  5. package/dist/ddl/column-ddl.d.ts.map +1 -1
  6. package/dist/ddl/column-ddl.js.map +1 -1
  7. package/dist/ddl/initialize.d.ts.map +1 -1
  8. package/dist/ddl/initialize.js.map +1 -1
  9. package/dist/ddl/relation-ddl.d.ts.map +1 -1
  10. package/dist/ddl/relation-ddl.js.map +1 -1
  11. package/dist/ddl/schema-ddl.d.ts.map +1 -1
  12. package/dist/ddl/schema-ddl.js.map +1 -1
  13. package/dist/ddl/table-ddl.d.ts.map +1 -1
  14. package/dist/ddl/table-ddl.js.map +1 -1
  15. package/dist/define-db-context.d.ts.map +1 -1
  16. package/dist/define-db-context.js.map +1 -1
  17. package/dist/exec/executable.d.ts.map +1 -1
  18. package/dist/exec/executable.js.map +1 -1
  19. package/dist/exec/queryable.d.ts.map +1 -1
  20. package/dist/exec/queryable.js +19 -6
  21. package/dist/exec/queryable.js.map +1 -1
  22. package/dist/exec/search-parser.js.map +1 -1
  23. package/dist/expr/expr.d.ts.map +1 -1
  24. package/dist/expr/expr.js.map +1 -1
  25. package/dist/query-builder/base/query-builder-base.d.ts.map +1 -1
  26. package/dist/query-builder/base/query-builder-base.js +3 -1
  27. package/dist/query-builder/base/query-builder-base.js.map +1 -1
  28. package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
  29. package/dist/query-builder/mssql/mssql-expr-renderer.js +3 -1
  30. package/dist/query-builder/mssql/mssql-expr-renderer.js.map +1 -1
  31. package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
  32. package/dist/query-builder/mssql/mssql-query-builder.js +9 -3
  33. package/dist/query-builder/mssql/mssql-query-builder.js.map +1 -1
  34. package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
  35. package/dist/query-builder/mysql/mysql-expr-renderer.js +3 -1
  36. package/dist/query-builder/mysql/mysql-expr-renderer.js.map +1 -1
  37. package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
  38. package/dist/query-builder/mysql/mysql-query-builder.js +12 -4
  39. package/dist/query-builder/mysql/mysql-query-builder.js.map +1 -1
  40. package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
  41. package/dist/query-builder/postgresql/postgresql-expr-renderer.js +3 -1
  42. package/dist/query-builder/postgresql/postgresql-expr-renderer.js.map +1 -1
  43. package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
  44. package/dist/query-builder/postgresql/postgresql-query-builder.js +21 -7
  45. package/dist/query-builder/postgresql/postgresql-query-builder.js.map +1 -1
  46. package/dist/schema/factory/column-builder.d.ts.map +1 -1
  47. package/dist/schema/factory/column-builder.js.map +1 -1
  48. package/dist/schema/factory/relation-builder.d.ts.map +1 -1
  49. package/dist/schema/factory/relation-builder.js.map +1 -1
  50. package/dist/schema/procedure-builder.d.ts.map +1 -1
  51. package/dist/schema/procedure-builder.js.map +1 -1
  52. package/dist/schema/table-builder.d.ts.map +1 -1
  53. package/dist/schema/table-builder.js +3 -1
  54. package/dist/schema/table-builder.js.map +1 -1
  55. package/dist/schema/view-builder.d.ts.map +1 -1
  56. package/dist/schema/view-builder.js +3 -1
  57. package/dist/schema/view-builder.js.map +1 -1
  58. package/dist/types/db-context-def.d.ts.map +1 -1
  59. package/dist/types/db.d.ts.map +1 -1
  60. package/dist/utils/result-parser.js +3 -1
  61. package/dist/utils/result-parser.js.map +1 -1
  62. package/docs/queries.md +89 -5
  63. package/docs/schema.md +12 -20
  64. package/package.json +2 -2
  65. package/src/create-db-context.ts +53 -15
  66. package/src/ddl/column-ddl.ts +4 -1
  67. package/src/ddl/initialize.ts +13 -3
  68. package/src/ddl/relation-ddl.ts +4 -1
  69. package/src/ddl/schema-ddl.ts +8 -2
  70. package/src/ddl/table-ddl.ts +12 -3
  71. package/src/define-db-context.ts +3 -1
  72. package/src/exec/executable.ts +4 -1
  73. package/src/exec/queryable.ts +91 -26
  74. package/src/exec/search-parser.ts +5 -1
  75. package/src/expr/expr.ts +56 -15
  76. package/src/query-builder/base/query-builder-base.ts +3 -1
  77. package/src/query-builder/mssql/mssql-expr-renderer.ts +6 -2
  78. package/src/query-builder/mssql/mssql-query-builder.ts +15 -5
  79. package/src/query-builder/mysql/mysql-expr-renderer.ts +6 -2
  80. package/src/query-builder/mysql/mysql-query-builder.ts +19 -6
  81. package/src/query-builder/postgresql/postgresql-expr-renderer.ts +6 -2
  82. package/src/query-builder/postgresql/postgresql-query-builder.ts +35 -13
  83. package/src/schema/factory/column-builder.ts +16 -5
  84. package/src/schema/factory/relation-builder.ts +14 -4
  85. package/src/schema/procedure-builder.ts +4 -1
  86. package/src/schema/table-builder.ts +14 -3
  87. package/src/schema/view-builder.ts +5 -1
  88. package/src/types/db-context-def.ts +37 -8
  89. package/src/types/db.ts +9 -2
  90. package/src/utils/result-parser.ts +10 -3
@@ -103,7 +103,10 @@ export class Executable<TParams extends ColumnBuilderRecord, TReturns extends Co
103
103
  * @see {@link Executable} 실행 클래스
104
104
  * @see {@link ProcedureBuilder} 프로시저 정의
105
105
  */
106
- export function executable<TParams extends ColumnBuilderRecord, TReturns extends ColumnBuilderRecord>(
106
+ export function executable<
107
+ TParams extends ColumnBuilderRecord,
108
+ TReturns extends ColumnBuilderRecord,
109
+ >(
107
110
  db: DbContextBase,
108
111
  builder: ProcedureBuilder<TParams, TReturns>,
109
112
  ): () => Executable<TParams, TReturns> {
@@ -14,7 +14,10 @@ import type {
14
14
  UpsertQueryDef,
15
15
  } from "../types/query-def";
16
16
  import type { DbContextBase } from "../types/db-context-def";
17
- import { type ColumnBuilderRecord, type DataToColumnBuilderRecord } from "../schema/factory/column-builder";
17
+ import {
18
+ type ColumnBuilderRecord,
19
+ type DataToColumnBuilderRecord,
20
+ } from "../schema/factory/column-builder";
18
21
  import type { ColumnPrimitive, ColumnPrimitiveStr } from "../types/column";
19
22
  import type { WhereExprUnit } from "../expr/expr-unit";
20
23
  import { ExprUnit } from "../expr/expr-unit";
@@ -110,7 +113,9 @@ class RecursiveQueryable<TBaseData extends DataRecord> {
110
113
  * @param table - 재귀할 대상 테이블
111
114
  * @returns self 속성이 추가된 Queryable (자기 참조용)
112
115
  */
113
- from<T extends TableBuilder<any, any>>(table: T): Queryable<T["$infer"] & { self?: TBaseData[] }, T> {
116
+ from<T extends TableBuilder<any, any>>(
117
+ table: T,
118
+ ): Queryable<T["$infer"] & { self?: TBaseData[] }, T> {
114
119
  const selfAlias = `${this._cteName}.self`;
115
120
 
116
121
  return queryable(this._baseQr.meta.db, table, this._cteName)().join(
@@ -132,7 +137,9 @@ class RecursiveQueryable<TBaseData extends DataRecord> {
132
137
  * @param columns - 커스텀 컬럼 정의
133
138
  * @returns self 속성이 추가된 Queryable
134
139
  */
135
- select<R extends DataRecord>(columns: QueryableRecord<R>): Queryable<R & { self?: TBaseData[] }, never> {
140
+ select<R extends DataRecord>(
141
+ columns: QueryableRecord<R>,
142
+ ): Queryable<R & { self?: TBaseData[] }, never> {
136
143
  const selfAlias = `${this._cteName}.self`;
137
144
 
138
145
  return new Queryable<R, never>({
@@ -240,7 +247,9 @@ export class Queryable<
240
247
  * }))
241
248
  * ```
242
249
  */
243
- select<R extends DataRecord>(fn: (columns: QueryableRecord<TData>) => QueryableRecord<R>): Queryable<R, never> {
250
+ select<R extends DataRecord>(
251
+ fn: (columns: QueryableRecord<TData>) => QueryableRecord<R>,
252
+ ): Queryable<R, never> {
244
253
  if (Array.isArray(this.meta.from)) {
245
254
  const newFroms = this.meta.from.map((from) => from.select(fn));
246
255
  return new Queryable({
@@ -507,7 +516,9 @@ export class Queryable<
507
516
  conditions.push(expr.or(columnMatches));
508
517
  } else if (parsed.or.length > 1) {
509
518
  const orConditions = parsed.or.map((pattern) => {
510
- const columnMatches = columns.map((col) => expr.like(expr.lower(col), pattern.toLowerCase()));
519
+ const columnMatches = columns.map((col) =>
520
+ expr.like(expr.lower(col), pattern.toLowerCase()),
521
+ );
511
522
  return expr.or(columnMatches);
512
523
  });
513
524
  conditions.push(expr.or(orConditions));
@@ -552,7 +563,9 @@ export class Queryable<
552
563
  * .groupBy((o) => [o.userId])
553
564
  * ```
554
565
  */
555
- groupBy(fn: (columns: QueryableRecord<TData>) => ExprUnit<ColumnPrimitive>[]): Queryable<TData, never> {
566
+ groupBy(
567
+ fn: (columns: QueryableRecord<TData>) => ExprUnit<ColumnPrimitive>[],
568
+ ): Queryable<TData, never> {
556
569
  if (Array.isArray(this.meta.from)) {
557
570
  const newFroms = this.meta.from.map((from) => from.groupBy(fn));
558
571
  return new Queryable({
@@ -677,7 +690,10 @@ export class Queryable<
677
690
  joinSingle<A extends string, R extends DataRecord>(
678
691
  as: A,
679
692
  fwd: (qr: JoinQueryable, cols: QueryableRecord<TData>) => Queryable<R, any>,
680
- ): Queryable<{ [K in keyof TData as K extends A ? never : K]: TData[K] } & { [K in A]?: R }, TFrom> {
693
+ ): Queryable<
694
+ { [K in keyof TData as K extends A ? never : K]: TData[K] } & { [K in A]?: R },
695
+ TFrom
696
+ > {
681
697
  if (Array.isArray(this.meta.from)) {
682
698
  const newFroms = this.meta.from.map((from) => from.joinSingle(as, fwd));
683
699
  return new Queryable({
@@ -797,7 +813,9 @@ export class Queryable<
797
813
 
798
814
  // FKT join은 배열로 저장되므로 배열인 경우 첫 번째 요소 사용
799
815
  const srcColsRaw = parentChain ? parentCols[parentChain] : parentCols;
800
- const srcCols = (Array.isArray(srcColsRaw) ? srcColsRaw[0] : srcColsRaw) as QueryableRecord<any>;
816
+ const srcCols = (
817
+ Array.isArray(srcColsRaw) ? srcColsRaw[0] : srcColsRaw
818
+ ) as QueryableRecord<any>;
801
819
  const conditions: WhereExprUnit[] = [];
802
820
 
803
821
  for (let i = 0; i < fkColKeys.length; i++) {
@@ -811,7 +829,10 @@ export class Queryable<
811
829
  });
812
830
 
813
831
  currentTable = targetTable;
814
- } else if (relationDef instanceof ForeignKeyTargetBuilder || relationDef instanceof RelationKeyTargetBuilder) {
832
+ } else if (
833
+ relationDef instanceof ForeignKeyTargetBuilder ||
834
+ relationDef instanceof RelationKeyTargetBuilder
835
+ ) {
815
836
  // FKT/RelationKeyTarget (1:N 또는 1:1): User.posts → Post[]
816
837
  // 조건: Post.userId = User.id
817
838
  const targetTable = relationDef.meta.targetTableFn();
@@ -834,7 +855,9 @@ export class Queryable<
834
855
 
835
856
  // FKT join은 배열로 저장되므로 배열인 경우 첫 번째 요소 사용
836
857
  const srcColsRaw = parentChain ? parentCols[parentChain] : parentCols;
837
- const srcCols = (Array.isArray(srcColsRaw) ? srcColsRaw[0] : srcColsRaw) as QueryableRecord<any>;
858
+ const srcCols = (
859
+ Array.isArray(srcColsRaw) ? srcColsRaw[0] : srcColsRaw
860
+ ) as QueryableRecord<any>;
838
861
  const conditions: WhereExprUnit[] = [];
839
862
 
840
863
  for (let i = 0; i < fkColKeys.length; i++) {
@@ -905,7 +928,9 @@ export class Queryable<
905
928
  * );
906
929
  * ```
907
930
  */
908
- static union<TData extends DataRecord>(...queries: Queryable<TData, any>[]): Queryable<TData, never> {
931
+ static union<TData extends DataRecord>(
932
+ ...queries: Queryable<TData, any>[]
933
+ ): Queryable<TData, never> {
909
934
  if (queries.length < 2) {
910
935
  throw new ArgumentError("union은 최소 2개의 queryable이 필요합니다.", {
911
936
  provided: queries.length,
@@ -946,7 +971,9 @@ export class Queryable<
946
971
  * )
947
972
  * ```
948
973
  */
949
- recursive(fwd: (qr: RecursiveQueryable<TData>) => Queryable<TData, any>): Queryable<TData, never> {
974
+ recursive(
975
+ fwd: (qr: RecursiveQueryable<TData>) => Queryable<TData, any>,
976
+ ): Queryable<TData, never> {
950
977
  if (Array.isArray(this.meta.from)) {
951
978
  const newFroms = this.meta.from.map((from) => from.recursive(fwd));
952
979
  return new Queryable({
@@ -994,7 +1021,10 @@ export class Queryable<
994
1021
  * ```
995
1022
  */
996
1023
  async result(): Promise<TData[]> {
997
- const results = await this.meta.db.executeDefs<TData>([this.getSelectQueryDef()], [this.getResultMeta()]);
1024
+ const results = await this.meta.db.executeDefs<TData>(
1025
+ [this.getSelectQueryDef()],
1026
+ [this.getResultMeta()],
1027
+ );
998
1028
  return results[0];
999
1029
  }
1000
1030
 
@@ -1126,7 +1156,12 @@ export class Queryable<
1126
1156
  });
1127
1157
  }
1128
1158
 
1129
- private _buildFromDef(): QueryDefObjectName | SelectQueryDef | SelectQueryDef[] | string | undefined {
1159
+ private _buildFromDef():
1160
+ | QueryDefObjectName
1161
+ | SelectQueryDef
1162
+ | SelectQueryDef[]
1163
+ | string
1164
+ | undefined {
1130
1165
  const from = this.meta.from;
1131
1166
 
1132
1167
  if (from instanceof TableBuilder || from instanceof ViewBuilder) {
@@ -1440,7 +1475,9 @@ export class Queryable<
1440
1475
  * }));
1441
1476
  * ```
1442
1477
  */
1443
- async update(recordFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferUpdate"]>): Promise<void>;
1478
+ async update(
1479
+ recordFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferUpdate"]>,
1480
+ ): Promise<void>;
1444
1481
  async update<K extends keyof TFrom["$columns"] & string>(
1445
1482
  recordFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferUpdate"]>,
1446
1483
  outputColumns: K[],
@@ -1479,7 +1516,9 @@ export class Queryable<
1479
1516
  * ```
1480
1517
  */
1481
1518
  async delete(): Promise<void>;
1482
- async delete<K extends keyof TFrom["$columns"] & string>(outputColumns: K[]): Promise<Pick<TFrom["$columns"], K>[]>;
1519
+ async delete<K extends keyof TFrom["$columns"] & string>(
1520
+ outputColumns: K[],
1521
+ ): Promise<Pick<TFrom["$columns"], K>[]>;
1483
1522
  async delete<K extends keyof TFrom["$columns"] & string>(
1484
1523
  outputColumns?: K[],
1485
1524
  ): Promise<Pick<TFrom["$columns"], K>[] | void> {
@@ -1574,7 +1613,9 @@ export class Queryable<
1574
1613
  * );
1575
1614
  * ```
1576
1615
  */
1577
- async upsert(updateFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferUpdate"]>): Promise<void>;
1616
+ async upsert(
1617
+ updateFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferUpdate"]>,
1618
+ ): Promise<void>;
1578
1619
  async upsert<K extends keyof TFrom["$inferColumns"] & string>(
1579
1620
  insertFwd: (cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferInsert"]>,
1580
1621
  outputColumns?: K[],
@@ -1583,12 +1624,18 @@ export class Queryable<
1583
1624
  updateFwd: (cols: QueryableRecord<TData>) => U,
1584
1625
  insertFwd: (updateRecord: U) => QueryableRecord<TFrom["$inferInsert"]>,
1585
1626
  ): Promise<void>;
1586
- async upsert<U extends QueryableRecord<TFrom["$inferUpdate"]>, K extends keyof TFrom["$inferColumns"] & string>(
1627
+ async upsert<
1628
+ U extends QueryableRecord<TFrom["$inferUpdate"]>,
1629
+ K extends keyof TFrom["$inferColumns"] & string,
1630
+ >(
1587
1631
  updateFwd: (cols: QueryableRecord<TData>) => U,
1588
1632
  insertFwd: (updateRecord: U) => QueryableRecord<TFrom["$inferInsert"]>,
1589
1633
  outputColumns?: K[],
1590
1634
  ): Promise<Pick<TFrom["$inferColumns"], K>[]>;
1591
- async upsert<U extends QueryableRecord<TFrom["$inferUpdate"]>, K extends keyof TFrom["$inferColumns"] & string>(
1635
+ async upsert<
1636
+ U extends QueryableRecord<TFrom["$inferUpdate"]>,
1637
+ K extends keyof TFrom["$inferColumns"] & string,
1638
+ >(
1592
1639
  updateFwdOrInsertFwd:
1593
1640
  | ((cols: QueryableRecord<TData>) => U)
1594
1641
  | ((cols: QueryableRecord<TData>) => QueryableRecord<TFrom["$inferInsert"]>),
@@ -1601,7 +1648,8 @@ export class Queryable<
1601
1648
  insertFwdOrOutputColumns instanceof Function ? insertFwdOrOutputColumns : updateFwdOrInsertFwd
1602
1649
  ) as (updateRecord: U) => QueryableRecord<TFrom["$inferInsert"]>;
1603
1650
 
1604
- const realOutputColumns = insertFwdOrOutputColumns instanceof Function ? outputColumns : insertFwdOrOutputColumns;
1651
+ const realOutputColumns =
1652
+ insertFwdOrOutputColumns instanceof Function ? outputColumns : insertFwdOrOutputColumns;
1605
1653
 
1606
1654
  const results = await this.meta.db.executeDefs<Pick<TFrom["$inferColumns"], K>>(
1607
1655
  [this.getUpsertQueryDef(updateRecordFwd, insertRecordFwd, realOutputColumns)],
@@ -1662,7 +1710,9 @@ export class Queryable<
1662
1710
  async switchFk(switch_: "on" | "off"): Promise<void> {
1663
1711
  const from = this.meta.from;
1664
1712
  if (!(from instanceof TableBuilder) && !(from instanceof ViewBuilder)) {
1665
- throw new Error("switchFk는 TableBuilder 또는 ViewBuilder 기반 queryable에서만 사용할 수 있습니다.");
1713
+ throw new Error(
1714
+ "switchFk는 TableBuilder 또는 ViewBuilder 기반 queryable에서만 사용할 수 있습니다.",
1715
+ );
1666
1716
  }
1667
1717
  await this.meta.db.switchFk(this.meta.db.getQueryDefObjectName(from), switch_);
1668
1718
  }
@@ -1711,7 +1761,10 @@ export class Queryable<
1711
1761
  * @returns 매칭된 PK 컬럼명 배열
1712
1762
  * @throws FK/PK 컬럼 수 불일치 시
1713
1763
  */
1714
- export function getMatchedPrimaryKeys(fkCols: string[], targetTable: TableBuilder<any, any>): string[] {
1764
+ export function getMatchedPrimaryKeys(
1765
+ fkCols: string[],
1766
+ targetTable: TableBuilder<any, any>,
1767
+ ): string[] {
1715
1768
  const pk = targetTable.meta.primaryKey;
1716
1769
  if (pk == null || fkCols.length !== pk.length) {
1717
1770
  throw new Error(
@@ -1749,7 +1802,9 @@ function transformColumnsAlias<TRecord extends DataRecord>(
1749
1802
  result[key] = expr.col(value.dataType, alias, fullKey);
1750
1803
  } else if (Array.isArray(value)) {
1751
1804
  if (value.length > 0) {
1752
- result[key] = [transformColumnsAlias(value[0] as QueryableRecord<DataRecord>, alias, fullKey)];
1805
+ result[key] = [
1806
+ transformColumnsAlias(value[0] as QueryableRecord<DataRecord>, alias, fullKey),
1807
+ ];
1753
1808
  }
1754
1809
  } else if (typeof value === "object" && value != null) {
1755
1810
  result[key] = transformColumnsAlias(value as QueryableRecord<DataRecord>, alias, fullKey);
@@ -1767,7 +1822,12 @@ function transformColumnsAlias<TRecord extends DataRecord>(
1767
1822
 
1768
1823
  interface QueryableMeta<TData extends DataRecord> {
1769
1824
  db: DbContextBase;
1770
- from?: TableBuilder<any, any> | ViewBuilder<any, any, any> | Queryable<any, any> | Queryable<TData, any>[] | string;
1825
+ from?:
1826
+ | TableBuilder<any, any>
1827
+ | ViewBuilder<any, any, any>
1828
+ | Queryable<any, any>
1829
+ | Queryable<TData, any>[]
1830
+ | string;
1771
1831
  as: string;
1772
1832
  columns: QueryableRecord<TData>;
1773
1833
  isCustomColumns?: boolean;
@@ -1835,7 +1895,9 @@ const PATH_SYMBOL = Symbol("path");
1835
1895
  * include()용 타입 안전 경로 프록시
1836
1896
  */
1837
1897
  export type PathProxy<TObject> = {
1838
- [K in keyof TObject as TObject[K] extends ColumnPrimitive ? never : K]-?: PathProxy<UnwrapArray<TObject[K]>>;
1898
+ [K in keyof TObject as TObject[K] extends ColumnPrimitive ? never : K]-?: PathProxy<
1899
+ UnwrapArray<TObject[K]>
1900
+ >;
1839
1901
  } & { readonly [PATH_SYMBOL]: string[] };
1840
1902
 
1841
1903
  /**
@@ -1898,7 +1960,10 @@ export function queryable<TBuilder extends TableBuilder<any, any> | ViewBuilder<
1898
1960
  from: tableOrView,
1899
1961
  as: finalAs,
1900
1962
  columns: Object.fromEntries(
1901
- Object.entries(columnDefs).map(([key, colDef]) => [key, expr.col(colDef.meta.type, finalAs, key)]),
1963
+ Object.entries(columnDefs).map(([key, colDef]) => [
1964
+ key,
1965
+ expr.col(colDef.meta.type, finalAs, key),
1966
+ ]),
1902
1967
  ),
1903
1968
  }) as any;
1904
1969
  }
@@ -164,7 +164,11 @@ function termToLikePattern(term: string): string {
164
164
  let pattern = term.replace(/\*/g, WILDCARD);
165
165
 
166
166
  // SQL LIKE 특수문자 이스케이프 (\ → \\, % → \%, _ → \_, [ → \[)
167
- pattern = pattern.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_").replace(/\[/g, "\\[");
167
+ pattern = pattern
168
+ .replace(/\\/g, "\\\\")
169
+ .replace(/%/g, "\\%")
170
+ .replace(/_/g, "\\_")
171
+ .replace(/\[/g, "\\[");
168
172
 
169
173
  // 와일드카드 마커 → % (SQL 와일드카드)
170
174
  pattern = pattern.replaceAll(WILDCARD, "%");
package/src/expr/expr.ts CHANGED
@@ -88,7 +88,9 @@ export const expr = {
88
88
  val<TStr extends ColumnPrimitiveStr, T extends ColumnPrimitiveMap[TStr] | undefined>(
89
89
  dataType: TStr,
90
90
  value: T,
91
- ): ExprUnit<T extends undefined ? ColumnPrimitiveMap[TStr] | undefined : ColumnPrimitiveMap[TStr]> {
91
+ ): ExprUnit<
92
+ T extends undefined ? ColumnPrimitiveMap[TStr] | undefined : ColumnPrimitiveMap[TStr]
93
+ > {
92
94
  return new ExprUnit(dataType, { type: "value", value });
93
95
  },
94
96
 
@@ -287,7 +289,11 @@ export const expr = {
287
289
  * // WHERE age >= 18
288
290
  * ```
289
291
  */
290
- between<T extends ColumnPrimitive>(source: ExprUnit<T>, from?: ExprInput<T>, to?: ExprInput<T>): WhereExprUnit {
292
+ between<T extends ColumnPrimitive>(
293
+ source: ExprUnit<T>,
294
+ from?: ExprInput<T>,
295
+ to?: ExprInput<T>,
296
+ ): WhereExprUnit {
291
297
  return new WhereExprUnit({
292
298
  type: "between",
293
299
  source: toExpr(source),
@@ -343,7 +349,10 @@ export const expr = {
343
349
  * db.user().where((u) => [expr.like(u.email, "%@gmail.com")])
344
350
  * ```
345
351
  */
346
- like(source: ExprUnit<string | undefined>, pattern: ExprInput<string | undefined>): WhereExprUnit {
352
+ like(
353
+ source: ExprUnit<string | undefined>,
354
+ pattern: ExprInput<string | undefined>,
355
+ ): WhereExprUnit {
347
356
  return new WhereExprUnit({
348
357
  type: "like",
349
358
  source: toExpr(source),
@@ -366,7 +375,10 @@ export const expr = {
366
375
  * // MySQL: WHERE email REGEXP '^[a-z]+@'
367
376
  * ```
368
377
  */
369
- regexp(source: ExprUnit<string | undefined>, pattern: ExprInput<string | undefined>): WhereExprUnit {
378
+ regexp(
379
+ source: ExprUnit<string | undefined>,
380
+ pattern: ExprInput<string | undefined>,
381
+ ): WhereExprUnit {
370
382
  return new WhereExprUnit({
371
383
  type: "regexp",
372
384
  source: toExpr(source),
@@ -1022,7 +1034,9 @@ export const expr = {
1022
1034
  * // SELECT HOUR(createdAt) AS logHour
1023
1035
  * ```
1024
1036
  */
1025
- hour<T extends DateTime | Time | undefined>(source: ExprUnit<T>): ExprUnit<T extends undefined ? undefined : number> {
1037
+ hour<T extends DateTime | Time | undefined>(
1038
+ source: ExprUnit<T>,
1039
+ ): ExprUnit<T extends undefined ? undefined : number> {
1026
1040
  return new ExprUnit("number", {
1027
1041
  type: "hour",
1028
1042
  arg: toExpr(source),
@@ -1091,7 +1105,9 @@ export const expr = {
1091
1105
  * // SELECT WEEK(orderDate, 3) AS weekNum (MySQL)
1092
1106
  * ```
1093
1107
  */
1094
- isoWeek<T extends DateOnly | undefined>(source: ExprUnit<T>): ExprUnit<T extends undefined ? undefined : number> {
1108
+ isoWeek<T extends DateOnly | undefined>(
1109
+ source: ExprUnit<T>,
1110
+ ): ExprUnit<T extends undefined ? undefined : number> {
1095
1111
  return new ExprUnit("number", {
1096
1112
  type: "isoWeek",
1097
1113
  arg: toExpr(source),
@@ -1271,7 +1287,10 @@ export const expr = {
1271
1287
  * // SELECT NULLIF(bio, '') AS bio
1272
1288
  * ```
1273
1289
  */
1274
- nullIf<T extends ColumnPrimitive>(source: ExprUnit<T>, value: ExprInput<T>): ExprUnit<T | undefined> {
1290
+ nullIf<T extends ColumnPrimitive>(
1291
+ source: ExprUnit<T>,
1292
+ value: ExprInput<T>,
1293
+ ): ExprUnit<T | undefined> {
1275
1294
  return new ExprUnit(source.dataType, {
1276
1295
  type: "nullIf",
1277
1296
  source: toExpr(source),
@@ -1341,7 +1360,11 @@ export const expr = {
1341
1360
  * // SELECT IF(age >= 18, 'adult', 'minor') AS type
1342
1361
  * ```
1343
1362
  */
1344
- if<T extends ColumnPrimitive>(condition: WhereExprUnit, then: ExprInput<T>, else_: ExprInput<T>): ExprUnit<T> {
1363
+ if<T extends ColumnPrimitive>(
1364
+ condition: WhereExprUnit,
1365
+ then: ExprInput<T>,
1366
+ else_: ExprInput<T>,
1367
+ ): ExprUnit<T> {
1345
1368
  const allValues = [then, else_];
1346
1369
  // 1. ExprUnit에서 dataType 찾기
1347
1370
  const exprUnit = allValues.find((v): v is ExprUnit<T> => v instanceof ExprUnit);
@@ -1832,7 +1855,10 @@ export const expr = {
1832
1855
  * }))
1833
1856
  * ```
1834
1857
  */
1835
- firstValue<T extends ColumnPrimitive>(column: ExprUnit<T>, spec: WinSpecInput): ExprUnit<T | undefined> {
1858
+ firstValue<T extends ColumnPrimitive>(
1859
+ column: ExprUnit<T>,
1860
+ spec: WinSpecInput,
1861
+ ): ExprUnit<T | undefined> {
1836
1862
  return new ExprUnit(column.dataType, {
1837
1863
  type: "window",
1838
1864
  fn: { type: "firstValue", column: toExpr(column) },
@@ -1858,7 +1884,10 @@ export const expr = {
1858
1884
  * }))
1859
1885
  * ```
1860
1886
  */
1861
- lastValue<T extends ColumnPrimitive>(column: ExprUnit<T>, spec: WinSpecInput): ExprUnit<T | undefined> {
1887
+ lastValue<T extends ColumnPrimitive>(
1888
+ column: ExprUnit<T>,
1889
+ spec: WinSpecInput,
1890
+ ): ExprUnit<T | undefined> {
1862
1891
  return new ExprUnit(column.dataType, {
1863
1892
  type: "window",
1864
1893
  fn: { type: "lastValue", column: toExpr(column) },
@@ -1962,7 +1991,10 @@ export const expr = {
1962
1991
  * }))
1963
1992
  * ```
1964
1993
  */
1965
- minOver<T extends ColumnPrimitive>(column: ExprUnit<T>, spec: WinSpecInput): ExprUnit<T | undefined> {
1994
+ minOver<T extends ColumnPrimitive>(
1995
+ column: ExprUnit<T>,
1996
+ spec: WinSpecInput,
1997
+ ): ExprUnit<T | undefined> {
1966
1998
  return new ExprUnit(column.dataType, {
1967
1999
  type: "window",
1968
2000
  fn: { type: "min", column: toExpr(column) },
@@ -1987,7 +2019,10 @@ export const expr = {
1987
2019
  * }))
1988
2020
  * ```
1989
2021
  */
1990
- maxOver<T extends ColumnPrimitive>(column: ExprUnit<T>, spec: WinSpecInput): ExprUnit<T | undefined> {
2022
+ maxOver<T extends ColumnPrimitive>(
2023
+ column: ExprUnit<T>,
2024
+ spec: WinSpecInput,
2025
+ ): ExprUnit<T | undefined> {
1991
2026
  return new ExprUnit(column.dataType, {
1992
2027
  type: "window",
1993
2028
  fn: { type: "max", column: toExpr(column) },
@@ -2022,8 +2057,12 @@ function ifNull<TPrimitive extends ColumnPrimitive>(
2022
2057
  ExprInput<NonNullable<TPrimitive>>,
2023
2058
  ]
2024
2059
  ): ExprUnit<NonNullable<TPrimitive>>;
2025
- function ifNull<TPrimitive extends ColumnPrimitive>(...args: ExprInput<TPrimitive>[]): ExprUnit<TPrimitive>;
2026
- function ifNull<TPrimitive extends ColumnPrimitive>(...args: ExprInput<TPrimitive>[]): ExprUnit<TPrimitive> {
2060
+ function ifNull<TPrimitive extends ColumnPrimitive>(
2061
+ ...args: ExprInput<TPrimitive>[]
2062
+ ): ExprUnit<TPrimitive>;
2063
+ function ifNull<TPrimitive extends ColumnPrimitive>(
2064
+ ...args: ExprInput<TPrimitive>[]
2065
+ ): ExprUnit<TPrimitive> {
2027
2066
  return new ExprUnit(findDataType(args), {
2028
2067
  type: "ifNull",
2029
2068
  args: args.map((a) => toExpr(a)),
@@ -2077,7 +2116,9 @@ export function toExpr(value: ExprInput<ColumnPrimitive>): Expr {
2077
2116
  return { type: "value", value };
2078
2117
  }
2079
2118
 
2080
- function findDataType<TPrimitive extends ColumnPrimitive>(args: ExprInput<TPrimitive>[]): ColumnPrimitiveStr {
2119
+ function findDataType<TPrimitive extends ColumnPrimitive>(
2120
+ args: ExprInput<TPrimitive>[],
2121
+ ): ColumnPrimitiveStr {
2081
2122
  const exprUnit = args.find((a): a is ExprUnit<TPrimitive> => a instanceof ExprUnit);
2082
2123
  if (!exprUnit) {
2083
2124
  throw new Error("args중 적어도 하나는 ExprUnit이어야 합니다.");
@@ -78,7 +78,9 @@ export abstract class QueryBuilderBase {
78
78
  /** ORDER BY 절 렌더링 */
79
79
  protected renderOrderBy(orderBy: [Expr, ("ASC" | "DESC")?][] | undefined): string {
80
80
  if (orderBy == null || orderBy.length === 0) return "";
81
- const parts = orderBy.map(([e, dir]) => `${this.expr.render(e)}${dir != null ? ` ${dir}` : ""}`);
81
+ const parts = orderBy.map(
82
+ ([e, dir]) => `${this.expr.render(e)}${dir != null ? ` ${dir}` : ""}`,
83
+ );
82
84
  return ` ORDER BY ${parts.join(", ")}`;
83
85
  }
84
86
 
@@ -457,7 +457,9 @@ export class MssqlExprRenderer extends ExprRendererBase {
457
457
  }
458
458
 
459
459
  protected switch(expr: ExprSwitch): string {
460
- const cases = expr.cases.map((c) => `WHEN ${this.render(c.when)} THEN ${this.render(c.then)}`).join(" ");
460
+ const cases = expr.cases
461
+ .map((c) => `WHEN ${this.render(c.when)} THEN ${this.render(c.then)}`)
462
+ .join(" ");
461
463
  return `CASE ${cases} ELSE ${this.render(expr.else)} END`;
462
464
  }
463
465
 
@@ -585,7 +587,9 @@ export class MssqlExprRenderer extends ExprRendererBase {
585
587
  parts.push(`PARTITION BY ${spec.partitionBy.map((p) => this.render(p)).join(", ")}`);
586
588
  }
587
589
  if (spec.orderBy != null && spec.orderBy.length > 0) {
588
- const orderParts = spec.orderBy.map(([expr, dir]) => `${this.render(expr)}${dir != null ? ` ${dir}` : ""}`);
590
+ const orderParts = spec.orderBy.map(
591
+ ([expr, dir]) => `${this.render(expr)}${dir != null ? ` ${dir}` : ""}`,
592
+ );
589
593
  parts.push(`ORDER BY ${orderParts.join(", ")}`);
590
594
  }
591
595
  return parts.join(" ");
@@ -75,7 +75,10 @@ export class MssqlQueryBuilder extends QueryBuilderBase {
75
75
  }
76
76
 
77
77
  // 일반 JOIN
78
- const where = join.where != null && join.where.length > 0 ? ` ON ${this.expr.renderWhere(join.where)}` : " ON 1=1";
78
+ const where =
79
+ join.where != null && join.where.length > 0
80
+ ? ` ON ${this.expr.renderWhere(join.where)}`
81
+ : " ON 1=1";
79
82
  return ` LEFT OUTER JOIN ${from} AS ${alias}${where}`;
80
83
  }
81
84
 
@@ -321,7 +324,8 @@ export class MssqlQueryBuilder extends QueryBuilderBase {
321
324
 
322
325
  let sql = `MERGE ${table} AS ${alias}\n`;
323
326
  sql += `USING (SELECT 1 AS [_]) AS [_src] ON `;
324
- sql += existsWhere != null && existsWhere.length > 0 ? this.expr.renderWhere(existsWhere) : "1=0";
327
+ sql +=
328
+ existsWhere != null && existsWhere.length > 0 ? this.expr.renderWhere(existsWhere) : "1=0";
325
329
 
326
330
  if (updateSetParts.length > 0) {
327
331
  sql += `\nWHEN MATCHED THEN UPDATE SET ${updateSetParts.join(", ")}`;
@@ -422,7 +426,9 @@ export class MssqlQueryBuilder extends QueryBuilderBase {
422
426
  }
423
427
 
424
428
  protected dropColumn(def: DropColumnQueryDef): QueryBuildResult {
425
- return { sql: `ALTER TABLE ${this.tableName(def.table)} DROP COLUMN ${this.expr.wrap(def.column)}` };
429
+ return {
430
+ sql: `ALTER TABLE ${this.tableName(def.table)} DROP COLUMN ${this.expr.wrap(def.column)}`,
431
+ };
426
432
  }
427
433
 
428
434
  protected modifyColumn(def: ModifyColumnQueryDef): QueryBuildResult {
@@ -458,7 +464,9 @@ export class MssqlQueryBuilder extends QueryBuilderBase {
458
464
  const table = this.tableName(def.table);
459
465
  const cols = def.columns.map((c) => this.expr.wrap(c)).join(", ");
460
466
  const pkName = `PK_${def.table.name}`;
461
- return { sql: `ALTER TABLE ${table} ADD CONSTRAINT ${this.expr.wrap(pkName)} PRIMARY KEY (${cols})` };
467
+ return {
468
+ sql: `ALTER TABLE ${table} ADD CONSTRAINT ${this.expr.wrap(pkName)} PRIMARY KEY (${cols})`,
469
+ };
462
470
  }
463
471
 
464
472
  protected dropPk(def: DropPkQueryDef): QueryBuildResult {
@@ -484,7 +492,9 @@ export class MssqlQueryBuilder extends QueryBuilderBase {
484
492
  }
485
493
 
486
494
  protected dropFk(def: DropFkQueryDef): QueryBuildResult {
487
- return { sql: `ALTER TABLE ${this.tableName(def.table)} DROP CONSTRAINT ${this.expr.wrap(def.foreignKey)}` };
495
+ return {
496
+ sql: `ALTER TABLE ${this.tableName(def.table)} DROP CONSTRAINT ${this.expr.wrap(def.foreignKey)}`,
497
+ };
488
498
  }
489
499
 
490
500
  protected addIdx(def: AddIdxQueryDef): QueryBuildResult {
@@ -467,7 +467,9 @@ export class MysqlExprRenderer extends ExprRendererBase {
467
467
  }
468
468
 
469
469
  protected switch(expr: ExprSwitch): string {
470
- const cases = expr.cases.map((c) => `WHEN ${this.render(c.when)} THEN ${this.render(c.then)}`).join(" ");
470
+ const cases = expr.cases
471
+ .map((c) => `WHEN ${this.render(c.when)} THEN ${this.render(c.then)}`)
472
+ .join(" ");
471
473
  return `CASE ${cases} ELSE ${this.render(expr.else)} END`;
472
474
  }
473
475
 
@@ -591,7 +593,9 @@ export class MysqlExprRenderer extends ExprRendererBase {
591
593
  parts.push(`PARTITION BY ${spec.partitionBy.map((p) => this.render(p)).join(", ")}`);
592
594
  }
593
595
  if (spec.orderBy != null && spec.orderBy.length > 0) {
594
- const orderParts = spec.orderBy.map(([expr, dir]) => `${this.render(expr)}${dir != null ? ` ${dir}` : ""}`);
596
+ const orderParts = spec.orderBy.map(
597
+ ([expr, dir]) => `${this.render(expr)}${dir != null ? ` ${dir}` : ""}`,
598
+ );
595
599
  parts.push(`ORDER BY ${orderParts.join(", ")}`);
596
600
  }
597
601
  return parts.join(" ");
@@ -75,7 +75,10 @@ export class MysqlQueryBuilder extends QueryBuilderBase {
75
75
  protected renderJoin(join: SelectQueryDefJoin): string {
76
76
  const alias = this.expr.wrap(join.as);
77
77
  const from = this.renderFrom(join.from);
78
- const where = join.where != null && join.where.length > 0 ? ` ON ${this.expr.renderWhere(join.where)}` : " ON TRUE";
78
+ const where =
79
+ join.where != null && join.where.length > 0
80
+ ? ` ON ${this.expr.renderWhere(join.where)}`
81
+ : " ON TRUE";
79
82
 
80
83
  // LATERAL JOIN 필요 여부 감지
81
84
  if (this.needsLateral(join)) {
@@ -287,7 +290,9 @@ export class MysqlQueryBuilder extends QueryBuilderBase {
287
290
  // recordsSelectQuery에서 PK 컬럼만 추출한 SELECT 생성
288
291
  const pkSelectDef: SelectQueryDef = {
289
292
  ...def.recordsSelectQuery,
290
- select: Object.fromEntries(def.output.pkColNames.map((pk) => [pk, def.recordsSelectQuery.select![pk]])),
293
+ select: Object.fromEntries(
294
+ def.output.pkColNames.map((pk) => [pk, def.recordsSelectQuery.select![pk]]),
295
+ ),
291
296
  };
292
297
  const pkSelectSql = this.select(pkSelectDef).sql;
293
298
 
@@ -569,7 +574,9 @@ export class MysqlQueryBuilder extends QueryBuilderBase {
569
574
  }
570
575
 
571
576
  protected dropColumn(def: DropColumnQueryDef): QueryBuildResult {
572
- return { sql: `ALTER TABLE ${this.tableName(def.table)} DROP COLUMN ${this.expr.wrap(def.column)}` };
577
+ return {
578
+ sql: `ALTER TABLE ${this.tableName(def.table)} DROP COLUMN ${this.expr.wrap(def.column)}`,
579
+ };
573
580
  }
574
581
 
575
582
  protected modifyColumn(def: ModifyColumnQueryDef): QueryBuildResult {
@@ -632,7 +639,9 @@ export class MysqlQueryBuilder extends QueryBuilderBase {
632
639
  }
633
640
 
634
641
  protected dropFk(def: DropFkQueryDef): QueryBuildResult {
635
- return { sql: `ALTER TABLE ${this.tableName(def.table)} DROP FOREIGN KEY ${this.expr.wrap(def.foreignKey)}` };
642
+ return {
643
+ sql: `ALTER TABLE ${this.tableName(def.table)} DROP FOREIGN KEY ${this.expr.wrap(def.foreignKey)}`,
644
+ };
636
645
  }
637
646
 
638
647
  protected addIdx(def: AddIdxQueryDef): QueryBuildResult {
@@ -731,12 +740,16 @@ SET FOREIGN_KEY_CHECKS = 1`,
731
740
  protected schemaExists(def: SchemaExistsQueryDef): QueryBuildResult {
732
741
  // MySQL: database와 schema는 동의어
733
742
  const dbName = this.expr.escapeString(def.database);
734
- return { sql: `SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = '${dbName}'` };
743
+ return {
744
+ sql: `SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = '${dbName}'`,
745
+ };
735
746
  }
736
747
 
737
748
  /** MySQL은 전역 설정만 지원 (테이블 파라미터 무시됨) */
738
749
  protected switchFk(def: SwitchFkQueryDef): QueryBuildResult {
739
- return def.switch === "on" ? { sql: "SET FOREIGN_KEY_CHECKS = 1" } : { sql: "SET FOREIGN_KEY_CHECKS = 0" };
750
+ return def.switch === "on"
751
+ ? { sql: "SET FOREIGN_KEY_CHECKS = 1" }
752
+ : { sql: "SET FOREIGN_KEY_CHECKS = 0" };
740
753
  }
741
754
 
742
755
  //#endregion