metal-orm 1.0.42 → 1.0.44
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.
- package/README.md +195 -37
- package/dist/index.cjs +1014 -538
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1267 -371
- package/dist/index.d.ts +1267 -371
- package/dist/index.js +1012 -536
- package/dist/index.js.map +1 -1
- package/package.json +8 -2
- package/scripts/run-eslint.mjs +34 -0
- package/src/codegen/typescript.ts +32 -15
- package/src/core/ast/adapters.ts +8 -2
- package/src/core/ast/builders.ts +105 -76
- package/src/core/ast/expression-builders.ts +430 -392
- package/src/core/ast/expression-nodes.ts +14 -5
- package/src/core/ast/expression-visitor.ts +56 -14
- package/src/core/ast/helpers.ts +23 -0
- package/src/core/ast/join-node.ts +18 -2
- package/src/core/ast/query.ts +6 -6
- package/src/core/ast/window-functions.ts +10 -2
- package/src/core/ddl/dialects/base-schema-dialect.ts +37 -4
- package/src/core/ddl/dialects/index.ts +1 -0
- package/src/core/ddl/dialects/mssql-schema-dialect.ts +5 -0
- package/src/core/ddl/dialects/mysql-schema-dialect.ts +3 -0
- package/src/core/ddl/dialects/postgres-schema-dialect.ts +14 -1
- package/src/core/ddl/dialects/render-reference.test.ts +69 -0
- package/src/core/ddl/dialects/sqlite-schema-dialect.ts +10 -0
- package/src/core/ddl/introspect/catalogs/index.ts +1 -0
- package/src/core/ddl/introspect/catalogs/postgres.ts +2 -0
- package/src/core/ddl/introspect/context.ts +6 -0
- package/src/core/ddl/introspect/functions/postgres.ts +13 -0
- package/src/core/ddl/introspect/mssql.ts +53 -8
- package/src/core/ddl/introspect/mysql.ts +32 -6
- package/src/core/ddl/introspect/postgres.ts +102 -34
- package/src/core/ddl/introspect/registry.ts +14 -0
- package/src/core/ddl/introspect/run-select.ts +19 -4
- package/src/core/ddl/introspect/sqlite.ts +78 -11
- package/src/core/ddl/introspect/types.ts +0 -1
- package/src/core/ddl/introspect/utils.ts +21 -3
- package/src/core/ddl/naming-strategy.ts +6 -0
- package/src/core/ddl/schema-dialect.ts +20 -6
- package/src/core/ddl/schema-diff.ts +22 -0
- package/src/core/ddl/schema-generator.ts +26 -12
- package/src/core/ddl/schema-plan-executor.ts +6 -0
- package/src/core/ddl/schema-types.ts +6 -0
- package/src/core/ddl/sql-writing.ts +4 -4
- package/src/core/dialect/abstract.ts +19 -7
- package/src/core/dialect/base/function-table-formatter.ts +3 -2
- package/src/core/dialect/base/join-compiler.ts +5 -3
- package/src/core/dialect/base/returning-strategy.ts +1 -0
- package/src/core/dialect/base/sql-dialect.ts +3 -3
- package/src/core/dialect/mssql/functions.ts +24 -25
- package/src/core/dialect/mssql/index.ts +1 -4
- package/src/core/dialect/mysql/functions.ts +0 -1
- package/src/core/dialect/postgres/functions.ts +33 -34
- package/src/core/dialect/postgres/index.ts +1 -0
- package/src/core/dialect/sqlite/functions.ts +18 -19
- package/src/core/dialect/sqlite/index.ts +2 -0
- package/src/core/execution/db-executor.ts +1 -1
- package/src/core/execution/executors/mysql-executor.ts +2 -2
- package/src/core/execution/executors/postgres-executor.ts +1 -1
- package/src/core/execution/pooling/pool.ts +12 -5
- package/src/core/functions/datetime.ts +58 -34
- package/src/core/functions/numeric.ts +96 -31
- package/src/core/functions/standard-strategy.ts +35 -0
- package/src/core/functions/text.ts +84 -23
- package/src/core/functions/types.ts +23 -8
- package/src/decorators/bootstrap.ts +42 -11
- package/src/decorators/column.ts +20 -11
- package/src/decorators/decorator-metadata.ts +30 -9
- package/src/decorators/entity.ts +29 -5
- package/src/decorators/index.ts +3 -0
- package/src/decorators/relations.ts +34 -11
- package/src/orm/als.ts +34 -9
- package/src/orm/entity-context.ts +62 -8
- package/src/orm/entity-meta.ts +8 -8
- package/src/orm/entity-metadata.ts +131 -16
- package/src/orm/entity.ts +28 -29
- package/src/orm/execute.ts +19 -4
- package/src/orm/hydration.ts +42 -39
- package/src/orm/identity-map.ts +1 -1
- package/src/orm/lazy-batch.ts +74 -104
- package/src/orm/orm-session.ts +24 -23
- package/src/orm/orm.ts +2 -5
- package/src/orm/relation-change-processor.ts +12 -11
- package/src/orm/relations/belongs-to.ts +11 -11
- package/src/orm/relations/has-many.ts +54 -10
- package/src/orm/relations/has-one.ts +8 -7
- package/src/orm/relations/many-to-many.ts +13 -13
- package/src/orm/runtime-types.ts +4 -4
- package/src/orm/save-graph.ts +31 -25
- package/src/orm/unit-of-work.ts +17 -17
- package/src/query/index.ts +74 -0
- package/src/query/target.ts +46 -0
- package/src/query-builder/delete-query-state.ts +30 -0
- package/src/query-builder/delete.ts +64 -18
- package/src/query-builder/hydration-manager.ts +52 -5
- package/src/query-builder/insert-query-state.ts +30 -0
- package/src/query-builder/insert.ts +58 -10
- package/src/query-builder/query-ast-service.ts +7 -2
- package/src/query-builder/query-resolution.ts +78 -0
- package/src/query-builder/raw-column-parser.ts +7 -1
- package/src/query-builder/relation-alias.ts +7 -0
- package/src/query-builder/relation-conditions.ts +61 -48
- package/src/query-builder/relation-service.ts +68 -63
- package/src/query-builder/relation-utils.ts +3 -0
- package/src/query-builder/select/cte-facet.ts +40 -0
- package/src/query-builder/select/from-facet.ts +80 -0
- package/src/query-builder/select/join-facet.ts +62 -0
- package/src/query-builder/select/predicate-facet.ts +103 -0
- package/src/query-builder/select/projection-facet.ts +69 -0
- package/src/query-builder/select/relation-facet.ts +81 -0
- package/src/query-builder/select/setop-facet.ts +36 -0
- package/src/query-builder/select-helpers.ts +15 -2
- package/src/query-builder/select-query-builder-deps.ts +19 -1
- package/src/query-builder/select-query-state.ts +2 -1
- package/src/query-builder/select.ts +795 -1163
- package/src/query-builder/update-query-state.ts +52 -0
- package/src/query-builder/update.ts +69 -18
- package/src/schema/column.ts +26 -26
- package/src/schema/table-guards.ts +31 -0
- package/src/schema/table.ts +47 -18
- package/src/schema/types.ts +22 -22
|
@@ -2,6 +2,7 @@ import type { TableDef, IndexDef } from '../../schema/table.js';
|
|
|
2
2
|
import type { ColumnDef, ForeignKeyReference } from '../../schema/column.js';
|
|
3
3
|
import type { DatabaseTable, DatabaseColumn, ColumnDiff } from './schema-types.js';
|
|
4
4
|
|
|
5
|
+
/** The name of a database dialect. */
|
|
5
6
|
export type DialectName =
|
|
6
7
|
| 'postgres'
|
|
7
8
|
| 'mysql'
|
|
@@ -9,33 +10,46 @@ export type DialectName =
|
|
|
9
10
|
| 'mssql'
|
|
10
11
|
| (string & {});
|
|
11
12
|
|
|
13
|
+
/** Interface for schema dialect implementations that handle database-specific DDL operations. */
|
|
12
14
|
export interface SchemaDialect {
|
|
15
|
+
/** The name of the dialect. */
|
|
13
16
|
readonly name: DialectName;
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
/** Quotes an identifier for use in SQL. */
|
|
16
19
|
quoteIdentifier(id: string): string;
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
/** Formats the table name for SQL. */
|
|
19
22
|
formatTableName(table: TableDef | DatabaseTable): string;
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
/** Renders the column type for SQL. */
|
|
22
25
|
renderColumnType(column: ColumnDef): string;
|
|
26
|
+
/** Renders the default value for SQL. */
|
|
23
27
|
renderDefault(value: unknown, column: ColumnDef): string;
|
|
28
|
+
/** Renders the auto-increment clause for SQL. */
|
|
24
29
|
renderAutoIncrement(column: ColumnDef, table: TableDef): string | undefined;
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
/** Renders a foreign key reference for SQL. */
|
|
27
32
|
renderReference(ref: ForeignKeyReference, table: TableDef): string;
|
|
33
|
+
/** Renders an index for SQL. */
|
|
28
34
|
renderIndex(table: TableDef, index: IndexDef): string;
|
|
35
|
+
/** Renders table options for SQL. */
|
|
29
36
|
renderTableOptions(table: TableDef): string | undefined;
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
/** Checks if the dialect supports partial indexes. */
|
|
32
39
|
supportsPartialIndexes(): boolean;
|
|
40
|
+
/** Checks if the dialect prefers inline primary key auto-increment. */
|
|
41
|
+
preferInlinePkAutoincrement(column: ColumnDef, table: TableDef, pk: string[]): boolean;
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
/** Generates SQL to drop a column. */
|
|
35
44
|
dropColumnSql?(table: DatabaseTable, column: string): string[];
|
|
45
|
+
/** Generates SQL to drop an index. */
|
|
36
46
|
dropIndexSql?(table: DatabaseTable, index: string): string[];
|
|
47
|
+
/** Generates SQL to drop a table. */
|
|
37
48
|
dropTableSql?(table: DatabaseTable): string[];
|
|
49
|
+
/** Returns a warning message for dropping a column. */
|
|
38
50
|
warnDropColumn?(table: DatabaseTable, column: string): string | undefined;
|
|
51
|
+
/** Generates SQL to alter a column. */
|
|
39
52
|
alterColumnSql?(table: TableDef, column: ColumnDef, actualColumn: DatabaseColumn, diff: ColumnDiff): string[];
|
|
53
|
+
/** Returns a warning message for altering a column. */
|
|
40
54
|
warnAlterColumn?(table: TableDef, column: ColumnDef, actualColumn: DatabaseColumn, diff: ColumnDiff): string | undefined;
|
|
41
55
|
}
|
|
@@ -6,6 +6,7 @@ import { deriveIndexName } from './naming-strategy.js';
|
|
|
6
6
|
import { generateCreateTableSql, renderColumnDefinition } from './schema-generator.js';
|
|
7
7
|
import { ColumnDiff, DatabaseColumn, DatabaseSchema, DatabaseTable } from './schema-types.js';
|
|
8
8
|
|
|
9
|
+
/** The kind of schema change. */
|
|
9
10
|
export type SchemaChangeKind =
|
|
10
11
|
| 'createTable'
|
|
11
12
|
| 'dropTable'
|
|
@@ -15,6 +16,7 @@ export type SchemaChangeKind =
|
|
|
15
16
|
| 'addIndex'
|
|
16
17
|
| 'dropIndex';
|
|
17
18
|
|
|
19
|
+
/** Represents a single schema change. */
|
|
18
20
|
export interface SchemaChange {
|
|
19
21
|
kind: SchemaChangeKind;
|
|
20
22
|
table: string;
|
|
@@ -23,11 +25,13 @@ export interface SchemaChange {
|
|
|
23
25
|
safe: boolean;
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
/** Represents a plan of schema changes. */
|
|
26
29
|
export interface SchemaPlan {
|
|
27
30
|
changes: SchemaChange[];
|
|
28
31
|
warnings: string[];
|
|
29
32
|
}
|
|
30
33
|
|
|
34
|
+
/** Options for schema diffing. */
|
|
31
35
|
export interface SchemaDiffOptions {
|
|
32
36
|
/** Allow destructive operations (drops) */
|
|
33
37
|
allowDestructive?: boolean;
|
|
@@ -69,6 +73,14 @@ const diffColumn = (expected: ColumnDef, actual: DatabaseColumn, dialect: Schema
|
|
|
69
73
|
};
|
|
70
74
|
};
|
|
71
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Computes the differences between expected and actual database schemas.
|
|
78
|
+
* @param expectedTables - The expected table definitions.
|
|
79
|
+
* @param actualSchema - The actual database schema.
|
|
80
|
+
* @param dialect - The schema dialect.
|
|
81
|
+
* @param options - Options for the diff.
|
|
82
|
+
* @returns The schema plan with changes and warnings.
|
|
83
|
+
*/
|
|
72
84
|
export const diffSchema = (
|
|
73
85
|
expectedTables: TableDef[],
|
|
74
86
|
actualSchema: DatabaseSchema,
|
|
@@ -191,10 +203,20 @@ export const diffSchema = (
|
|
|
191
203
|
return plan;
|
|
192
204
|
};
|
|
193
205
|
|
|
206
|
+
/** Options for schema synchronization. */
|
|
194
207
|
export interface SynchronizeOptions extends SchemaDiffOptions {
|
|
195
208
|
dryRun?: boolean;
|
|
196
209
|
}
|
|
197
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Synchronizes the database schema with the expected tables.
|
|
213
|
+
* @param expectedTables - The expected table definitions.
|
|
214
|
+
* @param actualSchema - The actual database schema.
|
|
215
|
+
* @param dialect - The schema dialect.
|
|
216
|
+
* @param executor - The database executor.
|
|
217
|
+
* @param options - Options for synchronization.
|
|
218
|
+
* @returns The schema plan with changes and warnings.
|
|
219
|
+
*/
|
|
198
220
|
export const synchronizeSchema = async (
|
|
199
221
|
expectedTables: TableDef[],
|
|
200
222
|
actualSchema: DatabaseSchema,
|
|
@@ -1,26 +1,28 @@
|
|
|
1
|
-
import type { TableDef
|
|
2
|
-
import type { ColumnDef
|
|
1
|
+
import type { TableDef } from '../../schema/table.js';
|
|
2
|
+
import type { ColumnDef } from '../../schema/column.js';
|
|
3
3
|
import type { SchemaDialect } from './schema-dialect.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
formatLiteral,
|
|
7
|
-
renderIndexColumns,
|
|
8
|
-
quoteQualified,
|
|
9
|
-
resolvePrimaryKey,
|
|
10
|
-
Quoter
|
|
11
|
-
} from './sql-writing.js';
|
|
12
|
-
import { DatabaseTable, DatabaseColumn, ColumnDiff } from './schema-types.js';
|
|
4
|
+
import { resolvePrimaryKey } from './sql-writing.js';
|
|
13
5
|
import { DialectName } from './schema-dialect.js';
|
|
14
6
|
|
|
7
|
+
/** Result of generating schema SQL. */
|
|
15
8
|
export interface SchemaGenerateResult {
|
|
16
9
|
tableSql: string;
|
|
17
10
|
indexSql: string[];
|
|
18
11
|
}
|
|
19
12
|
|
|
13
|
+
/** Options for rendering column definitions. */
|
|
20
14
|
export interface RenderColumnOptions {
|
|
21
15
|
includePrimary?: boolean;
|
|
22
16
|
}
|
|
23
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Renders a column definition for SQL.
|
|
20
|
+
* @param table - The table definition.
|
|
21
|
+
* @param col - The column definition.
|
|
22
|
+
* @param dialect - The schema dialect.
|
|
23
|
+
* @param options - Options for rendering.
|
|
24
|
+
* @returns The rendered SQL and whether primary key is inline.
|
|
25
|
+
*/
|
|
24
26
|
export const renderColumnDefinition = (
|
|
25
27
|
table: TableDef,
|
|
26
28
|
col: ColumnDef,
|
|
@@ -52,6 +54,12 @@ export const renderColumnDefinition = (
|
|
|
52
54
|
return { sql: parts.join(' '), inlinePrimary: !!(options.includePrimary && col.primary) };
|
|
53
55
|
};
|
|
54
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Generates SQL to create a table.
|
|
59
|
+
* @param table - The table definition.
|
|
60
|
+
* @param dialect - The schema dialect.
|
|
61
|
+
* @returns The table SQL and index SQL.
|
|
62
|
+
*/
|
|
55
63
|
export const generateCreateTableSql = (
|
|
56
64
|
table: TableDef,
|
|
57
65
|
dialect: SchemaDialect
|
|
@@ -60,7 +68,7 @@ export const generateCreateTableSql = (
|
|
|
60
68
|
const inlinePkColumns = new Set<string>();
|
|
61
69
|
|
|
62
70
|
const columnLines = Object.values(table.columns).map(col => {
|
|
63
|
-
const includePk =
|
|
71
|
+
const includePk = dialect.preferInlinePkAutoincrement(col, table, pk) && pk.includes(col.name);
|
|
64
72
|
if (includePk) {
|
|
65
73
|
inlinePkColumns.add(col.name);
|
|
66
74
|
}
|
|
@@ -99,6 +107,12 @@ export const generateCreateTableSql = (
|
|
|
99
107
|
return { tableSql, indexSql };
|
|
100
108
|
};
|
|
101
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Generates SQL for creating multiple tables.
|
|
112
|
+
* @param tables - The table definitions.
|
|
113
|
+
* @param dialect - The schema dialect.
|
|
114
|
+
* @returns The SQL statements.
|
|
115
|
+
*/
|
|
102
116
|
export const generateSchemaSql = (
|
|
103
117
|
tables: TableDef[],
|
|
104
118
|
dialect: SchemaDialect
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { DbExecutor } from '../execution/db-executor.js';
|
|
2
2
|
import type { SchemaPlan, SynchronizeOptions } from './schema-diff.js';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Executes a schema plan by running the SQL statements.
|
|
6
|
+
* @param plan - The schema plan to execute.
|
|
7
|
+
* @param executor - The database executor.
|
|
8
|
+
* @param options - Options for synchronization.
|
|
9
|
+
*/
|
|
4
10
|
export const executeSchemaPlan = async (
|
|
5
11
|
plan: SchemaPlan,
|
|
6
12
|
executor: DbExecutor,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ForeignKeyReference } from '../../schema/column.js';
|
|
2
2
|
import { IndexColumn } from '../../schema/table.js';
|
|
3
3
|
|
|
4
|
+
/** Represents the differences detected in a database column's properties. */
|
|
4
5
|
export interface ColumnDiff {
|
|
5
6
|
typeChanged?: boolean;
|
|
6
7
|
nullabilityChanged?: boolean;
|
|
@@ -8,6 +9,7 @@ export interface ColumnDiff {
|
|
|
8
9
|
autoIncrementChanged?: boolean;
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
/** Represents a column in the database schema. */
|
|
11
13
|
export interface DatabaseColumn {
|
|
12
14
|
name: string;
|
|
13
15
|
type: string;
|
|
@@ -20,6 +22,7 @@ export interface DatabaseColumn {
|
|
|
20
22
|
check?: string;
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
/** Represents an index in the database schema. */
|
|
23
26
|
export interface DatabaseIndex {
|
|
24
27
|
name: string;
|
|
25
28
|
columns: IndexColumn[];
|
|
@@ -27,11 +30,13 @@ export interface DatabaseIndex {
|
|
|
27
30
|
where?: string;
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
/** Represents a check constraint in the database schema. */
|
|
30
34
|
export interface DatabaseCheck {
|
|
31
35
|
name?: string;
|
|
32
36
|
expression: string;
|
|
33
37
|
}
|
|
34
38
|
|
|
39
|
+
/** Represents a table in the database schema. */
|
|
35
40
|
export interface DatabaseTable {
|
|
36
41
|
name: string;
|
|
37
42
|
schema?: string;
|
|
@@ -41,6 +46,7 @@ export interface DatabaseTable {
|
|
|
41
46
|
checks?: DatabaseCheck[];
|
|
42
47
|
}
|
|
43
48
|
|
|
49
|
+
/** Represents the overall database schema. */
|
|
44
50
|
export interface DatabaseSchema {
|
|
45
51
|
tables: DatabaseTable[];
|
|
46
52
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TableDef, IndexColumn } from '../../schema/table.js';
|
|
2
|
-
import type { RawDefaultValue } from '../../schema/column.js';
|
|
2
|
+
import type { ColumnDef, RawDefaultValue } from '../../schema/column.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Minimal surface for anything that can quote identifiers.
|
|
@@ -161,10 +161,10 @@ export const resolvePrimaryKey = (table: TableDef): string[] => {
|
|
|
161
161
|
return table.primaryKey;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
const columns = Object.values(table.columns ?? {});
|
|
164
|
+
const columns = Object.values(table.columns ?? {}) as ColumnDef[];
|
|
165
165
|
|
|
166
166
|
// `primary` / `name` are domain-level properties of ColumnDef.
|
|
167
167
|
return columns
|
|
168
|
-
.filter(
|
|
169
|
-
.map(
|
|
168
|
+
.filter(col => col.primary)
|
|
169
|
+
.map(col => col.name);
|
|
170
170
|
};
|
|
@@ -157,8 +157,9 @@ export abstract class Dialect
|
|
|
157
157
|
|
|
158
158
|
protected compileReturning(
|
|
159
159
|
returning: ColumnNode[] | undefined,
|
|
160
|
-
|
|
160
|
+
_ctx: CompilerContext
|
|
161
161
|
): string {
|
|
162
|
+
void _ctx;
|
|
162
163
|
if (!returning || returning.length === 0) return '';
|
|
163
164
|
throw new Error('RETURNING is not supported by this dialect.');
|
|
164
165
|
}
|
|
@@ -213,7 +214,8 @@ export abstract class Dialect
|
|
|
213
214
|
* @param index - Parameter index
|
|
214
215
|
* @returns Formatted placeholder string
|
|
215
216
|
*/
|
|
216
|
-
protected formatPlaceholder(
|
|
217
|
+
protected formatPlaceholder(_index: number): string {
|
|
218
|
+
void _index;
|
|
217
219
|
return '?';
|
|
218
220
|
}
|
|
219
221
|
|
|
@@ -221,7 +223,8 @@ export abstract class Dialect
|
|
|
221
223
|
* Whether the current dialect supports a given set operation.
|
|
222
224
|
* Override in concrete dialects to restrict support.
|
|
223
225
|
*/
|
|
224
|
-
protected supportsSetOperation(
|
|
226
|
+
protected supportsSetOperation(_kind: SetOperationKind): boolean {
|
|
227
|
+
void _kind;
|
|
225
228
|
return true;
|
|
226
229
|
}
|
|
227
230
|
|
|
@@ -376,7 +379,8 @@ export abstract class Dialect
|
|
|
376
379
|
if (isOperandNode(term)) {
|
|
377
380
|
return this.compileOperand(term, ctx);
|
|
378
381
|
}
|
|
379
|
-
|
|
382
|
+
// At this point, term must be an ExpressionNode
|
|
383
|
+
const expr = this.compileExpression(term as ExpressionNode, ctx);
|
|
380
384
|
return `(${expr})`;
|
|
381
385
|
}
|
|
382
386
|
|
|
@@ -438,15 +442,22 @@ export abstract class Dialect
|
|
|
438
442
|
private registerDefaultOperandCompilers(): void {
|
|
439
443
|
this.registerOperandCompiler('Literal', (literal: LiteralNode, ctx) => ctx.addParameter(literal.value));
|
|
440
444
|
|
|
441
|
-
this.registerOperandCompiler('AliasRef', (alias: AliasRefNode, _ctx) =>
|
|
445
|
+
this.registerOperandCompiler('AliasRef', (alias: AliasRefNode, _ctx) => {
|
|
446
|
+
void _ctx;
|
|
447
|
+
return this.quoteIdentifier(alias.name);
|
|
448
|
+
});
|
|
442
449
|
|
|
443
450
|
this.registerOperandCompiler('Column', (column: ColumnNode, _ctx) => {
|
|
451
|
+
void _ctx;
|
|
444
452
|
return `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`;
|
|
445
453
|
});
|
|
446
454
|
this.registerOperandCompiler('Function', (fnNode: FunctionNode, ctx) =>
|
|
447
455
|
this.compileFunctionOperand(fnNode, ctx)
|
|
448
456
|
);
|
|
449
|
-
this.registerOperandCompiler('JsonPath', (path: JsonPathNode, _ctx) =>
|
|
457
|
+
this.registerOperandCompiler('JsonPath', (path: JsonPathNode, _ctx) => {
|
|
458
|
+
void _ctx;
|
|
459
|
+
return this.compileJsonPath(path);
|
|
460
|
+
});
|
|
450
461
|
|
|
451
462
|
this.registerOperandCompiler('ScalarSubquery', (node: ScalarSubqueryNode, ctx) => {
|
|
452
463
|
const sql = this.compileSelectAst(node.query, ctx).trim().replace(/;$/, '');
|
|
@@ -499,7 +510,8 @@ export abstract class Dialect
|
|
|
499
510
|
}
|
|
500
511
|
|
|
501
512
|
// Default fallback, should be overridden by dialects if supported
|
|
502
|
-
protected compileJsonPath(
|
|
513
|
+
protected compileJsonPath(_node: JsonPathNode): string {
|
|
514
|
+
void _node;
|
|
503
515
|
throw new Error("JSON Path not supported by this dialect");
|
|
504
516
|
}
|
|
505
517
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CompilerContext } from '../abstract.js';
|
|
2
|
+
import { OperandNode } from '../../ast/expression.js';
|
|
2
3
|
import { SqlDialectBase } from './sql-dialect.js';
|
|
3
4
|
|
|
4
5
|
export interface FunctionTableNode {
|
|
@@ -57,9 +58,9 @@ export class FunctionTableFormatter {
|
|
|
57
58
|
*/
|
|
58
59
|
private static formatArgs(fn: FunctionTableNode, ctx?: CompilerContext, dialect?: SqlDialectBase): string {
|
|
59
60
|
return (fn.args || [])
|
|
60
|
-
.map((a:
|
|
61
|
+
.map((a: OperandNode) => {
|
|
61
62
|
if (ctx && dialect) {
|
|
62
|
-
return (dialect as
|
|
63
|
+
return (dialect as unknown as { compileOperand(n: OperandNode, c: CompilerContext): string }).compileOperand(a, ctx);
|
|
63
64
|
}
|
|
64
65
|
return String(a);
|
|
65
66
|
})
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { CompilerContext } from '../abstract.js';
|
|
2
2
|
import { JoinNode } from '../../ast/join.js';
|
|
3
|
+
import { TableSourceNode } from '../../ast/query.js';
|
|
4
|
+
import { ExpressionNode } from '../../ast/expression.js';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Compiler for JOIN clauses in SELECT statements.
|
|
@@ -9,12 +11,12 @@ export class JoinCompiler {
|
|
|
9
11
|
static compileJoins(
|
|
10
12
|
joins: JoinNode[] | undefined,
|
|
11
13
|
ctx: CompilerContext,
|
|
12
|
-
compileFrom: (from:
|
|
13
|
-
compileExpression: (expr:
|
|
14
|
+
compileFrom: (from: TableSourceNode, ctx: CompilerContext) => string,
|
|
15
|
+
compileExpression: (expr: ExpressionNode, ctx: CompilerContext) => string
|
|
14
16
|
): string {
|
|
15
17
|
if (!joins || joins.length === 0) return '';
|
|
16
18
|
const parts = joins.map(j => {
|
|
17
|
-
const table = compileFrom(j.table
|
|
19
|
+
const table = compileFrom(j.table, ctx);
|
|
18
20
|
const cond = compileExpression(j.condition, ctx);
|
|
19
21
|
return `${j.kind} JOIN ${table} ON ${cond}`;
|
|
20
22
|
});
|
|
@@ -35,6 +35,7 @@ export class NoReturningStrategy implements ReturningStrategy {
|
|
|
35
35
|
* @throws Error indicating RETURNING is not supported.
|
|
36
36
|
*/
|
|
37
37
|
compileReturning(returning: ColumnNode[] | undefined, _ctx: CompilerContext): string {
|
|
38
|
+
void _ctx;
|
|
38
39
|
if (!returning || returning.length === 0) return '';
|
|
39
40
|
throw new Error('RETURNING is not supported by this dialect.');
|
|
40
41
|
}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
OrderByNode,
|
|
12
12
|
TableNode
|
|
13
13
|
} from '../../ast/query.js';
|
|
14
|
-
import { ColumnNode } from '../../ast/expression.js';
|
|
14
|
+
import { ColumnNode, OperandNode } from '../../ast/expression.js';
|
|
15
15
|
import { FunctionTableFormatter } from './function-table-formatter.js';
|
|
16
16
|
import { PaginationStrategy, StandardLimitOffsetPagination } from './pagination-strategy.js';
|
|
17
17
|
import { CteCompiler } from './cte-compiler.js';
|
|
@@ -134,7 +134,7 @@ export abstract class SqlDialectBase extends Dialect {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
private compileUpdateAssignments(
|
|
137
|
-
assignments: { column: ColumnNode; value:
|
|
137
|
+
assignments: { column: ColumnNode; value: OperandNode }[],
|
|
138
138
|
table: TableNode,
|
|
139
139
|
ctx: CompilerContext
|
|
140
140
|
): string {
|
|
@@ -190,7 +190,7 @@ export abstract class SqlDialectBase extends Dialect {
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
protected compileFrom(ast: SelectQueryNode['from'], ctx?: CompilerContext): string {
|
|
193
|
-
const tableSource = ast
|
|
193
|
+
const tableSource = ast;
|
|
194
194
|
if (tableSource.type === 'FunctionTable') {
|
|
195
195
|
return this.compileFunctionTable(tableSource, ctx);
|
|
196
196
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { StandardFunctionStrategy } from '../../functions/standard-strategy.js';
|
|
2
|
-
import { FunctionRenderContext } from '../../functions/types.js';
|
|
3
2
|
import { LiteralNode } from '../../ast/expression.js';
|
|
4
3
|
|
|
5
4
|
export class MssqlFunctionStrategy extends StandardFunctionStrategy {
|
|
@@ -84,27 +83,27 @@ export class MssqlFunctionStrategy extends StandardFunctionStrategy {
|
|
|
84
83
|
return `DATEPART(dw, ${compiledArgs[0]})`;
|
|
85
84
|
});
|
|
86
85
|
|
|
87
|
-
this.add('WEEK_OF_YEAR', ({ compiledArgs }) => {
|
|
88
|
-
if (compiledArgs.length !== 1) throw new Error('WEEK_OF_YEAR expects 1 argument');
|
|
89
|
-
return `DATEPART(wk, ${compiledArgs[0]})`;
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
this.add('DATE_TRUNC', ({ node, compiledArgs }) => {
|
|
93
|
-
if (compiledArgs.length !== 2) throw new Error('DATE_TRUNC expects 2 arguments (part, date)');
|
|
94
|
-
const [, date] = compiledArgs;
|
|
95
|
-
const partArg = node.args[0] as LiteralNode;
|
|
96
|
-
const partClean = String(partArg.value).replace(/['"]/g, '').toLowerCase();
|
|
97
|
-
// SQL Server 2022+ has DATETRUNC
|
|
98
|
-
return `DATETRUNC(${partClean}, ${date})`;
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
this.add('GROUP_CONCAT', ctx => {
|
|
102
|
-
const arg = ctx.compiledArgs[0];
|
|
103
|
-
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
104
|
-
const separator = ctx.compileOperand(separatorOperand);
|
|
105
|
-
const orderClause = this.buildOrderByExpression(ctx);
|
|
106
|
-
const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : '';
|
|
107
|
-
return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
86
|
+
this.add('WEEK_OF_YEAR', ({ compiledArgs }) => {
|
|
87
|
+
if (compiledArgs.length !== 1) throw new Error('WEEK_OF_YEAR expects 1 argument');
|
|
88
|
+
return `DATEPART(wk, ${compiledArgs[0]})`;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
this.add('DATE_TRUNC', ({ node, compiledArgs }) => {
|
|
92
|
+
if (compiledArgs.length !== 2) throw new Error('DATE_TRUNC expects 2 arguments (part, date)');
|
|
93
|
+
const [, date] = compiledArgs;
|
|
94
|
+
const partArg = node.args[0] as LiteralNode;
|
|
95
|
+
const partClean = String(partArg.value).replace(/['"]/g, '').toLowerCase();
|
|
96
|
+
// SQL Server 2022+ has DATETRUNC
|
|
97
|
+
return `DATETRUNC(${partClean}, ${date})`;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
this.add('GROUP_CONCAT', ctx => {
|
|
101
|
+
const arg = ctx.compiledArgs[0];
|
|
102
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
103
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
104
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
105
|
+
const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : '';
|
|
106
|
+
return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { CompilerContext } from '../abstract.js';
|
|
2
2
|
import {
|
|
3
3
|
SelectQueryNode,
|
|
4
|
-
DeleteQueryNode
|
|
5
|
-
TableSourceNode,
|
|
6
|
-
DerivedTableNode,
|
|
7
|
-
OrderByNode
|
|
4
|
+
DeleteQueryNode
|
|
8
5
|
} from '../../ast/query.js';
|
|
9
6
|
import { JsonPathNode } from '../../ast/expression.js';
|
|
10
7
|
import { MssqlFunctionStrategy } from './functions.js';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { StandardFunctionStrategy } from '../../functions/standard-strategy.js';
|
|
2
|
-
import { FunctionRenderContext } from '../../functions/types.js';
|
|
3
2
|
import { LiteralNode } from '../../ast/expression.js';
|
|
4
3
|
|
|
5
4
|
export class MysqlFunctionStrategy extends StandardFunctionStrategy {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { StandardFunctionStrategy } from '../../functions/standard-strategy.js';
|
|
2
|
-
import { FunctionRenderContext } from '../../functions/types.js';
|
|
3
2
|
import { LiteralNode } from '../../ast/expression.js';
|
|
4
3
|
|
|
5
4
|
export class PostgresFunctionStrategy extends StandardFunctionStrategy {
|
|
@@ -69,36 +68,36 @@ export class PostgresFunctionStrategy extends StandardFunctionStrategy {
|
|
|
69
68
|
return `TO_CHAR(${date}, ${format})`;
|
|
70
69
|
});
|
|
71
70
|
|
|
72
|
-
this.add('END_OF_MONTH', ({ compiledArgs }) => {
|
|
73
|
-
if (compiledArgs.length !== 1) throw new Error('END_OF_MONTH expects 1 argument');
|
|
74
|
-
return `(date_trunc('month', ${compiledArgs[0]}) + interval '1 month' - interval '1 day')::DATE`;
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
this.add('DAY_OF_WEEK', ({ compiledArgs }) => {
|
|
78
|
-
if (compiledArgs.length !== 1) throw new Error('DAY_OF_WEEK expects 1 argument');
|
|
79
|
-
return `EXTRACT(DOW FROM ${compiledArgs[0]})`;
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
this.add('WEEK_OF_YEAR', ({ compiledArgs }) => {
|
|
83
|
-
if (compiledArgs.length !== 1) throw new Error('WEEK_OF_YEAR expects 1 argument');
|
|
84
|
-
return `EXTRACT(WEEK FROM ${compiledArgs[0]})`;
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
this.add('DATE_TRUNC', ({ node, compiledArgs }) => {
|
|
88
|
-
if (compiledArgs.length !== 2) throw new Error('DATE_TRUNC expects 2 arguments (part, date)');
|
|
89
|
-
const [, date] = compiledArgs;
|
|
90
|
-
const partArg = node.args[0] as LiteralNode;
|
|
91
|
-
const partClean = String(partArg.value).replace(/['"]/g, '').toLowerCase();
|
|
92
|
-
return `DATE_TRUNC('${partClean}', ${date})`;
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
this.add('GROUP_CONCAT', ctx => {
|
|
96
|
-
const arg = ctx.compiledArgs[0];
|
|
97
|
-
const orderClause = this.buildOrderByExpression(ctx);
|
|
98
|
-
const orderSegment = orderClause ? ` ${orderClause}` : '';
|
|
99
|
-
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
100
|
-
const separator = ctx.compileOperand(separatorOperand);
|
|
101
|
-
return `STRING_AGG(${arg}, ${separator}${orderSegment})`;
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
}
|
|
71
|
+
this.add('END_OF_MONTH', ({ compiledArgs }) => {
|
|
72
|
+
if (compiledArgs.length !== 1) throw new Error('END_OF_MONTH expects 1 argument');
|
|
73
|
+
return `(date_trunc('month', ${compiledArgs[0]}) + interval '1 month' - interval '1 day')::DATE`;
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
this.add('DAY_OF_WEEK', ({ compiledArgs }) => {
|
|
77
|
+
if (compiledArgs.length !== 1) throw new Error('DAY_OF_WEEK expects 1 argument');
|
|
78
|
+
return `EXTRACT(DOW FROM ${compiledArgs[0]})`;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
this.add('WEEK_OF_YEAR', ({ compiledArgs }) => {
|
|
82
|
+
if (compiledArgs.length !== 1) throw new Error('WEEK_OF_YEAR expects 1 argument');
|
|
83
|
+
return `EXTRACT(WEEK FROM ${compiledArgs[0]})`;
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
this.add('DATE_TRUNC', ({ node, compiledArgs }) => {
|
|
87
|
+
if (compiledArgs.length !== 2) throw new Error('DATE_TRUNC expects 2 arguments (part, date)');
|
|
88
|
+
const [, date] = compiledArgs;
|
|
89
|
+
const partArg = node.args[0] as LiteralNode;
|
|
90
|
+
const partClean = String(partArg.value).replace(/['"]/g, '').toLowerCase();
|
|
91
|
+
return `DATE_TRUNC('${partClean}', ${date})`;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
this.add('GROUP_CONCAT', ctx => {
|
|
95
|
+
const arg = ctx.compiledArgs[0];
|
|
96
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
97
|
+
const orderSegment = orderClause ? ` ${orderClause}` : '';
|
|
98
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
99
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
100
|
+
return `STRING_AGG(${arg}, ${separator}${orderSegment})`;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -36,6 +36,7 @@ export class PostgresDialect extends SqlDialectBase {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
|
|
39
|
+
void ctx;
|
|
39
40
|
if (!returning || returning.length === 0) return '';
|
|
40
41
|
const columns = this.formatReturningColumns(returning);
|
|
41
42
|
return ` RETURNING ${columns}`;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { StandardFunctionStrategy } from '../../functions/standard-strategy.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
1
|
+
import { StandardFunctionStrategy } from '../../functions/standard-strategy.js';
|
|
2
|
+
import { LiteralNode } from '../../ast/expression.js';
|
|
3
|
+
|
|
4
|
+
export class SqliteFunctionStrategy extends StandardFunctionStrategy {
|
|
5
|
+
constructor() {
|
|
6
|
+
super();
|
|
7
|
+
this.registerOverrides();
|
|
8
|
+
}
|
|
10
9
|
|
|
11
10
|
private registerOverrides() {
|
|
12
11
|
// Override Standard/Abstract definitions with SQLite specifics
|
|
@@ -110,13 +109,13 @@ export class SqliteFunctionStrategy extends StandardFunctionStrategy {
|
|
|
110
109
|
return `date(${date})`;
|
|
111
110
|
}
|
|
112
111
|
return `date(${date}, 'start of ${partClean}')`;
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
this.add('GROUP_CONCAT', ctx => {
|
|
116
|
-
const arg = ctx.compiledArgs[0];
|
|
117
|
-
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
118
|
-
const separator = ctx.compileOperand(separatorOperand);
|
|
119
|
-
return `GROUP_CONCAT(${arg}, ${separator})`;
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
this.add('GROUP_CONCAT', ctx => {
|
|
115
|
+
const arg = ctx.compiledArgs[0];
|
|
116
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
117
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
118
|
+
return `GROUP_CONCAT(${arg}, ${separator})`;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -37,10 +37,12 @@ export class SqliteDialect extends SqlDialectBase {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
protected compileQualifiedColumn(column: ColumnNode, _table: TableNode): string {
|
|
40
|
+
void _table;
|
|
40
41
|
return this.quoteIdentifier(column.name);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
|
|
45
|
+
void ctx;
|
|
44
46
|
if (!returning || returning.length === 0) return '';
|
|
45
47
|
const columns = this.formatReturningColumns(returning);
|
|
46
48
|
return ` RETURNING ${columns}`;
|