metal-orm 1.1.11 → 1.1.18

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 (182) hide show
  1. package/README.md +758 -769
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/package.json +100 -96
  5. package/scripts/generate-entities/schema.mjs +122 -122
  6. package/scripts/generate-entities/tree-detection.mjs +92 -92
  7. package/scripts/inflection/pt-br.mjs +468 -468
  8. package/scripts/run-eslint.mjs +33 -34
  9. package/scripts/show-sql-seed.sql +102 -0
  10. package/scripts/show-sql.mjs +321 -325
  11. package/src/codegen/naming-strategy.ts +54 -54
  12. package/src/codegen/typescript.ts +482 -482
  13. package/src/core/ast/adapters.ts +1 -1
  14. package/src/core/ast/builders.ts +123 -123
  15. package/src/core/ast/expression-builders.ts +745 -745
  16. package/src/core/ast/expression-nodes.ts +304 -304
  17. package/src/core/ast/expression-visitor.ts +212 -212
  18. package/src/core/ast/expression.ts +20 -20
  19. package/src/core/ast/helpers.ts +14 -14
  20. package/src/core/ast/join.ts +18 -18
  21. package/src/core/ast/query.ts +200 -200
  22. package/src/core/ddl/dialects/base-schema-dialect.ts +1 -1
  23. package/src/core/ddl/dialects/mssql-schema-dialect.ts +1 -1
  24. package/src/core/ddl/dialects/mysql-schema-dialect.ts +1 -1
  25. package/src/core/ddl/dialects/postgres-schema-dialect.ts +1 -1
  26. package/src/core/ddl/dialects/render-reference.test.ts +70 -70
  27. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +1 -1
  28. package/src/core/ddl/introspect/catalogs/index.ts +5 -5
  29. package/src/core/ddl/introspect/catalogs/postgres.ts +146 -146
  30. package/src/core/ddl/introspect/context.ts +15 -15
  31. package/src/core/ddl/introspect/functions/postgres.ts +35 -35
  32. package/src/core/ddl/introspect/registry.ts +40 -40
  33. package/src/core/ddl/introspect/run-select.ts +35 -35
  34. package/src/core/ddl/introspect/utils.ts +56 -56
  35. package/src/core/ddl/naming-strategy.ts +16 -16
  36. package/src/core/ddl/schema-dialect.ts +56 -56
  37. package/src/core/ddl/schema-diff.ts +234 -234
  38. package/src/core/ddl/schema-generator.ts +1 -1
  39. package/src/core/ddl/schema-introspect.ts +25 -25
  40. package/src/core/ddl/sql-writing.ts +171 -171
  41. package/src/core/dialect/abstract.ts +541 -541
  42. package/src/core/dialect/base/cte-compiler.ts +33 -33
  43. package/src/core/dialect/base/function-table-formatter.ts +103 -103
  44. package/src/core/dialect/base/groupby-compiler.ts +21 -21
  45. package/src/core/dialect/base/join-compiler.ts +25 -25
  46. package/src/core/dialect/base/orderby-compiler.ts +35 -35
  47. package/src/core/dialect/base/pagination-strategy.ts +32 -32
  48. package/src/core/dialect/base/returning-strategy.ts +57 -57
  49. package/src/core/dialect/base/sql-dialect.ts +294 -294
  50. package/src/core/dialect/dialect-factory.ts +91 -91
  51. package/src/core/dialect/mssql/functions.ts +120 -120
  52. package/src/core/dialect/mssql/index.ts +317 -317
  53. package/src/core/dialect/mysql/functions.ts +103 -103
  54. package/src/core/dialect/mysql/index.ts +105 -105
  55. package/src/core/dialect/postgres/functions.ts +108 -108
  56. package/src/core/dialect/postgres/index.ts +91 -91
  57. package/src/core/dialect/sqlite/functions.ts +129 -129
  58. package/src/core/dialect/sqlite/index.ts +67 -67
  59. package/src/core/driver/database-driver.ts +19 -19
  60. package/src/core/driver/mssql-driver.ts +23 -23
  61. package/src/core/driver/mysql-driver.ts +23 -23
  62. package/src/core/driver/postgres-driver.ts +23 -23
  63. package/src/core/driver/sqlite-driver.ts +23 -23
  64. package/src/core/execution/db-executor.ts +92 -92
  65. package/src/core/execution/executors/better-sqlite3-executor.ts +90 -90
  66. package/src/core/execution/executors/mssql-executor.ts +184 -184
  67. package/src/core/execution/executors/mysql-executor.ts +88 -88
  68. package/src/core/execution/executors/postgres-executor.ts +26 -26
  69. package/src/core/execution/executors/sqlite-executor.ts +42 -42
  70. package/src/core/execution/pooling/pool-types.ts +30 -30
  71. package/src/core/execution/pooling/pool.ts +275 -275
  72. package/src/core/functions/array.ts +35 -35
  73. package/src/core/functions/control-flow.ts +79 -79
  74. package/src/core/functions/datetime.ts +237 -237
  75. package/src/core/functions/json.ts +70 -70
  76. package/src/core/functions/numeric.ts +297 -297
  77. package/src/core/functions/text.ts +334 -334
  78. package/src/core/functions/types.ts +33 -33
  79. package/src/core/hydration/types.ts +51 -51
  80. package/src/core/sql/sql-operator-config.ts +39 -39
  81. package/src/core/sql/sql.ts +152 -152
  82. package/src/decorators/column-decorator.ts +87 -87
  83. package/src/decorators/decorator-metadata.ts +143 -143
  84. package/src/decorators/entity.ts +93 -93
  85. package/src/decorators/index.ts +39 -39
  86. package/src/decorators/relations.ts +231 -231
  87. package/src/decorators/transformers/built-in/string-transformers.ts +231 -231
  88. package/src/decorators/transformers/transformer-decorators.ts +134 -134
  89. package/src/decorators/transformers/transformer-executor.ts +171 -171
  90. package/src/decorators/transformers/transformer-metadata.ts +73 -73
  91. package/src/decorators/validators/built-in/br-cep-validator.ts +55 -55
  92. package/src/decorators/validators/built-in/br-cnpj-validator.ts +105 -105
  93. package/src/decorators/validators/built-in/br-cpf-validator.ts +103 -103
  94. package/src/decorators/validators/country-validator-registry.ts +64 -64
  95. package/src/decorators/validators/country-validators-decorators.ts +203 -203
  96. package/src/decorators/validators/country-validators.ts +105 -105
  97. package/src/decorators/validators/validator-metadata.ts +59 -59
  98. package/src/dto/dto-types.ts +226 -226
  99. package/src/dto/filter-types.ts +141 -141
  100. package/src/dto/index.ts +95 -95
  101. package/src/dto/openapi/generators/base.ts +29 -29
  102. package/src/dto/openapi/generators/column.ts +37 -37
  103. package/src/dto/openapi/generators/dto.ts +91 -91
  104. package/src/dto/openapi/generators/filter.ts +75 -75
  105. package/src/dto/openapi/generators/nested-dto.ts +618 -618
  106. package/src/dto/openapi/generators/pagination.ts +111 -111
  107. package/src/dto/openapi/generators/relation-filter.ts +228 -228
  108. package/src/dto/openapi/index.ts +12 -12
  109. package/src/dto/openapi/types.ts +101 -101
  110. package/src/dto/openapi/utilities.ts +95 -95
  111. package/src/dto/pagination-utils.ts +150 -150
  112. package/src/dto/transform.ts +197 -197
  113. package/src/index.ts +86 -86
  114. package/src/orm/als.ts +58 -58
  115. package/src/orm/domain-event-bus.ts +119 -119
  116. package/src/orm/entity-context.ts +86 -86
  117. package/src/orm/entity-materializer.ts +159 -159
  118. package/src/orm/entity-meta.ts +97 -97
  119. package/src/orm/entity-registry.ts +39 -39
  120. package/src/orm/entity-relation-cache.ts +39 -39
  121. package/src/orm/execute.ts +194 -194
  122. package/src/orm/execution-context.ts +18 -18
  123. package/src/orm/hydration-context.ts +26 -26
  124. package/src/orm/hydration.ts +112 -112
  125. package/src/orm/identity-map.ts +61 -61
  126. package/src/orm/interceptor-pipeline.ts +16 -16
  127. package/src/orm/lazy-batch/belongs-to-many.ts +119 -119
  128. package/src/orm/lazy-batch/belongs-to.ts +108 -108
  129. package/src/orm/lazy-batch/has-many.ts +69 -69
  130. package/src/orm/lazy-batch/has-one.ts +68 -68
  131. package/src/orm/lazy-batch/shared.ts +125 -125
  132. package/src/orm/orm-session.ts +620 -620
  133. package/src/orm/orm.ts +34 -34
  134. package/src/orm/pooled-executor-factory.ts +121 -121
  135. package/src/orm/query-logger.ts +40 -40
  136. package/src/orm/relation-change-processor.ts +420 -420
  137. package/src/orm/relations/belongs-to.ts +143 -143
  138. package/src/orm/relations/has-many.ts +204 -204
  139. package/src/orm/relations/has-one.ts +174 -174
  140. package/src/orm/relations/many-to-many.ts +288 -288
  141. package/src/orm/relations/morph-many.ts +156 -156
  142. package/src/orm/relations/morph-one.ts +151 -151
  143. package/src/orm/relations/morph-to.ts +162 -162
  144. package/src/orm/runtime-types.ts +92 -92
  145. package/src/orm/save-graph.ts +561 -561
  146. package/src/orm/transaction-runner.ts +24 -24
  147. package/src/orm/unit-of-work.ts +426 -426
  148. package/src/query/index.ts +69 -69
  149. package/src/query/target.ts +46 -46
  150. package/src/query-builder/column-selector.ts +81 -81
  151. package/src/query-builder/delete.ts +141 -141
  152. package/src/query-builder/insert-query-state.ts +149 -149
  153. package/src/query-builder/insert.ts +117 -117
  154. package/src/query-builder/query-ast-service.ts +287 -287
  155. package/src/query-builder/query-resolution.ts +78 -78
  156. package/src/query-builder/raw-column-parser.ts +38 -38
  157. package/src/query-builder/relation-filter-utils.ts +153 -153
  158. package/src/query-builder/relation-join-planner.ts +10 -10
  159. package/src/query-builder/relation-manager.ts +87 -87
  160. package/src/query-builder/relation-projection-helper.ts +102 -102
  161. package/src/query-builder/relation-types.ts +9 -9
  162. package/src/query-builder/relation-utils.ts +15 -15
  163. package/src/query-builder/select/cte-facet.ts +40 -40
  164. package/src/query-builder/select/from-facet.ts +80 -80
  165. package/src/query-builder/select/join-facet.ts +62 -62
  166. package/src/query-builder/select/predicate-facet.ts +104 -104
  167. package/src/query-builder/select/projection-facet.ts +70 -70
  168. package/src/query-builder/select/relation-facet.ts +81 -81
  169. package/src/query-builder/select/setop-facet.ts +36 -36
  170. package/src/query-builder/select-helpers.ts +1 -1
  171. package/src/query-builder/select-query-builder-deps.ts +130 -130
  172. package/src/query-builder/select-query-state.ts +207 -207
  173. package/src/query-builder/update.ts +151 -151
  174. package/src/schema/column-types.ts +322 -322
  175. package/src/schema/table-guards.ts +37 -37
  176. package/src/schema/table.ts +281 -281
  177. package/src/tree/index.ts +13 -13
  178. package/src/tree/nested-set-strategy.ts +545 -545
  179. package/src/tree/tree-decorator.ts +397 -397
  180. package/src/tree/tree-manager.ts +754 -754
  181. package/src/tree/tree-query.ts +427 -427
  182. package/src/tree/tree-types.ts +299 -299
