metal-orm 1.1.11 → 1.1.16
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 +758 -769
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +100 -96
- package/scripts/generate-entities/schema.mjs +122 -122
- package/scripts/generate-entities/tree-detection.mjs +92 -92
- package/scripts/inflection/pt-br.mjs +468 -468
- package/scripts/run-eslint.mjs +33 -34
- package/scripts/show-sql-seed.sql +102 -0
- package/scripts/show-sql.mjs +321 -325
- package/src/codegen/naming-strategy.ts +54 -54
- package/src/codegen/typescript.ts +482 -482
- package/src/core/ast/adapters.ts +1 -1
- package/src/core/ast/builders.ts +123 -123
- package/src/core/ast/expression-builders.ts +745 -745
- package/src/core/ast/expression-nodes.ts +304 -304
- package/src/core/ast/expression-visitor.ts +212 -212
- package/src/core/ast/expression.ts +20 -20
- package/src/core/ast/helpers.ts +14 -14
- package/src/core/ast/join.ts +18 -18
- package/src/core/ast/query.ts +200 -200
- package/src/core/ddl/dialects/base-schema-dialect.ts +1 -1
- package/src/core/ddl/dialects/mssql-schema-dialect.ts +1 -1
- package/src/core/ddl/dialects/mysql-schema-dialect.ts +1 -1
- package/src/core/ddl/dialects/postgres-schema-dialect.ts +1 -1
- package/src/core/ddl/dialects/render-reference.test.ts +70 -70
- package/src/core/ddl/dialects/sqlite-schema-dialect.ts +1 -1
- package/src/core/ddl/introspect/catalogs/index.ts +5 -5
- package/src/core/ddl/introspect/catalogs/postgres.ts +146 -146
- package/src/core/ddl/introspect/context.ts +15 -15
- package/src/core/ddl/introspect/functions/postgres.ts +35 -35
- package/src/core/ddl/introspect/registry.ts +40 -40
- package/src/core/ddl/introspect/run-select.ts +35 -35
- package/src/core/ddl/introspect/utils.ts +56 -56
- package/src/core/ddl/naming-strategy.ts +16 -16
- package/src/core/ddl/schema-dialect.ts +56 -56
- package/src/core/ddl/schema-diff.ts +234 -234
- package/src/core/ddl/schema-generator.ts +1 -1
- package/src/core/ddl/schema-introspect.ts +25 -25
- package/src/core/ddl/sql-writing.ts +171 -171
- package/src/core/dialect/abstract.ts +541 -541
- package/src/core/dialect/base/cte-compiler.ts +33 -33
- package/src/core/dialect/base/function-table-formatter.ts +103 -103
- package/src/core/dialect/base/groupby-compiler.ts +21 -21
- package/src/core/dialect/base/join-compiler.ts +25 -25
- package/src/core/dialect/base/orderby-compiler.ts +35 -35
- package/src/core/dialect/base/pagination-strategy.ts +32 -32
- package/src/core/dialect/base/returning-strategy.ts +57 -57
- package/src/core/dialect/base/sql-dialect.ts +294 -294
- package/src/core/dialect/dialect-factory.ts +91 -91
- package/src/core/dialect/mssql/functions.ts +120 -120
- package/src/core/dialect/mssql/index.ts +317 -317
- package/src/core/dialect/mysql/functions.ts +103 -103
- package/src/core/dialect/mysql/index.ts +105 -105
- package/src/core/dialect/postgres/functions.ts +108 -108
- package/src/core/dialect/postgres/index.ts +91 -91
- package/src/core/dialect/sqlite/functions.ts +129 -129
- package/src/core/dialect/sqlite/index.ts +67 -67
- package/src/core/driver/database-driver.ts +19 -19
- package/src/core/driver/mssql-driver.ts +23 -23
- package/src/core/driver/mysql-driver.ts +23 -23
- package/src/core/driver/postgres-driver.ts +23 -23
- package/src/core/driver/sqlite-driver.ts +23 -23
- package/src/core/execution/db-executor.ts +92 -92
- package/src/core/execution/executors/better-sqlite3-executor.ts +90 -90
- package/src/core/execution/executors/mssql-executor.ts +184 -184
- package/src/core/execution/executors/mysql-executor.ts +88 -88
- package/src/core/execution/executors/postgres-executor.ts +26 -26
- package/src/core/execution/executors/sqlite-executor.ts +42 -42
- package/src/core/execution/pooling/pool-types.ts +30 -30
- package/src/core/execution/pooling/pool.ts +275 -275
- package/src/core/functions/array.ts +35 -35
- package/src/core/functions/control-flow.ts +79 -79
- package/src/core/functions/datetime.ts +237 -237
- package/src/core/functions/json.ts +70 -70
- package/src/core/functions/numeric.ts +297 -297
- package/src/core/functions/text.ts +334 -334
- package/src/core/functions/types.ts +33 -33
- package/src/core/hydration/types.ts +51 -51
- package/src/core/sql/sql-operator-config.ts +39 -39
- package/src/core/sql/sql.ts +152 -152
- package/src/decorators/column-decorator.ts +87 -87
- package/src/decorators/decorator-metadata.ts +143 -143
- package/src/decorators/entity.ts +93 -93
- package/src/decorators/index.ts +39 -39
- package/src/decorators/relations.ts +231 -231
- package/src/decorators/transformers/built-in/string-transformers.ts +231 -231
- package/src/decorators/transformers/transformer-decorators.ts +134 -134
- package/src/decorators/transformers/transformer-executor.ts +171 -171
- package/src/decorators/transformers/transformer-metadata.ts +73 -73
- package/src/decorators/validators/built-in/br-cep-validator.ts +55 -55
- package/src/decorators/validators/built-in/br-cnpj-validator.ts +105 -105
- package/src/decorators/validators/built-in/br-cpf-validator.ts +103 -103
- package/src/decorators/validators/country-validator-registry.ts +64 -64
- package/src/decorators/validators/country-validators-decorators.ts +203 -203
- package/src/decorators/validators/country-validators.ts +105 -105
- package/src/decorators/validators/validator-metadata.ts +59 -59
- package/src/dto/dto-types.ts +226 -226
- package/src/dto/filter-types.ts +141 -141
- package/src/dto/index.ts +95 -95
- package/src/dto/openapi/generators/base.ts +29 -29
- package/src/dto/openapi/generators/column.ts +37 -37
- package/src/dto/openapi/generators/dto.ts +91 -91
- package/src/dto/openapi/generators/filter.ts +75 -75
- package/src/dto/openapi/generators/nested-dto.ts +618 -618
- package/src/dto/openapi/generators/pagination.ts +111 -111
- package/src/dto/openapi/generators/relation-filter.ts +228 -228
- package/src/dto/openapi/index.ts +12 -12
- package/src/dto/openapi/types.ts +101 -101
- package/src/dto/openapi/utilities.ts +95 -95
- package/src/dto/pagination-utils.ts +150 -150
- package/src/dto/transform.ts +197 -197
- package/src/index.ts +86 -86
- package/src/orm/als.ts +58 -58
- package/src/orm/domain-event-bus.ts +119 -119
- package/src/orm/entity-context.ts +86 -86
- package/src/orm/entity-materializer.ts +159 -159
- package/src/orm/entity-meta.ts +97 -97
- package/src/orm/entity-registry.ts +39 -39
- package/src/orm/entity-relation-cache.ts +39 -39
- package/src/orm/execute.ts +194 -194
- package/src/orm/execution-context.ts +18 -18
- package/src/orm/hydration-context.ts +26 -26
- package/src/orm/hydration.ts +112 -112
- package/src/orm/identity-map.ts +61 -61
- package/src/orm/interceptor-pipeline.ts +16 -16
- package/src/orm/lazy-batch/belongs-to-many.ts +119 -119
- package/src/orm/lazy-batch/belongs-to.ts +108 -108
- package/src/orm/lazy-batch/has-many.ts +69 -69
- package/src/orm/lazy-batch/has-one.ts +68 -68
- package/src/orm/lazy-batch/shared.ts +125 -125
- package/src/orm/orm-session.ts +620 -620
- package/src/orm/orm.ts +34 -34
- package/src/orm/pooled-executor-factory.ts +121 -121
- package/src/orm/query-logger.ts +40 -40
- package/src/orm/relation-change-processor.ts +420 -420
- package/src/orm/relations/belongs-to.ts +143 -143
- package/src/orm/relations/has-many.ts +204 -204
- package/src/orm/relations/has-one.ts +174 -174
- package/src/orm/relations/many-to-many.ts +288 -288
- package/src/orm/relations/morph-many.ts +156 -156
- package/src/orm/relations/morph-one.ts +151 -151
- package/src/orm/relations/morph-to.ts +162 -162
- package/src/orm/runtime-types.ts +92 -92
- package/src/orm/save-graph.ts +561 -561
- package/src/orm/transaction-runner.ts +24 -24
- package/src/orm/unit-of-work.ts +426 -426
- package/src/query/index.ts +69 -69
- package/src/query/target.ts +46 -46
- package/src/query-builder/column-selector.ts +81 -81
- package/src/query-builder/delete.ts +141 -141
- package/src/query-builder/insert-query-state.ts +149 -149
- package/src/query-builder/insert.ts +117 -117
- package/src/query-builder/query-ast-service.ts +287 -287
- package/src/query-builder/query-resolution.ts +78 -78
- package/src/query-builder/raw-column-parser.ts +38 -38
- package/src/query-builder/relation-filter-utils.ts +153 -153
- package/src/query-builder/relation-join-planner.ts +10 -10
- package/src/query-builder/relation-manager.ts +87 -87
- package/src/query-builder/relation-projection-helper.ts +102 -102
- package/src/query-builder/relation-types.ts +9 -9
- package/src/query-builder/relation-utils.ts +15 -15
- package/src/query-builder/select/cte-facet.ts +40 -40
- package/src/query-builder/select/from-facet.ts +80 -80
- package/src/query-builder/select/join-facet.ts +62 -62
- package/src/query-builder/select/predicate-facet.ts +104 -104
- package/src/query-builder/select/projection-facet.ts +70 -70
- package/src/query-builder/select/relation-facet.ts +81 -81
- package/src/query-builder/select/setop-facet.ts +36 -36
- package/src/query-builder/select-helpers.ts +1 -1
- package/src/query-builder/select-query-builder-deps.ts +130 -130
- package/src/query-builder/select-query-state.ts +207 -207
- package/src/query-builder/update.ts +151 -151
- package/src/schema/column-types.ts +322 -322
- package/src/schema/table-guards.ts +37 -37
- package/src/schema/table.ts +281 -281
- package/src/tree/index.ts +13 -13
- package/src/tree/nested-set-strategy.ts +545 -545
- package/src/tree/tree-decorator.ts +397 -397
- package/src/tree/tree-manager.ts +754 -754
- package/src/tree/tree-query.ts +427 -427
- package/src/tree/tree-types.ts +299 -299
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
// Dialect factory for the SQL DSL.
|
|
2
|
-
// Centralizes how we go from a symbolic name ("sqlite") to a concrete Dialect instance.
|
|
3
|
-
|
|
4
|
-
import { Dialect } from './abstract.js';
|
|
5
|
-
import { PostgresDialect } from './postgres/index.js';
|
|
6
|
-
import { MySqlDialect } from './mysql/index.js';
|
|
7
|
-
import { SqliteDialect } from './sqlite/index.js';
|
|
8
|
-
import { SqlServerDialect } from './mssql/index.js';
|
|
9
|
-
|
|
10
|
-
export type DialectKey =
|
|
11
|
-
| 'postgres'
|
|
12
|
-
| 'mysql'
|
|
13
|
-
| 'sqlite'
|
|
14
|
-
| 'mssql'
|
|
15
|
-
| (string & {}); // allow user-defined keys without constraining too much
|
|
16
|
-
|
|
17
|
-
type DialectFactoryFn = () => Dialect;
|
|
18
|
-
|
|
19
|
-
export class DialectFactory {
|
|
20
|
-
private static registry = new Map<DialectKey, DialectFactoryFn>();
|
|
21
|
-
private static defaultsInitialized = false;
|
|
22
|
-
|
|
23
|
-
private static ensureDefaults(): void {
|
|
24
|
-
if (this.defaultsInitialized) return;
|
|
25
|
-
this.defaultsInitialized = true;
|
|
26
|
-
|
|
27
|
-
// Register built-in dialects only if no override exists yet.
|
|
28
|
-
if (!this.registry.has('postgres')) {
|
|
29
|
-
this.registry.set('postgres', () => new PostgresDialect());
|
|
30
|
-
}
|
|
31
|
-
if (!this.registry.has('mysql')) {
|
|
32
|
-
this.registry.set('mysql', () => new MySqlDialect());
|
|
33
|
-
}
|
|
34
|
-
if (!this.registry.has('sqlite')) {
|
|
35
|
-
this.registry.set('sqlite', () => new SqliteDialect());
|
|
36
|
-
}
|
|
37
|
-
if (!this.registry.has('mssql')) {
|
|
38
|
-
this.registry.set('mssql', () => new SqlServerDialect());
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Register (or override) a dialect factory for a key.
|
|
44
|
-
*
|
|
45
|
-
* Examples:
|
|
46
|
-
* DialectFactory.register('sqlite', () => new SqliteDialect());
|
|
47
|
-
* DialectFactory.register('my-tenant-dialect', () => new CustomDialect());
|
|
48
|
-
*/
|
|
49
|
-
public static register(key: DialectKey, factory: DialectFactoryFn): void {
|
|
50
|
-
this.registry.set(key, factory);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Resolve a key into a Dialect instance.
|
|
55
|
-
* Throws if the key is not registered.
|
|
56
|
-
*/
|
|
57
|
-
public static create(key: DialectKey): Dialect {
|
|
58
|
-
this.ensureDefaults();
|
|
59
|
-
const factory = this.registry.get(key);
|
|
60
|
-
if (!factory) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
`Dialect "${String(
|
|
63
|
-
key
|
|
64
|
-
)}" is not registered. Use DialectFactory.register(...) to register it.`
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
return factory();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Clear all registrations (mainly for tests).
|
|
72
|
-
* Built-ins will be re-registered lazily on the next create().
|
|
73
|
-
*/
|
|
74
|
-
public static clear(): void {
|
|
75
|
-
this.registry.clear();
|
|
76
|
-
this.defaultsInitialized = false;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Helper to normalize either a Dialect instance OR a key into a Dialect instance.
|
|
82
|
-
* This is what query builders will use.
|
|
83
|
-
*/
|
|
84
|
-
export const resolveDialectInput = (
|
|
85
|
-
dialect: Dialect | DialectKey
|
|
86
|
-
): Dialect => {
|
|
87
|
-
if (typeof dialect === 'string') {
|
|
88
|
-
return DialectFactory.create(dialect);
|
|
89
|
-
}
|
|
90
|
-
return dialect;
|
|
91
|
-
};
|
|
1
|
+
// Dialect factory for the SQL DSL.
|
|
2
|
+
// Centralizes how we go from a symbolic name ("sqlite") to a concrete Dialect instance.
|
|
3
|
+
|
|
4
|
+
import { Dialect } from './abstract.js';
|
|
5
|
+
import { PostgresDialect } from './postgres/index.js';
|
|
6
|
+
import { MySqlDialect } from './mysql/index.js';
|
|
7
|
+
import { SqliteDialect } from './sqlite/index.js';
|
|
8
|
+
import { SqlServerDialect } from './mssql/index.js';
|
|
9
|
+
|
|
10
|
+
export type DialectKey =
|
|
11
|
+
| 'postgres'
|
|
12
|
+
| 'mysql'
|
|
13
|
+
| 'sqlite'
|
|
14
|
+
| 'mssql'
|
|
15
|
+
| (string & {}); // allow user-defined keys without constraining too much
|
|
16
|
+
|
|
17
|
+
type DialectFactoryFn = () => Dialect;
|
|
18
|
+
|
|
19
|
+
export class DialectFactory {
|
|
20
|
+
private static registry = new Map<DialectKey, DialectFactoryFn>();
|
|
21
|
+
private static defaultsInitialized = false;
|
|
22
|
+
|
|
23
|
+
private static ensureDefaults(): void {
|
|
24
|
+
if (this.defaultsInitialized) return;
|
|
25
|
+
this.defaultsInitialized = true;
|
|
26
|
+
|
|
27
|
+
// Register built-in dialects only if no override exists yet.
|
|
28
|
+
if (!this.registry.has('postgres')) {
|
|
29
|
+
this.registry.set('postgres', () => new PostgresDialect());
|
|
30
|
+
}
|
|
31
|
+
if (!this.registry.has('mysql')) {
|
|
32
|
+
this.registry.set('mysql', () => new MySqlDialect());
|
|
33
|
+
}
|
|
34
|
+
if (!this.registry.has('sqlite')) {
|
|
35
|
+
this.registry.set('sqlite', () => new SqliteDialect());
|
|
36
|
+
}
|
|
37
|
+
if (!this.registry.has('mssql')) {
|
|
38
|
+
this.registry.set('mssql', () => new SqlServerDialect());
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Register (or override) a dialect factory for a key.
|
|
44
|
+
*
|
|
45
|
+
* Examples:
|
|
46
|
+
* DialectFactory.register('sqlite', () => new SqliteDialect());
|
|
47
|
+
* DialectFactory.register('my-tenant-dialect', () => new CustomDialect());
|
|
48
|
+
*/
|
|
49
|
+
public static register(key: DialectKey, factory: DialectFactoryFn): void {
|
|
50
|
+
this.registry.set(key, factory);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Resolve a key into a Dialect instance.
|
|
55
|
+
* Throws if the key is not registered.
|
|
56
|
+
*/
|
|
57
|
+
public static create(key: DialectKey): Dialect {
|
|
58
|
+
this.ensureDefaults();
|
|
59
|
+
const factory = this.registry.get(key);
|
|
60
|
+
if (!factory) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`Dialect "${String(
|
|
63
|
+
key
|
|
64
|
+
)}" is not registered. Use DialectFactory.register(...) to register it.`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return factory();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Clear all registrations (mainly for tests).
|
|
72
|
+
* Built-ins will be re-registered lazily on the next create().
|
|
73
|
+
*/
|
|
74
|
+
public static clear(): void {
|
|
75
|
+
this.registry.clear();
|
|
76
|
+
this.defaultsInitialized = false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Helper to normalize either a Dialect instance OR a key into a Dialect instance.
|
|
82
|
+
* This is what query builders will use.
|
|
83
|
+
*/
|
|
84
|
+
export const resolveDialectInput = (
|
|
85
|
+
dialect: Dialect | DialectKey
|
|
86
|
+
): Dialect => {
|
|
87
|
+
if (typeof dialect === 'string') {
|
|
88
|
+
return DialectFactory.create(dialect);
|
|
89
|
+
}
|
|
90
|
+
return dialect;
|
|
91
|
+
};
|
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
import { StandardFunctionStrategy } from '../../functions/standard-strategy.js';
|
|
2
|
-
import { LiteralNode } from '../../ast/expression.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Microsoft SQL Server specific function strategy.
|
|
6
|
-
* Implements and overrides SQL function compilation rules for MSSQL.
|
|
7
|
-
*/
|
|
8
|
-
export class MssqlFunctionStrategy extends StandardFunctionStrategy {
|
|
9
|
-
constructor() {
|
|
10
|
-
super();
|
|
11
|
-
this.registerOverrides();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
private registerOverrides() {
|
|
15
|
-
// Override Standard/Abstract definitions with MSSQL specifics
|
|
16
|
-
|
|
17
|
-
// Date/Time functions
|
|
18
|
-
this.add('NOW', () => `GETDATE()`);
|
|
19
|
-
this.add('CURRENT_DATE', () => `CAST(GETDATE() AS DATE)`);
|
|
20
|
-
this.add('CURRENT_TIME', () => `CAST(GETDATE() AS TIME)`);
|
|
21
|
-
this.add('UTC_NOW', () => `GETUTCDATE()`);
|
|
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
|
-
const partClean = part.replace(/['"]/g, '').toLowerCase();
|
|
27
|
-
return `DATEPART(${partClean}, ${date})`;
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
this.add('YEAR', ({ compiledArgs }) => {
|
|
31
|
-
if (compiledArgs.length !== 1) throw new Error('YEAR expects 1 argument');
|
|
32
|
-
return `YEAR(${compiledArgs[0]})`;
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
this.add('MONTH', ({ compiledArgs }) => {
|
|
36
|
-
if (compiledArgs.length !== 1) throw new Error('MONTH expects 1 argument');
|
|
37
|
-
return `MONTH(${compiledArgs[0]})`;
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
this.add('DAY', ({ compiledArgs }) => {
|
|
41
|
-
if (compiledArgs.length !== 1) throw new Error('DAY expects 1 argument');
|
|
42
|
-
return `DAY(${compiledArgs[0]})`;
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
this.add('DATE_ADD', ({ node, compiledArgs }) => {
|
|
46
|
-
if (compiledArgs.length !== 3) throw new Error('DATE_ADD expects 3 arguments (date, interval, unit)');
|
|
47
|
-
const [date, interval] = compiledArgs;
|
|
48
|
-
const unitArg = node.args[2] as LiteralNode;
|
|
49
|
-
const unitClean = String(unitArg.value).replace(/['"]/g, '').toLowerCase();
|
|
50
|
-
return `DATEADD(${unitClean}, ${interval}, ${date})`;
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
this.add('DATE_SUB', ({ node, compiledArgs }) => {
|
|
54
|
-
if (compiledArgs.length !== 3) throw new Error('DATE_SUB expects 3 arguments (date, interval, unit)');
|
|
55
|
-
const [date, interval] = compiledArgs;
|
|
56
|
-
const unitArg = node.args[2] as LiteralNode;
|
|
57
|
-
const unitClean = String(unitArg.value).replace(/['"]/g, '').toLowerCase();
|
|
58
|
-
return `DATEADD(${unitClean}, -${interval}, ${date})`;
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
this.add('DATE_DIFF', ({ compiledArgs }) => {
|
|
62
|
-
if (compiledArgs.length !== 2) throw new Error('DATE_DIFF expects 2 arguments');
|
|
63
|
-
const [date1, date2] = compiledArgs;
|
|
64
|
-
return `DATEDIFF(day, ${date2}, ${date1})`;
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
this.add('DATE_FORMAT', ({ compiledArgs }) => {
|
|
68
|
-
if (compiledArgs.length !== 2) throw new Error('DATE_FORMAT expects 2 arguments');
|
|
69
|
-
const [date, format] = compiledArgs;
|
|
70
|
-
return `FORMAT(${date}, ${format})`;
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
this.add('UNIX_TIMESTAMP', () => `DATEDIFF(SECOND, '1970-01-01', GETUTCDATE())`);
|
|
74
|
-
|
|
75
|
-
this.add('FROM_UNIXTIME', ({ compiledArgs }) => {
|
|
76
|
-
if (compiledArgs.length !== 1) throw new Error('FROM_UNIXTIME expects 1 argument');
|
|
77
|
-
return `DATEADD(SECOND, ${compiledArgs[0]}, '1970-01-01')`;
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
this.add('END_OF_MONTH', ({ compiledArgs }) => {
|
|
81
|
-
if (compiledArgs.length !== 1) throw new Error('END_OF_MONTH expects 1 argument');
|
|
82
|
-
return `EOMONTH(${compiledArgs[0]})`;
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
this.add('DAY_OF_WEEK', ({ compiledArgs }) => {
|
|
86
|
-
if (compiledArgs.length !== 1) throw new Error('DAY_OF_WEEK expects 1 argument');
|
|
87
|
-
return `DATEPART(dw, ${compiledArgs[0]})`;
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
this.add('WEEK_OF_YEAR', ({ compiledArgs }) => {
|
|
91
|
-
if (compiledArgs.length !== 1) throw new Error('WEEK_OF_YEAR expects 1 argument');
|
|
92
|
-
return `DATEPART(wk, ${compiledArgs[0]})`;
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
this.add('DATE_TRUNC', ({ node, compiledArgs }) => {
|
|
96
|
-
if (compiledArgs.length !== 2) throw new Error('DATE_TRUNC expects 2 arguments (part, date)');
|
|
97
|
-
const [, date] = compiledArgs;
|
|
98
|
-
const partArg = node.args[0] as LiteralNode;
|
|
99
|
-
const partClean = String(partArg.value).replace(/['"]/g, '').toLowerCase();
|
|
100
|
-
// SQL Server 2022+ has DATETRUNC
|
|
101
|
-
return `DATETRUNC(${partClean}, ${date})`;
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
this.add('GROUP_CONCAT', ctx => {
|
|
105
|
-
const arg = ctx.compiledArgs[0];
|
|
106
|
-
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
107
|
-
const separator = ctx.compileOperand(separatorOperand);
|
|
108
|
-
const orderClause = this.buildOrderByExpression(ctx);
|
|
109
|
-
const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : '';
|
|
110
|
-
return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
this.add('LENGTH', ({ compiledArgs }) => `LEN(${compiledArgs[0]})`);
|
|
114
|
-
this.add('CHAR_LENGTH', ({ compiledArgs }) => `LEN(${compiledArgs[0]})`);
|
|
115
|
-
this.add('CHARACTER_LENGTH', ({ compiledArgs }) => `LEN(${compiledArgs[0]})`);
|
|
116
|
-
this.add('POSITION', ({ compiledArgs }) => `CHARINDEX(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
117
|
-
this.add('LOCATE', ({ compiledArgs }) => compiledArgs.length === 3 ? `CHARINDEX(${compiledArgs[0]}, ${compiledArgs[1]}, ${compiledArgs[2]})` : `CHARINDEX(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
118
|
-
this.add('INSTR', ({ compiledArgs }) => `CHARINDEX(${compiledArgs[1]}, ${compiledArgs[0]})`);
|
|
119
|
-
this.add('CHR', ({ compiledArgs }) => `CHAR(${compiledArgs[0]})`);
|
|
120
|
-
|
|
1
|
+
import { StandardFunctionStrategy } from '../../functions/standard-strategy.js';
|
|
2
|
+
import { LiteralNode } from '../../ast/expression.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Microsoft SQL Server specific function strategy.
|
|
6
|
+
* Implements and overrides SQL function compilation rules for MSSQL.
|
|
7
|
+
*/
|
|
8
|
+
export class MssqlFunctionStrategy extends StandardFunctionStrategy {
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
this.registerOverrides();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
private registerOverrides() {
|
|
15
|
+
// Override Standard/Abstract definitions with MSSQL specifics
|
|
16
|
+
|
|
17
|
+
// Date/Time functions
|
|
18
|
+
this.add('NOW', () => `GETDATE()`);
|
|
19
|
+
this.add('CURRENT_DATE', () => `CAST(GETDATE() AS DATE)`);
|
|
20
|
+
this.add('CURRENT_TIME', () => `CAST(GETDATE() AS TIME)`);
|
|
21
|
+
this.add('UTC_NOW', () => `GETUTCDATE()`);
|
|
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
|
+
const partClean = part.replace(/['"]/g, '').toLowerCase();
|
|
27
|
+
return `DATEPART(${partClean}, ${date})`;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
this.add('YEAR', ({ compiledArgs }) => {
|
|
31
|
+
if (compiledArgs.length !== 1) throw new Error('YEAR expects 1 argument');
|
|
32
|
+
return `YEAR(${compiledArgs[0]})`;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
this.add('MONTH', ({ compiledArgs }) => {
|
|
36
|
+
if (compiledArgs.length !== 1) throw new Error('MONTH expects 1 argument');
|
|
37
|
+
return `MONTH(${compiledArgs[0]})`;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
this.add('DAY', ({ compiledArgs }) => {
|
|
41
|
+
if (compiledArgs.length !== 1) throw new Error('DAY expects 1 argument');
|
|
42
|
+
return `DAY(${compiledArgs[0]})`;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
this.add('DATE_ADD', ({ node, compiledArgs }) => {
|
|
46
|
+
if (compiledArgs.length !== 3) throw new Error('DATE_ADD expects 3 arguments (date, interval, unit)');
|
|
47
|
+
const [date, interval] = compiledArgs;
|
|
48
|
+
const unitArg = node.args[2] as LiteralNode;
|
|
49
|
+
const unitClean = String(unitArg.value).replace(/['"]/g, '').toLowerCase();
|
|
50
|
+
return `DATEADD(${unitClean}, ${interval}, ${date})`;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
this.add('DATE_SUB', ({ node, compiledArgs }) => {
|
|
54
|
+
if (compiledArgs.length !== 3) throw new Error('DATE_SUB expects 3 arguments (date, interval, unit)');
|
|
55
|
+
const [date, interval] = compiledArgs;
|
|
56
|
+
const unitArg = node.args[2] as LiteralNode;
|
|
57
|
+
const unitClean = String(unitArg.value).replace(/['"]/g, '').toLowerCase();
|
|
58
|
+
return `DATEADD(${unitClean}, -${interval}, ${date})`;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
this.add('DATE_DIFF', ({ compiledArgs }) => {
|
|
62
|
+
if (compiledArgs.length !== 2) throw new Error('DATE_DIFF expects 2 arguments');
|
|
63
|
+
const [date1, date2] = compiledArgs;
|
|
64
|
+
return `DATEDIFF(day, ${date2}, ${date1})`;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
this.add('DATE_FORMAT', ({ compiledArgs }) => {
|
|
68
|
+
if (compiledArgs.length !== 2) throw new Error('DATE_FORMAT expects 2 arguments');
|
|
69
|
+
const [date, format] = compiledArgs;
|
|
70
|
+
return `FORMAT(${date}, ${format})`;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
this.add('UNIX_TIMESTAMP', () => `DATEDIFF(SECOND, '1970-01-01', GETUTCDATE())`);
|
|
74
|
+
|
|
75
|
+
this.add('FROM_UNIXTIME', ({ compiledArgs }) => {
|
|
76
|
+
if (compiledArgs.length !== 1) throw new Error('FROM_UNIXTIME expects 1 argument');
|
|
77
|
+
return `DATEADD(SECOND, ${compiledArgs[0]}, '1970-01-01')`;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
this.add('END_OF_MONTH', ({ compiledArgs }) => {
|
|
81
|
+
if (compiledArgs.length !== 1) throw new Error('END_OF_MONTH expects 1 argument');
|
|
82
|
+
return `EOMONTH(${compiledArgs[0]})`;
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
this.add('DAY_OF_WEEK', ({ compiledArgs }) => {
|
|
86
|
+
if (compiledArgs.length !== 1) throw new Error('DAY_OF_WEEK expects 1 argument');
|
|
87
|
+
return `DATEPART(dw, ${compiledArgs[0]})`;
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
this.add('WEEK_OF_YEAR', ({ compiledArgs }) => {
|
|
91
|
+
if (compiledArgs.length !== 1) throw new Error('WEEK_OF_YEAR expects 1 argument');
|
|
92
|
+
return `DATEPART(wk, ${compiledArgs[0]})`;
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
this.add('DATE_TRUNC', ({ node, compiledArgs }) => {
|
|
96
|
+
if (compiledArgs.length !== 2) throw new Error('DATE_TRUNC expects 2 arguments (part, date)');
|
|
97
|
+
const [, date] = compiledArgs;
|
|
98
|
+
const partArg = node.args[0] as LiteralNode;
|
|
99
|
+
const partClean = String(partArg.value).replace(/['"]/g, '').toLowerCase();
|
|
100
|
+
// SQL Server 2022+ has DATETRUNC
|
|
101
|
+
return `DATETRUNC(${partClean}, ${date})`;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
this.add('GROUP_CONCAT', ctx => {
|
|
105
|
+
const arg = ctx.compiledArgs[0];
|
|
106
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
107
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
108
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
109
|
+
const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : '';
|
|
110
|
+
return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
this.add('LENGTH', ({ compiledArgs }) => `LEN(${compiledArgs[0]})`);
|
|
114
|
+
this.add('CHAR_LENGTH', ({ compiledArgs }) => `LEN(${compiledArgs[0]})`);
|
|
115
|
+
this.add('CHARACTER_LENGTH', ({ compiledArgs }) => `LEN(${compiledArgs[0]})`);
|
|
116
|
+
this.add('POSITION', ({ compiledArgs }) => `CHARINDEX(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
117
|
+
this.add('LOCATE', ({ compiledArgs }) => compiledArgs.length === 3 ? `CHARINDEX(${compiledArgs[0]}, ${compiledArgs[1]}, ${compiledArgs[2]})` : `CHARINDEX(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
118
|
+
this.add('INSTR', ({ compiledArgs }) => `CHARINDEX(${compiledArgs[1]}, ${compiledArgs[0]})`);
|
|
119
|
+
this.add('CHR', ({ compiledArgs }) => `CHAR(${compiledArgs[0]})`);
|
|
120
|
+
|
|
121
121
|
this.add('HOUR', ({ compiledArgs }) => `DATEPART(hour, ${compiledArgs[0]})`);
|
|
122
122
|
this.add('MINUTE', ({ compiledArgs }) => `DATEPART(minute, ${compiledArgs[0]})`);
|
|
123
123
|
this.add('SECOND', ({ compiledArgs }) => `DATEPART(second, ${compiledArgs[0]})`);
|