metal-orm 1.0.13 → 1.0.15

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 (115) hide show
  1. package/README.md +75 -82
  2. package/dist/decorators/index.cjs +1600 -27
  3. package/dist/decorators/index.cjs.map +1 -1
  4. package/dist/decorators/index.d.cts +6 -2
  5. package/dist/decorators/index.d.ts +6 -2
  6. package/dist/decorators/index.js +1599 -27
  7. package/dist/decorators/index.js.map +1 -1
  8. package/dist/index.cjs +4608 -3429
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +511 -159
  11. package/dist/index.d.ts +511 -159
  12. package/dist/index.js +4526 -3415
  13. package/dist/index.js.map +1 -1
  14. package/dist/{select-CCp1oz9p.d.cts → select-Bkv8g8u_.d.cts} +193 -67
  15. package/dist/{select-CCp1oz9p.d.ts → select-Bkv8g8u_.d.ts} +193 -67
  16. package/package.json +1 -1
  17. package/src/codegen/typescript.ts +38 -35
  18. package/src/core/ast/adapters.ts +21 -0
  19. package/src/core/ast/aggregate-functions.ts +13 -13
  20. package/src/core/ast/builders.ts +56 -43
  21. package/src/core/ast/expression-builders.ts +34 -34
  22. package/src/core/ast/expression-nodes.ts +18 -16
  23. package/src/core/ast/expression-visitor.ts +122 -69
  24. package/src/core/ast/expression.ts +6 -4
  25. package/src/core/ast/join-metadata.ts +15 -0
  26. package/src/core/ast/join-node.ts +22 -20
  27. package/src/core/ast/join.ts +5 -5
  28. package/src/core/ast/query.ts +52 -88
  29. package/src/core/ast/types.ts +20 -0
  30. package/src/core/ast/window-functions.ts +55 -55
  31. package/src/core/ddl/dialects/base-schema-dialect.ts +20 -6
  32. package/src/core/ddl/dialects/mssql-schema-dialect.ts +32 -8
  33. package/src/core/ddl/dialects/mysql-schema-dialect.ts +21 -10
  34. package/src/core/ddl/dialects/postgres-schema-dialect.ts +52 -7
  35. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +23 -9
  36. package/src/core/ddl/introspect/catalogs/index.ts +1 -0
  37. package/src/core/ddl/introspect/catalogs/postgres.ts +143 -0
  38. package/src/core/ddl/introspect/context.ts +9 -0
  39. package/src/core/ddl/introspect/functions/postgres.ts +26 -0
  40. package/src/core/ddl/introspect/mssql.ts +149 -149
  41. package/src/core/ddl/introspect/mysql.ts +99 -99
  42. package/src/core/ddl/introspect/postgres.ts +245 -154
  43. package/src/core/ddl/introspect/registry.ts +26 -0
  44. package/src/core/ddl/introspect/run-select.ts +25 -0
  45. package/src/core/ddl/introspect/sqlite.ts +7 -7
  46. package/src/core/ddl/introspect/types.ts +23 -19
  47. package/src/core/ddl/introspect/utils.ts +1 -1
  48. package/src/core/ddl/naming-strategy.ts +10 -0
  49. package/src/core/ddl/schema-dialect.ts +41 -0
  50. package/src/core/ddl/schema-diff.ts +211 -179
  51. package/src/core/ddl/schema-generator.ts +16 -90
  52. package/src/core/ddl/schema-introspect.ts +25 -32
  53. package/src/core/ddl/schema-plan-executor.ts +17 -0
  54. package/src/core/ddl/schema-types.ts +46 -39
  55. package/src/core/ddl/sql-writing.ts +170 -0
  56. package/src/core/dialect/abstract.ts +144 -126
  57. package/src/core/dialect/base/cte-compiler.ts +33 -0
  58. package/src/core/dialect/base/function-table-formatter.ts +132 -0
  59. package/src/core/dialect/base/groupby-compiler.ts +21 -0
  60. package/src/core/dialect/base/join-compiler.ts +26 -0
  61. package/src/core/dialect/base/orderby-compiler.ts +21 -0
  62. package/src/core/dialect/base/pagination-strategy.ts +32 -0
  63. package/src/core/dialect/base/returning-strategy.ts +56 -0
  64. package/src/core/dialect/base/sql-dialect.ts +181 -204
  65. package/src/core/dialect/dialect-factory.ts +91 -0
  66. package/src/core/dialect/mssql/functions.ts +101 -0
  67. package/src/core/dialect/mssql/index.ts +128 -126
  68. package/src/core/dialect/mysql/functions.ts +101 -0
  69. package/src/core/dialect/mysql/index.ts +20 -18
  70. package/src/core/dialect/postgres/functions.ts +95 -0
  71. package/src/core/dialect/postgres/index.ts +30 -28
  72. package/src/core/dialect/sqlite/functions.ts +115 -0
  73. package/src/core/dialect/sqlite/index.ts +30 -28
  74. package/src/core/driver/database-driver.ts +11 -0
  75. package/src/core/driver/mssql-driver.ts +20 -0
  76. package/src/core/driver/mysql-driver.ts +20 -0
  77. package/src/core/driver/postgres-driver.ts +20 -0
  78. package/src/core/driver/sqlite-driver.ts +20 -0
  79. package/src/core/execution/db-executor.ts +63 -0
  80. package/src/core/execution/executors/mssql-executor.ts +39 -0
  81. package/src/core/execution/executors/mysql-executor.ts +47 -0
  82. package/src/core/execution/executors/postgres-executor.ts +32 -0
  83. package/src/core/execution/executors/sqlite-executor.ts +31 -0
  84. package/src/core/functions/datetime.ts +132 -0
  85. package/src/core/functions/numeric.ts +179 -0
  86. package/src/core/functions/standard-strategy.ts +47 -0
  87. package/src/core/functions/text.ts +147 -0
  88. package/src/core/functions/types.ts +18 -0
  89. package/src/core/hydration/types.ts +57 -0
  90. package/src/decorators/bootstrap.ts +10 -0
  91. package/src/decorators/relations.ts +15 -0
  92. package/src/index.ts +30 -19
  93. package/src/orm/entity-metadata.ts +7 -0
  94. package/src/orm/entity.ts +58 -27
  95. package/src/orm/hydration.ts +25 -17
  96. package/src/orm/lazy-batch.ts +46 -2
  97. package/src/orm/orm-context.ts +60 -60
  98. package/src/orm/query-logger.ts +1 -1
  99. package/src/orm/relation-change-processor.ts +43 -2
  100. package/src/orm/relations/has-one.ts +139 -0
  101. package/src/orm/transaction-runner.ts +1 -1
  102. package/src/orm/unit-of-work.ts +60 -60
  103. package/src/query-builder/delete.ts +22 -5
  104. package/src/query-builder/hydration-manager.ts +2 -1
  105. package/src/query-builder/hydration-planner.ts +8 -7
  106. package/src/query-builder/insert.ts +22 -5
  107. package/src/query-builder/relation-conditions.ts +9 -8
  108. package/src/query-builder/relation-service.ts +3 -2
  109. package/src/query-builder/select.ts +66 -61
  110. package/src/query-builder/update.ts +22 -5
  111. package/src/schema/column.ts +246 -246
  112. package/src/schema/relation.ts +35 -1
  113. package/src/schema/table.ts +28 -28
  114. package/src/schema/types.ts +41 -31
  115. package/src/orm/db-executor.ts +0 -11