@@ -5,55 +5,55 @@ import { SqlDialectBase } from '../base/sql-dialect.js';
5
5
  import { PostgresFunctionStrategy } from './functions.js';
6
6
  import { PostgresTableFunctionStrategy } from './table-functions.js';
7
7
  import { ProcedureCallNode } from '../../ast/procedure.js';
8
-
9
- /**
10
- * PostgreSQL dialect implementation
11
- */
12
- export class PostgresDialect extends SqlDialectBase {
13
- protected readonly dialect = 'postgres';
14
- /**
15
- * Creates a new PostgresDialect instance
16
- */
17
- public constructor() {
18
- super(new PostgresFunctionStrategy(), new PostgresTableFunctionStrategy());
19
- this.registerExpressionCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
20
- const left = this.compileOperand(node.left, ctx);
21
- const right = this.compileOperand(node.right, ctx);
22
- const op = node.operator === '^' ? '#' : node.operator;
23
- return `${left} ${op} ${right}`;
24
- });
25
- this.registerOperandCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
26
- const left = this.compileOperand(node.left, ctx);
27
- const right = this.compileOperand(node.right, ctx);
28
- const op = node.operator === '^' ? '#' : node.operator;
29
- return `(${left} ${op} ${right})`;
30
- });
31
- }
32
-
33
- /**
34
- * Quotes an identifier using PostgreSQL double-quote syntax
35
- * @param id - Identifier to quote
36
- * @returns Quoted identifier
37
- */
38
- quoteIdentifier(id: string): string {
39
- return `"${id}"`;
40
- }
41
-
42
- protected formatPlaceholder(index: number): string {
43
- return `$${index}`;
44
- }
45
-
46
- /**
47
- * Compiles JSON path expression using PostgreSQL syntax
48
- * @param node - JSON path node
49
- * @returns PostgreSQL JSON path expression
50
- */
51
- protected compileJsonPath(node: JsonPathNode): string {
52
- const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
53
- // Postgres uses col->>'path' for text extraction
54
- return `${col}->>'${node.path}'`;
55
- }
56
-
8
+
9
+ /**
10
+ * PostgreSQL dialect implementation
11
+ */
12
+ export class PostgresDialect extends SqlDialectBase {
13
+ protected readonly dialect = 'postgres';
14
+ /**
15
+ * Creates a new PostgresDialect instance
16
+ */
17
+ public constructor() {
18
+ super(new PostgresFunctionStrategy(), new PostgresTableFunctionStrategy());
19
+ this.registerExpressionCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
20
+ const left = this.compileOperand(node.left, ctx);
21
+ const right = this.compileOperand(node.right, ctx);
22
+ const op = node.operator === '^' ? '#' : node.operator;
23
+ return `${left} ${op} ${right}`;
24
+ });
25
+ this.registerOperandCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
26
+ const left = this.compileOperand(node.left, ctx);
27
+ const right = this.compileOperand(node.right, ctx);
28
+ const op = node.operator === '^' ? '#' : node.operator;
29
+ return `(${left} ${op} ${right})`;
30
+ });
31
+ }
32
+
33
+ /**
34
+ * Quotes an identifier using PostgreSQL double-quote syntax
35
+ * @param id - Identifier to quote
36
+ * @returns Quoted identifier
37
+ */
38
+ quoteIdentifier(id: string): string {
39
+ return `"${id}"`;
40
+ }
41
+
42
+ protected formatPlaceholder(index: number): string {
43
+ return `$${index}`;
44
+ }
45
+
46
+ /**
47
+ * Compiles JSON path expression using PostgreSQL syntax
48
+ * @param node - JSON path node
49
+ * @returns PostgreSQL JSON path expression
50
+ */
51
+ protected compileJsonPath(node: JsonPathNode): string {
52
+ const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
53
+ // Postgres uses col->>'path' for text extraction
54
+ return `${col}->>'${node.path}'`;
55
+ }
56
+
57
57
  protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
58
58
  void ctx;
59
59
  if (!returning || returning.length === 0) return '';
@@ -90,45 +90,45 @@ export class PostgresDialect extends SqlDialectBase {
90
90
  : '';
91
91
  return `${target} DO UPDATE SET ${assignments}${where}`;
92
92
  }
93
-
94
- supportsDmlReturningClause(): boolean {
95
- return true;
96
- }
97
-
98
- compileProcedureCall(ast: ProcedureCallNode): CompiledProcedureCall {
99
- const ctx = this.createCompilerContext();
100
- const qualifiedName = ast.ref.schema
101
- ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}`
102
- : this.quoteIdentifier(ast.ref.name);
103
-
104
- const args: string[] = [];
105
- for (const param of ast.params) {
106
- if (param.direction === 'out') continue;
107
- if (!param.value) {
108
- throw new Error(`Procedure parameter "${param.name}" requires a value for direction "${param.direction}".`);
109
- }
110
- args.push(this.compileOperand(param.value, ctx));
111
- }
112
-
113
- const outNames = ast.params
114
- .filter(param => param.direction === 'out' || param.direction === 'inout')
115
- .map(param => param.name);
116
-
117
- const rawSql = `CALL ${qualifiedName}(${args.join(', ')})`;
118
- return {
119
- sql: `${rawSql};`,
120
- params: [...ctx.params],
121
- outParams: {
122
- source: outNames.length ? 'firstResultSet' : 'none',
123
- names: outNames
124
- }
125
- };
126
- }
127
-
128
- /**
129
- * PostgreSQL requires unqualified column names in SET clause
130
- */
131
- protected compileSetTarget(column: ColumnNode, _table: TableNode): string {
132
- return this.quoteIdentifier(column.name);
133
- }
134
- }
93
+
94
+ supportsDmlReturningClause(): boolean {
95
+ return true;
96
+ }
97
+
98
+ compileProcedureCall(ast: ProcedureCallNode): CompiledProcedureCall {
99
+ const ctx = this.createCompilerContext();
100
+ const qualifiedName = ast.ref.schema
101
+ ? `${this.quoteIdentifier(ast.ref.schema)}.${this.quoteIdentifier(ast.ref.name)}`
102
+ : this.quoteIdentifier(ast.ref.name);
103
+
104
+ const args: string[] = [];
105
+ for (const param of ast.params) {
106
+ if (param.direction === 'out') continue;
107
+ if (!param.value) {
108
+ throw new Error(`Procedure parameter "${param.name}" requires a value for direction "${param.direction}".`);
109
+ }
110
+ args.push(this.compileOperand(param.value, ctx));
111
+ }
112
+
113
+ const outNames = ast.params
114
+ .filter(param => param.direction === 'out' || param.direction === 'inout')
115
+ .map(param => param.name);
116
+
117
+ const rawSql = `CALL ${qualifiedName}(${args.join(', ')})`;
118
+ return {
119
+ sql: `${rawSql};`,
120
+ params: [...ctx.params],
121
+ outParams: {
122
+ source: outNames.length ? 'firstResultSet' : 'none',
123
+ names: outNames
124
+ }
125
+ };
126
+ }
127
+
128
+ /**
129
+ * PostgreSQL requires unqualified column names in SET clause
130
+ */
131
+ protected compileSetTarget(column: ColumnNode, _table: TableNode): string {
132
+ return this.quoteIdentifier(column.name);
133
+ }
134
+ }
@@ -1,130 +1,130 @@
1
- import { StandardFunctionStrategy } from '../../functions/standard-strategy.js';
2
- import { LiteralNode } from '../../ast/expression.js';
3
-
4
- /**
5
- * SQLite specific function strategy.
6
- * Implements and overrides SQL function compilation rules for SQLite.
7
- */
8
- export class SqliteFunctionStrategy extends StandardFunctionStrategy {
9
- constructor() {
10
- super();
11
- this.registerOverrides();
12
- }
13
-
14
- private registerOverrides() {
15
- // Override Standard/Abstract definitions with SQLite specifics
16
-
17
- // Date/Time functions
18
- this.add('NOW', () => `datetime('now', 'localtime')`);
19
- this.add('CURRENT_DATE', () => `date('now', 'localtime')`);
20
- this.add('CURRENT_TIME', () => `time('now', 'localtime')`);
21
- this.add('UTC_NOW', () => `datetime('now')`);
22
-
23
- this.add('EXTRACT', ({ compiledArgs }) => {
24
- if (compiledArgs.length !== 2) throw new Error('EXTRACT expects 2 arguments (part, date)');
25
- const [part, date] = compiledArgs;
26
- // Map common parts to strftime format
27
- const partUpper = part.replace(/['"]/g, '').toUpperCase();
28
- const formatMap: Record<string, string> = {
29
- 'YEAR': '%Y', 'MONTH': '%m', 'DAY': '%d',
30
- 'HOUR': '%H', 'MINUTE': '%M', 'SECOND': '%S',
31
- 'DOW': '%w', 'WEEK': '%W'
32
- };
33
- const format = formatMap[partUpper] || '%Y';
34
- return `CAST(strftime('${format}', ${date}) AS INTEGER)`;
35
- });
36
-
37
- this.add('YEAR', ({ compiledArgs }) => {
38
- if (compiledArgs.length !== 1) throw new Error('YEAR expects 1 argument');
39
- return `CAST(strftime('%Y', ${compiledArgs[0]}) AS INTEGER)`;
40
- });
41
-
42
- this.add('MONTH', ({ compiledArgs }) => {
43
- if (compiledArgs.length !== 1) throw new Error('MONTH expects 1 argument');
44
- return `CAST(strftime('%m', ${compiledArgs[0]}) AS INTEGER)`;
45
- });
46
-
47
- this.add('DAY', ({ compiledArgs }) => {
48
- if (compiledArgs.length !== 1) throw new Error('DAY expects 1 argument');
49
- return `CAST(strftime('%d', ${compiledArgs[0]}) AS INTEGER)`;
50
- });
51
-
52
- this.add('DATE_ADD', ({ node, compiledArgs }) => {
53
- if (compiledArgs.length !== 3) throw new Error('DATE_ADD expects 3 arguments (date, interval, unit)');
54
- const [date, interval] = compiledArgs;
55
- const unitArg = node.args[2] as LiteralNode;
56
- const unitClean = String(unitArg.value).replace(/['"]/g, '').toLowerCase();
57
- return `datetime(${date}, '+' || ${interval} || ' ${unitClean}')`;
58
- });
59
-
60
- this.add('DATE_SUB', ({ node, compiledArgs }) => {
61
- if (compiledArgs.length !== 3) throw new Error('DATE_SUB expects 3 arguments (date, interval, unit)');
62
- const [date, interval] = compiledArgs;
63
- const unitArg = node.args[2] as LiteralNode;
64
- const unitClean = String(unitArg.value).replace(/['"]/g, '').toLowerCase();
65
- return `datetime(${date}, '-' || ${interval} || ' ${unitClean}')`;
66
- });
67
-
68
- this.add('DATE_DIFF', ({ compiledArgs }) => {
69
- if (compiledArgs.length !== 2) throw new Error('DATE_DIFF expects 2 arguments');
70
- const [date1, date2] = compiledArgs;
71
- return `CAST(julianday(${date1}) - julianday(${date2}) AS INTEGER)`;
72
- });
73
-
74
- this.add('DATE_FORMAT', ({ compiledArgs }) => {
75
- if (compiledArgs.length !== 2) throw new Error('DATE_FORMAT expects 2 arguments');
76
- const [date, format] = compiledArgs;
77
- return `strftime(${format}, ${date})`;
78
- });
79
-
80
- this.add('UNIX_TIMESTAMP', () => `CAST(strftime('%s', 'now') AS INTEGER)`);
81
-
82
- this.add('FROM_UNIXTIME', ({ compiledArgs }) => {
83
- if (compiledArgs.length !== 1) throw new Error('FROM_UNIXTIME expects 1 argument');
84
- return `datetime(${compiledArgs[0]}, 'unixepoch')`;
85
- });
86
-
87
- this.add('END_OF_MONTH', ({ compiledArgs }) => {
88
- if (compiledArgs.length !== 1) throw new Error('END_OF_MONTH expects 1 argument');
89
- return `date(${compiledArgs[0]}, 'start of month', '+1 month', '-1 day')`;
90
- });
91
-
92
- this.add('DAY_OF_WEEK', ({ compiledArgs }) => {
93
- if (compiledArgs.length !== 1) throw new Error('DAY_OF_WEEK expects 1 argument');
94
- return `CAST(strftime('%w', ${compiledArgs[0]}) AS INTEGER)`;
95
- });
96
-
97
- this.add('WEEK_OF_YEAR', ({ compiledArgs }) => {
98
- if (compiledArgs.length !== 1) throw new Error('WEEK_OF_YEAR expects 1 argument');
99
- return `CAST(strftime('%W', ${compiledArgs[0]}) AS INTEGER)`;
100
- });
101
-
102
- this.add('DATE_TRUNC', ({ node, compiledArgs }) => {
103
- if (compiledArgs.length !== 2) throw new Error('DATE_TRUNC expects 2 arguments (part, date)');
104
- const [, date] = compiledArgs;
105
- const partArg = node.args[0] as LiteralNode;
106
- const partClean = String(partArg.value).replace(/['"]/g, '').toLowerCase();
107
- // SQLite uses date modifiers
108
- if (partClean === 'year') {
109
- return `date(${date}, 'start of year')`;
110
- } else if (partClean === 'month') {
111
- return `date(${date}, 'start of month')`;
112
- } else if (partClean === 'day') {
113
- return `date(${date})`;
114
- }
115
- return `date(${date}, 'start of ${partClean}')`;
116
- });
117
-
118
- this.add('GROUP_CONCAT', ctx => {
119
- const arg = ctx.compiledArgs[0];
120
- const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
121
- const separator = ctx.compileOperand(separatorOperand);
122
- return `GROUP_CONCAT(${arg}, ${separator})`;
123
- });
124
-
125
- this.add('HOUR', ({ compiledArgs }) => `CAST(strftime('%H', ${compiledArgs[0]}) AS INTEGER)`);
126
- this.add('MINUTE', ({ compiledArgs }) => `CAST(strftime('%M', ${compiledArgs[0]}) AS INTEGER)`);
127
- this.add('SECOND', ({ compiledArgs }) => `CAST(strftime('%S', ${compiledArgs[0]}) AS INTEGER)`);
1
+ import { StandardFunctionStrategy } from '../../functions/standard-strategy.js';
2
+ import { LiteralNode } from '../../ast/expression.js';
3
+
4
+ /**
5
+ * SQLite specific function strategy.
6
+ * Implements and overrides SQL function compilation rules for SQLite.
7
+ */
8
+ export class SqliteFunctionStrategy extends StandardFunctionStrategy {
9
+ constructor() {
10
+ super();
11
+ this.registerOverrides();
12
+ }
13
+
14
+ private registerOverrides() {
15
+ // Override Standard/Abstract definitions with SQLite specifics
16
+
17
+ // Date/Time functions
18
+ this.add('NOW', () => `datetime('now', 'localtime')`);
19
+ this.add('CURRENT_DATE', () => `date('now', 'localtime')`);
20
+ this.add('CURRENT_TIME', () => `time('now', 'localtime')`);
21
+ this.add('UTC_NOW', () => `datetime('now')`);
22
+
23
+ this.add('EXTRACT', ({ compiledArgs }) => {
24
+ if (compiledArgs.length !== 2) throw new Error('EXTRACT expects 2 arguments (part, date)');
25
+ const [part, date] = compiledArgs;
26
+ // Map common parts to strftime format
27
+ const partUpper = part.replace(/['"]/g, '').toUpperCase();
28
+ const formatMap: Record<string, string> = {
29
+ 'YEAR': '%Y', 'MONTH': '%m', 'DAY': '%d',
30
+ 'HOUR': '%H', 'MINUTE': '%M', 'SECOND': '%S',
31
+ 'DOW': '%w', 'WEEK': '%W'
32
+ };
33
+ const format = formatMap[partUpper] || '%Y';
34
+ return `CAST(strftime('${format}', ${date}) AS INTEGER)`;
35
+ });
36
+
37
+ this.add('YEAR', ({ compiledArgs }) => {
38
+ if (compiledArgs.length !== 1) throw new Error('YEAR expects 1 argument');
39
+ return `CAST(strftime('%Y', ${compiledArgs[0]}) AS INTEGER)`;
40
+ });
41
+
42
+ this.add('MONTH', ({ compiledArgs }) => {
43
+ if (compiledArgs.length !== 1) throw new Error('MONTH expects 1 argument');
44
+ return `CAST(strftime('%m', ${compiledArgs[0]}) AS INTEGER)`;
45
+ });
46
+
47
+ this.add('DAY', ({ compiledArgs }) => {
48
+ if (compiledArgs.length !== 1) throw new Error('DAY expects 1 argument');
49
+ return `CAST(strftime('%d', ${compiledArgs[0]}) AS INTEGER)`;
50
+ });
51
+
52
+ this.add('DATE_ADD', ({ node, compiledArgs }) => {
53
+ if (compiledArgs.length !== 3) throw new Error('DATE_ADD expects 3 arguments (date, interval, unit)');
54
+ const [date, interval] = compiledArgs;
55
+ const unitArg = node.args[2] as LiteralNode;
56
+ const unitClean = String(unitArg.value).replace(/['"]/g, '').toLowerCase();
57
+ return `datetime(${date}, '+' || ${interval} || ' ${unitClean}')`;
58
+ });
59
+
60
+ this.add('DATE_SUB', ({ node, compiledArgs }) => {
61
+ if (compiledArgs.length !== 3) throw new Error('DATE_SUB expects 3 arguments (date, interval, unit)');
62
+ const [date, interval] = compiledArgs;
63
+ const unitArg = node.args[2] as LiteralNode;
64
+ const unitClean = String(unitArg.value).replace(/['"]/g, '').toLowerCase();
65
+ return `datetime(${date}, '-' || ${interval} || ' ${unitClean}')`;
66
+ });
67
+
68
+ this.add('DATE_DIFF', ({ compiledArgs }) => {
69
+ if (compiledArgs.length !== 2) throw new Error('DATE_DIFF expects 2 arguments');
70
+ const [date1, date2] = compiledArgs;
71
+ return `CAST(julianday(${date1}) - julianday(${date2}) AS INTEGER)`;
72
+ });
73
+
74
+ this.add('DATE_FORMAT', ({ compiledArgs }) => {
75
+ if (compiledArgs.length !== 2) throw new Error('DATE_FORMAT expects 2 arguments');
76
+ const [date, format] = compiledArgs;
77
+ return `strftime(${format}, ${date})`;
78
+ });
79
+
80
+ this.add('UNIX_TIMESTAMP', () => `CAST(strftime('%s', 'now') AS INTEGER)`);
81
+
82
+ this.add('FROM_UNIXTIME', ({ compiledArgs }) => {
83
+ if (compiledArgs.length !== 1) throw new Error('FROM_UNIXTIME expects 1 argument');
84
+ return `datetime(${compiledArgs[0]}, 'unixepoch')`;
85
+ });
86
+
87
+ this.add('END_OF_MONTH', ({ compiledArgs }) => {
88
+ if (compiledArgs.length !== 1) throw new Error('END_OF_MONTH expects 1 argument');
89
+ return `date(${compiledArgs[0]}, 'start of month', '+1 month', '-1 day')`;
90
+ });
91
+
92
+ this.add('DAY_OF_WEEK', ({ compiledArgs }) => {
93
+ if (compiledArgs.length !== 1) throw new Error('DAY_OF_WEEK expects 1 argument');
94
+ return `CAST(strftime('%w', ${compiledArgs[0]}) AS INTEGER)`;
95
+ });
96
+
97
+ this.add('WEEK_OF_YEAR', ({ compiledArgs }) => {
98
+ if (compiledArgs.length !== 1) throw new Error('WEEK_OF_YEAR expects 1 argument');
99
+ return `CAST(strftime('%W', ${compiledArgs[0]}) AS INTEGER)`;
100
+ });
101
+
102
+ this.add('DATE_TRUNC', ({ node, compiledArgs }) => {
103
+ if (compiledArgs.length !== 2) throw new Error('DATE_TRUNC expects 2 arguments (part, date)');
104
+ const [, date] = compiledArgs;
105
+ const partArg = node.args[0] as LiteralNode;
106
+ const partClean = String(partArg.value).replace(/['"]/g, '').toLowerCase();
107
+ // SQLite uses date modifiers
108
+ if (partClean === 'year') {
109
+ return `date(${date}, 'start of year')`;
110
+ } else if (partClean === 'month') {
111
+ return `date(${date}, 'start of month')`;
112
+ } else if (partClean === 'day') {
113
+ return `date(${date})`;
114
+ }
115
+ return `date(${date}, 'start of ${partClean}')`;
116
+ });
117
+
118
+ this.add('GROUP_CONCAT', ctx => {
119
+ const arg = ctx.compiledArgs[0];
120
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
121
+ const separator = ctx.compileOperand(separatorOperand);
122
+ return `GROUP_CONCAT(${arg}, ${separator})`;
123
+ });
124
+
125
+ this.add('HOUR', ({ compiledArgs }) => `CAST(strftime('%H', ${compiledArgs[0]}) AS INTEGER)`);
126
+ this.add('MINUTE', ({ compiledArgs }) => `CAST(strftime('%M', ${compiledArgs[0]}) AS INTEGER)`);
127
+ this.add('SECOND', ({ compiledArgs }) => `CAST(strftime('%S', ${compiledArgs[0]}) AS INTEGER)`);
128
128
  this.add('QUARTER', ({ compiledArgs }) => `((CAST(strftime('%m', ${compiledArgs[0]}) AS INTEGER) + 2) / 3)`);
129
129
 
130
130
  this.add('JSON_LENGTH', ({ compiledArgs }) => {
@@ -151,5 +151,5 @@ export class SqliteFunctionStrategy extends StandardFunctionStrategy {
151
151
  });
152
152
 
153
153
  this.add('CHR', ({ compiledArgs }) => `CHAR(${compiledArgs[0]})`);
154
- }
155
- }
154
+ }
155
+ }
@@ -4,67 +4,67 @@ import { InsertQueryNode, TableNode } from '../../ast/query.js';
4
4
  import { SqlDialectBase } from '../base/sql-dialect.js';
5
5
  import { SqliteFunctionStrategy } from './functions.js';
6
6
  import { ProcedureCallNode } from '../../ast/procedure.js';
7
-
8
- /**
9
- * SQLite dialect implementation
10
- */
11
- export class SqliteDialect extends SqlDialectBase {
12
- protected readonly dialect = 'sqlite';
13
- /**
14
- * Creates a new SqliteDialect instance
15
- */
16
- public constructor() {
17
- super(new SqliteFunctionStrategy());
18
- this.registerExpressionCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
19
- const left = this.compileOperand(node.left, ctx);
20
- const right = this.compileOperand(node.right, ctx);
21
- if (node.operator === '^') {
22
- return `(${left} | ${right}) & ~(${left} & ${right})`;
23
- }
24
- return `${left} ${node.operator} ${right}`;
25
- });
26
- this.registerOperandCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
27
- const left = this.compileOperand(node.left, ctx);
28
- const right = this.compileOperand(node.right, ctx);
29
- if (node.operator === '^') {
30
- return `((${left} | ${right}) & ~(${left} & ${right}))`;
31
- }
32
- return `(${left} ${node.operator} ${right})`;
33
- });
34
- }
35
-
36
- /**
37
- * Quotes an identifier using SQLite double-quote syntax
38
- * @param id - Identifier to quote
39
- * @returns Quoted identifier
40
- */
41
- quoteIdentifier(id: string): string {
42
- return `"${id}"`;
43
- }
44
-
45
- /**
46
- * Compiles JSON path expression using SQLite syntax
47
- * @param node - JSON path node
48
- * @returns SQLite JSON path expression
49
- */
50
- protected compileJsonPath(node: JsonPathNode): string {
51
- const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
52
- // SQLite uses json_extract(col, '$.path')
53
- return `json_extract(${col}, '${node.path}')`;
54
- }
55
-
56
- protected compileQualifiedColumn(column: ColumnNode, _table: TableNode): string {
57
- void _table;
58
- return this.quoteIdentifier(column.name);
59
- }
60
-
61
- protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
62
- void ctx;
63
- if (!returning || returning.length === 0) return '';
64
- const columns = this.formatReturningColumns(returning);
65
- return ` RETURNING ${columns}`;
66
- }
67
-
7
+
8
+ /**
9
+ * SQLite dialect implementation
10
+ */
11
+ export class SqliteDialect extends SqlDialectBase {
12
+ protected readonly dialect = 'sqlite';
13
+ /**
14
+ * Creates a new SqliteDialect instance
15
+ */
16
+ public constructor() {
17
+ super(new SqliteFunctionStrategy());
18
+ this.registerExpressionCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
19
+ const left = this.compileOperand(node.left, ctx);
20
+ const right = this.compileOperand(node.right, ctx);
21
+ if (node.operator === '^') {
22
+ return `(${left} | ${right}) & ~(${left} & ${right})`;
23
+ }
24
+ return `${left} ${node.operator} ${right}`;
25
+ });
26
+ this.registerOperandCompiler('BitwiseExpression', (node: BitwiseExpressionNode, ctx) => {
27
+ const left = this.compileOperand(node.left, ctx);
28
+ const right = this.compileOperand(node.right, ctx);
29
+ if (node.operator === '^') {
30
+ return `((${left} | ${right}) & ~(${left} & ${right}))`;
31
+ }
32
+ return `(${left} ${node.operator} ${right})`;
33
+ });
34
+ }
35
+
36
+ /**
37
+ * Quotes an identifier using SQLite double-quote syntax
38
+ * @param id - Identifier to quote
39
+ * @returns Quoted identifier
40
+ */
41
+ quoteIdentifier(id: string): string {
42
+ return `"${id}"`;
43
+ }
44
+
45
+ /**
46
+ * Compiles JSON path expression using SQLite syntax
47
+ * @param node - JSON path node
48
+ * @returns SQLite JSON path expression
49
+ */
50
+ protected compileJsonPath(node: JsonPathNode): string {
51
+ const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
52
+ // SQLite uses json_extract(col, '$.path')
53
+ return `json_extract(${col}, '${node.path}')`;
54
+ }
55
+
56
+ protected compileQualifiedColumn(column: ColumnNode, _table: TableNode): string {
57
+ void _table;
58
+ return this.quoteIdentifier(column.name);
59
+ }
60
+
61
+ protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
62
+ void ctx;
63
+ if (!returning || returning.length === 0) return '';
64
+ const columns = this.formatReturningColumns(returning);
65
+ return ` RETURNING ${columns}`;
66
+ }
67
+
68
68
  protected formatReturningColumns(returning: ColumnNode[]): string {
69
69
  return returning
70
70
  .map(column => {
@@ -104,9 +104,9 @@ export class SqliteDialect extends SqlDialectBase {
104
104
  supportsDmlReturningClause(): boolean {
105
105
  return true;
106
106
  }
107
-
108
- compileProcedureCall(_ast: ProcedureCallNode): CompiledProcedureCall {
109
- void _ast;
110
- throw new Error('Stored procedures are not supported by the SQLite dialect.');
111
- }
112
- }
107
+
108
+ compileProcedureCall(_ast: ProcedureCallNode): CompiledProcedureCall {
109
+ void _ast;
110
+ throw new Error('Stored procedures are not supported by the SQLite dialect.');
111
+ }
112
+ }
@@ -1,19 +1,19 @@
1
- import type { Dialect } from '../dialect/abstract.js';
2
- import type { SchemaDialect } from '../ddl/schema-dialect.js';
3
- import type { SchemaIntrospector } from '../ddl/schema-introspect.js';
4
-
5
- /**
6
- * Interface for database drivers.
7
- * A driver provides access to dialect-specific compilers and introspectors.
8
- */
9
- export interface DatabaseDriver {
10
- /** The name of the driver (e.g., "postgres", "mysql"). */
11
- readonly name: string;
12
-
13
- /** Creates a query compiler dialect. */
14
- createDialect(): Dialect;
15
- /** Creates a DDL/schema dialect. */
16
- createSchemaDialect(): SchemaDialect;
17
- /** Creates a schema introspector. */
18
- createIntrospector(): SchemaIntrospector;
19
- }
1
+ import type { Dialect } from '../dialect/abstract.js';
2
+ import type { SchemaDialect } from '../ddl/schema-dialect.js';
3
+ import type { SchemaIntrospector } from '../ddl/schema-introspect.js';
4
+
5
+ /**
6
+ * Interface for database drivers.
7
+ * A driver provides access to dialect-specific compilers and introspectors.
8
+ */
9
+ export interface DatabaseDriver {
10
+ /** The name of the driver (e.g., "postgres", "mysql"). */
11
+ readonly name: string;
12
+
13
+ /** Creates a query compiler dialect. */
14
+ createDialect(): Dialect;
15
+ /** Creates a DDL/schema dialect. */
16
+ createSchemaDialect(): SchemaDialect;
17
+ /** Creates a schema introspector. */
18
+ createIntrospector(): SchemaIntrospector;
19
+ }