@@ -0,0 +1,115 @@
1
+ import { StandardFunctionStrategy } from '../../functions/standard-strategy.js';
2
+ import { FunctionRenderContext } from '../../functions/types.js';
3
+ import { LiteralNode } from '../../ast/expression.js';
4
+
5
+ export class SqliteFunctionStrategy extends StandardFunctionStrategy {
6
+ constructor() {
7
+ super();
8
+ this.registerOverrides();
9
+ }
10
+
11
+ private registerOverrides() {
12
+ // Override Standard/Abstract definitions with SQLite specifics
13
+
14
+ // Date/Time functions
15
+ this.add('NOW', () => `datetime('now', 'localtime')`);
16
+ this.add('CURRENT_DATE', () => `date('now', 'localtime')`);
17
+ this.add('CURRENT_TIME', () => `time('now', 'localtime')`);
18
+ this.add('UTC_NOW', () => `datetime('now')`);
19
+
20
+ this.add('EXTRACT', ({ compiledArgs }) => {
21
+ if (compiledArgs.length !== 2) throw new Error('EXTRACT expects 2 arguments (part, date)');
22
+ const [part, date] = compiledArgs;
23
+ // Map common parts to strftime format
24
+ const partUpper = part.replace(/['"]/g, '').toUpperCase();
25
+ const formatMap: Record<string, string> = {
26
+ 'YEAR': '%Y', 'MONTH': '%m', 'DAY': '%d',
27
+ 'HOUR': '%H', 'MINUTE': '%M', 'SECOND': '%S',
28
+ 'DOW': '%w', 'WEEK': '%W'
29
+ };
30
+ const format = formatMap[partUpper] || '%Y';
31
+ return `CAST(strftime('${format}', ${date}) AS INTEGER)`;
32
+ });
33
+
34
+ this.add('YEAR', ({ compiledArgs }) => {
35
+ if (compiledArgs.length !== 1) throw new Error('YEAR expects 1 argument');
36
+ return `CAST(strftime('%Y', ${compiledArgs[0]}) AS INTEGER)`;
37
+ });
38
+
39
+ this.add('MONTH', ({ compiledArgs }) => {
40
+ if (compiledArgs.length !== 1) throw new Error('MONTH expects 1 argument');
41
+ return `CAST(strftime('%m', ${compiledArgs[0]}) AS INTEGER)`;
42
+ });
43
+
44
+ this.add('DAY', ({ compiledArgs }) => {
45
+ if (compiledArgs.length !== 1) throw new Error('DAY expects 1 argument');
46
+ return `CAST(strftime('%d', ${compiledArgs[0]}) AS INTEGER)`;
47
+ });
48
+
49
+ this.add('DATE_ADD', ({ node, compiledArgs }) => {
50
+ if (compiledArgs.length !== 3) throw new Error('DATE_ADD expects 3 arguments (date, interval, unit)');
51
+ const [date, interval] = compiledArgs;
52
+ const unitArg = node.args[2] as LiteralNode;
53
+ const unitClean = String(unitArg.value).replace(/['"]/g, '').toLowerCase();
54
+ return `datetime(${date}, '+' || ${interval} || ' ${unitClean}')`;
55
+ });
56
+
57
+ this.add('DATE_SUB', ({ node, compiledArgs }) => {
58
+ if (compiledArgs.length !== 3) throw new Error('DATE_SUB expects 3 arguments (date, interval, unit)');
59
+ const [date, interval] = compiledArgs;
60
+ const unitArg = node.args[2] as LiteralNode;
61
+ const unitClean = String(unitArg.value).replace(/['"]/g, '').toLowerCase();
62
+ return `datetime(${date}, '-' || ${interval} || ' ${unitClean}')`;
63
+ });
64
+
65
+ this.add('DATE_DIFF', ({ compiledArgs }) => {
66
+ if (compiledArgs.length !== 2) throw new Error('DATE_DIFF expects 2 arguments');
67
+ const [date1, date2] = compiledArgs;
68
+ return `CAST(julianday(${date1}) - julianday(${date2}) AS INTEGER)`;
69
+ });
70
+
71
+ this.add('DATE_FORMAT', ({ compiledArgs }) => {
72
+ if (compiledArgs.length !== 2) throw new Error('DATE_FORMAT expects 2 arguments');
73
+ const [date, format] = compiledArgs;
74
+ return `strftime(${format}, ${date})`;
75
+ });
76
+
77
+ this.add('UNIX_TIMESTAMP', () => `CAST(strftime('%s', 'now') AS INTEGER)`);
78
+
79
+ this.add('FROM_UNIXTIME', ({ compiledArgs }) => {
80
+ if (compiledArgs.length !== 1) throw new Error('FROM_UNIXTIME expects 1 argument');
81
+ return `datetime(${compiledArgs[0]}, 'unixepoch')`;
82
+ });
83
+
84
+ this.add('END_OF_MONTH', ({ compiledArgs }) => {
85
+ if (compiledArgs.length !== 1) throw new Error('END_OF_MONTH expects 1 argument');
86
+ return `date(${compiledArgs[0]}, 'start of month', '+1 month', '-1 day')`;
87
+ });
88
+
89
+ this.add('DAY_OF_WEEK', ({ compiledArgs }) => {
90
+ if (compiledArgs.length !== 1) throw new Error('DAY_OF_WEEK expects 1 argument');
91
+ return `CAST(strftime('%w', ${compiledArgs[0]}) AS INTEGER)`;
92
+ });
93
+
94
+ this.add('WEEK_OF_YEAR', ({ compiledArgs }) => {
95
+ if (compiledArgs.length !== 1) throw new Error('WEEK_OF_YEAR expects 1 argument');
96
+ return `CAST(strftime('%W', ${compiledArgs[0]}) AS INTEGER)`;
97
+ });
98
+
99
+ this.add('DATE_TRUNC', ({ node, compiledArgs }) => {
100
+ if (compiledArgs.length !== 2) throw new Error('DATE_TRUNC expects 2 arguments (part, date)');
101
+ const [, date] = compiledArgs;
102
+ const partArg = node.args[0] as LiteralNode;
103
+ const partClean = String(partArg.value).replace(/['"]/g, '').toLowerCase();
104
+ // SQLite uses date modifiers
105
+ if (partClean === 'year') {
106
+ return `date(${date}, 'start of year')`;
107
+ } else if (partClean === 'month') {
108
+ return `date(${date}, 'start of month')`;
109
+ } else if (partClean === 'day') {
110
+ return `date(${date})`;
111
+ }
112
+ return `date(${date}, 'start of ${partClean}')`;
113
+ });
114
+ }
115
+ }
@@ -1,16 +1,18 @@
1
- import { CompilerContext } from '../abstract.js';
2
- import { JsonPathNode, ColumnNode } from '../../ast/expression.js';
3
- import { SqlDialectBase } from '../base/sql-dialect.js';
4
-
5
- /**
6
- * SQLite dialect implementation
7
- */
8
- export class SqliteDialect extends SqlDialectBase {
9
- /**
10
- * Creates a new SqliteDialect instance
11
- */
12
- public constructor() {
13
- super();
1
+ import { CompilerContext } from '../abstract.js';
2
+ import { JsonPathNode, ColumnNode } from '../../ast/expression.js';
3
+ import { SqlDialectBase } from '../base/sql-dialect.js';
4
+ import { SqliteFunctionStrategy } from './functions.js';
5
+
6
+ /**
7
+ * SQLite dialect implementation
8
+ */
9
+ export class SqliteDialect extends SqlDialectBase {
10
+ protected readonly dialect = 'sqlite';
11
+ /**
12
+ * Creates a new SqliteDialect instance
13
+ */
14
+ public constructor() {
15
+ super(new SqliteFunctionStrategy());
14
16
  }
15
17
 
16
18
  /**
@@ -27,19 +29,19 @@ export class SqliteDialect extends SqlDialectBase {
27
29
  * @param node - JSON path node
28
30
  * @returns SQLite JSON path expression
29
31
  */
30
- protected compileJsonPath(node: JsonPathNode): string {
31
- const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
32
- // SQLite uses json_extract(col, '$.path')
33
- return `json_extract(${col}, '${node.path}')`;
34
- }
32
+ protected compileJsonPath(node: JsonPathNode): string {
33
+ const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
34
+ // SQLite uses json_extract(col, '$.path')
35
+ return `json_extract(${col}, '${node.path}')`;
36
+ }
35
37
 
36
- protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
37
- if (!returning || returning.length === 0) return '';
38
- const columns = this.formatReturningColumns(returning);
39
- return ` RETURNING ${columns}`;
40
- }
41
-
42
- supportsReturning(): boolean {
43
- return true;
44
- }
45
- }
38
+ protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
39
+ if (!returning || returning.length === 0) return '';
40
+ const columns = this.formatReturningColumns(returning);
41
+ return ` RETURNING ${columns}`;
42
+ }
43
+
44
+ supportsReturning(): boolean {
45
+ return true;
46
+ }
47
+ }
@@ -0,0 +1,11 @@
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
+ export interface DatabaseDriver {
6
+ readonly name: string; // e.g. "postgres"
7
+
8
+ createDialect(): Dialect;
9
+ createSchemaDialect(): SchemaDialect;
10
+ createIntrospector(): SchemaIntrospector;
11
+ }
@@ -0,0 +1,20 @@
1
+ import { DatabaseDriver } from './database-driver.js';
2
+ import { SqlServerDialect } from '../dialect/mssql/index.js';
3
+ import { MSSqlSchemaDialect } from '../ddl/dialects/mssql-schema-dialect.js';
4
+ import { mssqlIntrospector } from '../ddl/introspect/mssql.js';
5
+
6
+ export class MssqlDriver implements DatabaseDriver {
7
+ readonly name = 'mssql';
8
+
9
+ createDialect() {
10
+ return new SqlServerDialect();
11
+ }
12
+
13
+ createSchemaDialect() {
14
+ return new MSSqlSchemaDialect();
15
+ }
16
+
17
+ createIntrospector() {
18
+ return mssqlIntrospector;
19
+ }
20
+ }
@@ -0,0 +1,20 @@
1
+ import { DatabaseDriver } from './database-driver.js';
2
+ import { MySqlDialect } from '../dialect/mysql/index.js';
3
+ import { MySqlSchemaDialect } from '../ddl/dialects/mysql-schema-dialect.js';
4
+ import { mysqlIntrospector } from '../ddl/introspect/mysql.js';
5
+
6
+ export class MySqlDriver implements DatabaseDriver {
7
+ readonly name = 'mysql';
8
+
9
+ createDialect() {
10
+ return new MySqlDialect();
11
+ }
12
+
13
+ createSchemaDialect() {
14
+ return new MySqlSchemaDialect();
15
+ }
16
+
17
+ createIntrospector() {
18
+ return mysqlIntrospector;
19
+ }
20
+ }
@@ -0,0 +1,20 @@
1
+ import { DatabaseDriver } from './database-driver.js';
2
+ import { PostgresDialect } from '../dialect/postgres/index.js';
3
+ import { PostgresSchemaDialect } from '../ddl/dialects/postgres-schema-dialect.js';
4
+ import { postgresIntrospector } from '../ddl/introspect/postgres.js';
5
+
6
+ export class PostgresDriver implements DatabaseDriver {
7
+ readonly name = 'postgres';
8
+
9
+ createDialect() {
10
+ return new PostgresDialect();
11
+ }
12
+
13
+ createSchemaDialect() {
14
+ return new PostgresSchemaDialect();
15
+ }
16
+
17
+ createIntrospector() {
18
+ return postgresIntrospector;
19
+ }
20
+ }
@@ -0,0 +1,20 @@
1
+ import { DatabaseDriver } from './database-driver.js';
2
+ import { SqliteDialect } from '../dialect/sqlite/index.js';
3
+ import { SQLiteSchemaDialect } from '../ddl/dialects/sqlite-schema-dialect.js';
4
+ import { sqliteIntrospector } from '../ddl/introspect/sqlite.js';
5
+
6
+ export class SqliteDriver implements DatabaseDriver {
7
+ readonly name = 'sqlite';
8
+
9
+ createDialect() {
10
+ return new SqliteDialect();
11
+ }
12
+
13
+ createSchemaDialect() {
14
+ return new SQLiteSchemaDialect();
15
+ }
16
+
17
+ createIntrospector() {
18
+ return sqliteIntrospector;
19
+ }
20
+ }
@@ -0,0 +1,63 @@
1
+ // src/core/execution/db-executor.ts
2
+
3
+ // low-level canonical shape
4
+ export type QueryResult = {
5
+ columns: string[];
6
+ values: unknown[][];
7
+ };
8
+
9
+ export interface DbExecutor {
10
+ executeSql(sql: string, params?: unknown[]): Promise<QueryResult[]>;
11
+
12
+ beginTransaction?(): Promise<void>;
13
+ commitTransaction?(): Promise<void>;
14
+ rollbackTransaction?(): Promise<void>;
15
+ }
16
+
17
+ // --- helpers ---
18
+
19
+ /**
20
+ * Convert an array of row objects into a QueryResult.
21
+ */
22
+ export function rowsToQueryResult(
23
+ rows: Array<Record<string, unknown>>
24
+ ): QueryResult {
25
+ if (rows.length === 0) {
26
+ return { columns: [], values: [] };
27
+ }
28
+
29
+ const columns = Object.keys(rows[0]);
30
+ const values = rows.map(row => columns.map(c => (row as any)[c]));
31
+ return { columns, values };
32
+ }
33
+
34
+ /**
35
+ * Minimal contract that most SQL clients can implement.
36
+ */
37
+ export interface SimpleQueryRunner {
38
+ query(
39
+ sql: string,
40
+ params?: unknown[]
41
+ ): Promise<Array<Record<string, unknown>>>;
42
+ beginTransaction?(): Promise<void>;
43
+ commitTransaction?(): Promise<void>;
44
+ rollbackTransaction?(): Promise<void>;
45
+ }
46
+
47
+ /**
48
+ * Generic factory: turn any SimpleQueryRunner into a DbExecutor.
49
+ */
50
+ export function createExecutorFromQueryRunner(
51
+ runner: SimpleQueryRunner
52
+ ): DbExecutor {
53
+ return {
54
+ async executeSql(sql, params) {
55
+ const rows = await runner.query(sql, params);
56
+ const result = rowsToQueryResult(rows);
57
+ return [result];
58
+ },
59
+ beginTransaction: runner.beginTransaction?.bind(runner),
60
+ commitTransaction: runner.commitTransaction?.bind(runner),
61
+ rollbackTransaction: runner.rollbackTransaction?.bind(runner),
62
+ };
63
+ }
@@ -0,0 +1,39 @@
1
+ // src/core/execution/executors/mssql-executor.ts
2
+ import {
3
+ DbExecutor,
4
+ rowsToQueryResult
5
+ } from '../db-executor.js';
6
+
7
+ export interface MssqlClientLike {
8
+ query(
9
+ sql: string,
10
+ params?: unknown[]
11
+ ): Promise<{ recordset: Array<Record<string, unknown>> }>;
12
+ beginTransaction?(): Promise<void>;
13
+ commit?(): Promise<void>;
14
+ rollback?(): Promise<void>;
15
+ }
16
+
17
+ export function createMssqlExecutor(
18
+ client: MssqlClientLike
19
+ ): DbExecutor {
20
+ return {
21
+ async executeSql(sql, params) {
22
+ const { recordset } = await client.query(sql, params);
23
+ const result = rowsToQueryResult(recordset ?? []);
24
+ return [result];
25
+ },
26
+ async beginTransaction() {
27
+ if (!client.beginTransaction) return;
28
+ await client.beginTransaction();
29
+ },
30
+ async commitTransaction() {
31
+ if (!client.commit) return;
32
+ await client.commit();
33
+ },
34
+ async rollbackTransaction() {
35
+ if (!client.rollback) return;
36
+ await client.rollback();
37
+ },
38
+ };
39
+ }
@@ -0,0 +1,47 @@
1
+ // src/core/execution/executors/mysql-executor.ts
2
+ import {
3
+ DbExecutor,
4
+ rowsToQueryResult
5
+ } from '../db-executor.js';
6
+
7
+ export interface MysqlClientLike {
8
+ query(
9
+ sql: string,
10
+ params?: unknown[]
11
+ ): Promise<[any, any?]>; // rows, metadata
12
+ beginTransaction?(): Promise<void>;
13
+ commit?(): Promise<void>;
14
+ rollback?(): Promise<void>;
15
+ }
16
+
17
+ export function createMysqlExecutor(
18
+ client: MysqlClientLike
19
+ ): DbExecutor {
20
+ return {
21
+ async executeSql(sql, params) {
22
+ const [rows] = await client.query(sql, params as any[]);
23
+
24
+ if (!Array.isArray(rows)) {
25
+ // e.g. insert/update returning only headers, treat as no rows
26
+ return [{ columns: [], values: [] }];
27
+ }
28
+
29
+ const result = rowsToQueryResult(
30
+ rows as Array<Record<string, unknown>>
31
+ );
32
+ return [result];
33
+ },
34
+ async beginTransaction() {
35
+ if (!client.beginTransaction) return;
36
+ await client.beginTransaction();
37
+ },
38
+ async commitTransaction() {
39
+ if (!client.commit) return;
40
+ await client.commit();
41
+ },
42
+ async rollbackTransaction() {
43
+ if (!client.rollback) return;
44
+ await client.rollback();
45
+ },
46
+ };
47
+ }
@@ -0,0 +1,32 @@
1
+ // src/core/execution/executors/postgres-executor.ts
2
+ import {
3
+ DbExecutor,
4
+ createExecutorFromQueryRunner
5
+ } from '../db-executor.js';
6
+
7
+ export interface PostgresClientLike {
8
+ query(
9
+ text: string,
10
+ params?: unknown[]
11
+ ): Promise<{ rows: Array<Record<string, unknown>> }>;
12
+ }
13
+
14
+ export function createPostgresExecutor(
15
+ client: PostgresClientLike
16
+ ): DbExecutor {
17
+ return createExecutorFromQueryRunner({
18
+ async query(sql, params) {
19
+ const { rows } = await client.query(sql, params as any[]);
20
+ return rows;
21
+ },
22
+ async beginTransaction() {
23
+ await client.query('BEGIN');
24
+ },
25
+ async commitTransaction() {
26
+ await client.query('COMMIT');
27
+ },
28
+ async rollbackTransaction() {
29
+ await client.query('ROLLBACK');
30
+ },
31
+ });
32
+ }
@@ -0,0 +1,31 @@
1
+ // src/core/execution/executors/sqlite-executor.ts
2
+ import {
3
+ DbExecutor,
4
+ rowsToQueryResult
5
+ } from '../db-executor.js';
6
+
7
+ export interface SqliteClientLike {
8
+ all(
9
+ sql: string,
10
+ params?: unknown[]
11
+ ): Promise<Array<Record<string, unknown>>>;
12
+ run?(sql: string, params?: unknown[]): Promise<unknown>;
13
+ beginTransaction?(): Promise<void>;
14
+ commitTransaction?(): Promise<void>;
15
+ rollbackTransaction?(): Promise<void>;
16
+ }
17
+
18
+ export function createSqliteExecutor(
19
+ client: SqliteClientLike
20
+ ): DbExecutor {
21
+ return {
22
+ async executeSql(sql, params) {
23
+ const rows = await client.all(sql, params);
24
+ const result = rowsToQueryResult(rows);
25
+ return [result];
26
+ },
27
+ beginTransaction: client.beginTransaction?.bind(client),
28
+ commitTransaction: client.commitTransaction?.bind(client),
29
+ rollbackTransaction: client.rollbackTransaction?.bind(client),
30
+ };
31
+ }
@@ -0,0 +1,132 @@
1
+ // Pure AST Builders - No Dialect Logic Here!
2
+
3
+ import { ColumnDef } from '../../schema/column.js';
4
+ import { columnOperand, valueToOperand } from '../ast/expression-builders.js';
5
+ import { FunctionNode, OperandNode, isOperandNode } from '../ast/expression.js';
6
+
7
+ type OperandInput = OperandNode | ColumnDef | string | number | boolean | null;
8
+
9
+ const isColumnDef = (val: any): val is ColumnDef => !!val && typeof val === 'object' && 'type' in val && 'name' in val;
10
+
11
+ const toOperand = (input: OperandInput): OperandNode => {
12
+ if (isOperandNode(input)) return input;
13
+ if (isColumnDef(input)) return columnOperand(input);
14
+ return valueToOperand(input as any);
15
+ };
16
+
17
+ const fn = (key: string, args: OperandInput[]): FunctionNode => ({
18
+ type: 'Function',
19
+ name: key,
20
+ args: args.map(toOperand)
21
+ });
22
+
23
+ // ----------------------
24
+ // Helper Functions
25
+ // ----------------------
26
+
27
+ /**
28
+ * Helper: NOW() - Returns the current local date and time
29
+ */
30
+ export const now = (): FunctionNode => fn('NOW', []);
31
+
32
+ /**
33
+ * Helper: CURRENT_DATE - Returns only the current date (no time)
34
+ */
35
+ export const currentDate = (): FunctionNode => fn('CURRENT_DATE', []);
36
+
37
+ /**
38
+ * Helper: CURRENT_TIME - Returns only the current time
39
+ */
40
+ export const currentTime = (): FunctionNode => fn('CURRENT_TIME', []);
41
+
42
+ /**
43
+ * Helper: UTC_NOW() - Returns current UTC/GMT date and time
44
+ */
45
+ export const utcNow = (): FunctionNode => fn('UTC_NOW', []);
46
+
47
+ /**
48
+ * Helper: EXTRACT(part FROM date) - Extracts a part (year, month, day, hour, etc.) from a date
49
+ * @param part - The date part to extract (e.g., 'YEAR', 'MONTH', 'DAY', 'HOUR', 'MINUTE', 'SECOND')
50
+ * @param date - The date/datetime value
51
+ */
52
+ export const extract = (part: OperandInput, date: OperandInput): FunctionNode => fn('EXTRACT', [part, date]);
53
+
54
+ /**
55
+ * Helper: YEAR(date) - Extracts the year from a date
56
+ */
57
+ export const year = (date: OperandInput): FunctionNode => fn('YEAR', [date]);
58
+
59
+ /**
60
+ * Helper: MONTH(date) - Extracts the month from a date
61
+ */
62
+ export const month = (date: OperandInput): FunctionNode => fn('MONTH', [date]);
63
+
64
+ /**
65
+ * Helper: DAY(date) - Extracts the day from a date
66
+ */
67
+ export const day = (date: OperandInput): FunctionNode => fn('DAY', [date]);
68
+
69
+ /**
70
+ * Helper: DATE_ADD(date, interval, unit) - Adds a specific time interval to a date
71
+ * @param date - The date/datetime value
72
+ * @param interval - The number of units to add
73
+ * @param unit - The unit type (e.g., 'DAY', 'MONTH', 'YEAR', 'HOUR', 'MINUTE', 'SECOND')
74
+ */
75
+ export const dateAdd = (date: OperandInput, interval: OperandInput, unit: OperandInput): FunctionNode =>
76
+ fn('DATE_ADD', [date, interval, unit]);
77
+
78
+ /**
79
+ * Helper: DATE_SUB(date, interval, unit) - Subtracts a specific time interval from a date
80
+ * @param date - The date/datetime value
81
+ * @param interval - The number of units to subtract
82
+ * @param unit - The unit type (e.g., 'DAY', 'MONTH', 'YEAR', 'HOUR', 'MINUTE', 'SECOND')
83
+ */
84
+ export const dateSub = (date: OperandInput, interval: OperandInput, unit: OperandInput): FunctionNode =>
85
+ fn('DATE_SUB', [date, interval, unit]);
86
+
87
+ /**
88
+ * Helper: DATE_DIFF(date1, date2) - Returns the difference between two dates in days
89
+ * @param date1 - The end date
90
+ * @param date2 - The start date
91
+ */
92
+ export const dateDiff = (date1: OperandInput, date2: OperandInput): FunctionNode => fn('DATE_DIFF', [date1, date2]);
93
+
94
+ /**
95
+ * Helper: DATE_FORMAT(date, format) - Converts a date to a formatted string
96
+ * @param date - The date/datetime value
97
+ * @param format - The format string (dialect-specific)
98
+ */
99
+ export const dateFormat = (date: OperandInput, format: OperandInput): FunctionNode => fn('DATE_FORMAT', [date, format]);
100
+
101
+ /**
102
+ * Helper: UNIX_TIMESTAMP() - Returns the current Unix epoch (seconds since 1970)
103
+ */
104
+ export const unixTimestamp = (): FunctionNode => fn('UNIX_TIMESTAMP', []);
105
+
106
+ /**
107
+ * Helper: FROM_UNIXTIME(timestamp) - Converts Unix epoch seconds to a date
108
+ * @param timestamp - Unix timestamp in seconds
109
+ */
110
+ export const fromUnixTime = (timestamp: OperandInput): FunctionNode => fn('FROM_UNIXTIME', [timestamp]);
111
+
112
+ /**
113
+ * Helper: END_OF_MONTH(date) - Returns the last day of the month for a given date
114
+ */
115
+ export const endOfMonth = (date: OperandInput): FunctionNode => fn('END_OF_MONTH', [date]);
116
+
117
+ /**
118
+ * Helper: DAY_OF_WEEK(date) - Returns the index of the weekday
119
+ */
120
+ export const dayOfWeek = (date: OperandInput): FunctionNode => fn('DAY_OF_WEEK', [date]);
121
+
122
+ /**
123
+ * Helper: WEEK_OF_YEAR(date) - Returns the week number of the year
124
+ */
125
+ export const weekOfYear = (date: OperandInput): FunctionNode => fn('WEEK_OF_YEAR', [date]);
126
+
127
+ /**
128
+ * Helper: DATE_TRUNC(part, date) - Resets date precision (e.g., first day of the month/year)
129
+ * @param part - The truncation precision (e.g., 'YEAR', 'MONTH', 'DAY')
130
+ * @param date - The date/datetime value
131
+ */
132
+ export const dateTrunc = (part: OperandInput, date: OperandInput): FunctionNode => fn('DATE_TRUNC', [part, date]);