@mikro-orm/sql 7.0.15-dev.8 → 7.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 (89) hide show
  1. package/AbstractSqlConnection.d.ts +94 -58
  2. package/AbstractSqlConnection.js +235 -238
  3. package/AbstractSqlDriver.d.ts +410 -155
  4. package/AbstractSqlDriver.js +2100 -1972
  5. package/AbstractSqlPlatform.d.ts +86 -76
  6. package/AbstractSqlPlatform.js +169 -167
  7. package/PivotCollectionPersister.d.ts +33 -15
  8. package/PivotCollectionPersister.js +158 -160
  9. package/README.md +1 -1
  10. package/SqlEntityManager.d.ts +67 -22
  11. package/SqlEntityManager.js +54 -38
  12. package/SqlEntityRepository.d.ts +14 -14
  13. package/SqlEntityRepository.js +23 -23
  14. package/SqlMikroORM.d.ts +49 -8
  15. package/SqlMikroORM.js +8 -8
  16. package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +12 -12
  17. package/dialects/mssql/MsSqlNativeQueryBuilder.js +199 -201
  18. package/dialects/mysql/BaseMySqlPlatform.d.ts +65 -46
  19. package/dialects/mysql/BaseMySqlPlatform.js +137 -134
  20. package/dialects/mysql/MySqlExceptionConverter.d.ts +6 -6
  21. package/dialects/mysql/MySqlExceptionConverter.js +91 -77
  22. package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +3 -3
  23. package/dialects/mysql/MySqlNativeQueryBuilder.js +66 -69
  24. package/dialects/mysql/MySqlSchemaHelper.d.ts +58 -39
  25. package/dialects/mysql/MySqlSchemaHelper.js +327 -319
  26. package/dialects/oracledb/OracleDialect.d.ts +81 -52
  27. package/dialects/oracledb/OracleDialect.js +155 -149
  28. package/dialects/oracledb/OracleNativeQueryBuilder.d.ts +12 -12
  29. package/dialects/oracledb/OracleNativeQueryBuilder.js +239 -243
  30. package/dialects/postgresql/BasePostgreSqlPlatform.d.ts +110 -107
  31. package/dialects/postgresql/BasePostgreSqlPlatform.js +370 -369
  32. package/dialects/postgresql/FullTextType.d.ts +10 -6
  33. package/dialects/postgresql/FullTextType.js +51 -51
  34. package/dialects/postgresql/PostgreSqlExceptionConverter.d.ts +5 -5
  35. package/dialects/postgresql/PostgreSqlExceptionConverter.js +55 -43
  36. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +1 -1
  37. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +4 -4
  38. package/dialects/postgresql/PostgreSqlSchemaHelper.d.ts +117 -82
  39. package/dialects/postgresql/PostgreSqlSchemaHelper.js +748 -712
  40. package/dialects/sqlite/BaseSqliteConnection.d.ts +3 -5
  41. package/dialects/sqlite/BaseSqliteConnection.js +21 -19
  42. package/dialects/sqlite/NodeSqliteDialect.d.ts +1 -1
  43. package/dialects/sqlite/NodeSqliteDialect.js +23 -23
  44. package/dialects/sqlite/SqliteDriver.d.ts +1 -1
  45. package/dialects/sqlite/SqliteDriver.js +3 -3
  46. package/dialects/sqlite/SqliteExceptionConverter.d.ts +6 -6
  47. package/dialects/sqlite/SqliteExceptionConverter.js +67 -51
  48. package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +2 -2
  49. package/dialects/sqlite/SqliteNativeQueryBuilder.js +7 -7
  50. package/dialects/sqlite/SqlitePlatform.d.ts +64 -73
  51. package/dialects/sqlite/SqlitePlatform.js +143 -143
  52. package/dialects/sqlite/SqliteSchemaHelper.d.ts +78 -61
  53. package/dialects/sqlite/SqliteSchemaHelper.js +541 -522
  54. package/package.json +3 -3
  55. package/plugin/index.d.ts +42 -35
  56. package/plugin/index.js +43 -36
  57. package/plugin/transformer.d.ts +137 -95
  58. package/plugin/transformer.js +1012 -881
  59. package/query/ArrayCriteriaNode.d.ts +4 -4
  60. package/query/ArrayCriteriaNode.js +18 -18
  61. package/query/CriteriaNode.d.ts +35 -25
  62. package/query/CriteriaNode.js +142 -132
  63. package/query/CriteriaNodeFactory.d.ts +49 -6
  64. package/query/CriteriaNodeFactory.js +97 -94
  65. package/query/NativeQueryBuilder.d.ts +120 -120
  66. package/query/NativeQueryBuilder.js +507 -501
  67. package/query/ObjectCriteriaNode.d.ts +12 -12
  68. package/query/ObjectCriteriaNode.js +298 -282
  69. package/query/QueryBuilder.d.ts +1558 -906
  70. package/query/QueryBuilder.js +2346 -2202
  71. package/query/QueryBuilderHelper.d.ts +153 -72
  72. package/query/QueryBuilderHelper.js +1084 -1032
  73. package/query/ScalarCriteriaNode.d.ts +3 -3
  74. package/query/ScalarCriteriaNode.js +53 -46
  75. package/query/enums.d.ts +14 -14
  76. package/query/enums.js +14 -14
  77. package/query/raw.d.ts +16 -6
  78. package/query/raw.js +10 -10
  79. package/schema/DatabaseSchema.d.ts +74 -50
  80. package/schema/DatabaseSchema.js +359 -331
  81. package/schema/DatabaseTable.d.ts +96 -73
  82. package/schema/DatabaseTable.js +1046 -974
  83. package/schema/SchemaComparator.d.ts +70 -66
  84. package/schema/SchemaComparator.js +790 -765
  85. package/schema/SchemaHelper.d.ts +128 -97
  86. package/schema/SchemaHelper.js +683 -668
  87. package/schema/SqlSchemaGenerator.d.ts +79 -59
  88. package/schema/SqlSchemaGenerator.js +525 -495
  89. package/typings.d.ts +405 -275
package/SqlMikroORM.d.ts CHANGED
@@ -1,13 +1,38 @@
1
- import { type AnyEntity, type EntityClass, type EntityManager, type EntityManagerType, type EntitySchema, type IDatabaseDriver, MikroORM, type Options } from '@mikro-orm/core';
1
+ import {
2
+ type AnyEntity,
3
+ type EntityClass,
4
+ type EntityManager,
5
+ type EntityManagerType,
6
+ type EntitySchema,
7
+ type IDatabaseDriver,
8
+ MikroORM,
9
+ type Options,
10
+ } from '@mikro-orm/core';
2
11
  import type { AbstractSqlDriver } from './AbstractSqlDriver.js';
3
12
  import type { SqlEntityManager } from './SqlEntityManager.js';
4
13
  /** Configuration options shared by all SQL drivers. */
5
- export type SqlOptions<D extends AbstractSqlDriver = AbstractSqlDriver, EM extends SqlEntityManager<D> = SqlEntityManager<D>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> = Partial<Options<D, EM, Entities>>;
14
+ export type SqlOptions<
15
+ D extends AbstractSqlDriver = AbstractSqlDriver,
16
+ EM extends SqlEntityManager<D> = SqlEntityManager<D>,
17
+ Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (
18
+ | string
19
+ | EntityClass<AnyEntity>
20
+ | EntitySchema
21
+ )[],
22
+ > = Partial<Options<D, EM, Entities>>;
6
23
  /**
7
24
  * Creates a type-safe configuration object for any SQL driver. The driver class
8
25
  * must be passed via `options.driver` (e.g. `SqliteDriver`, `MySqlDriver`, …).
9
26
  */
10
- export declare function defineSqlConfig<D extends AbstractSqlDriver = AbstractSqlDriver, EM extends SqlEntityManager<D> = SqlEntityManager<D>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: Partial<Options<D, EM, Entities>>): Partial<Options<D, EM, Entities>>;
27
+ export declare function defineSqlConfig<
28
+ D extends AbstractSqlDriver = AbstractSqlDriver,
29
+ EM extends SqlEntityManager<D> = SqlEntityManager<D>,
30
+ Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (
31
+ | string
32
+ | EntityClass<AnyEntity>
33
+ | EntitySchema
34
+ )[],
35
+ >(options: Partial<Options<D, EM, Entities>>): Partial<Options<D, EM, Entities>>;
11
36
  /**
12
37
  * Generic entry point for SQL drivers. Use this when consuming `@mikro-orm/sql`
13
38
  * directly with a Kysely dialect; for the bundled driver packages prefer
@@ -15,9 +40,25 @@ export declare function defineSqlConfig<D extends AbstractSqlDriver = AbstractSq
15
40
  *
16
41
  * @inheritDoc
17
42
  */
18
- export declare class SqlMikroORM<D extends AbstractSqlDriver = AbstractSqlDriver, EM extends SqlEntityManager<D> = SqlEntityManager<D>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> extends MikroORM<D, EM, Entities> {
19
- /**
20
- * @inheritDoc
21
- */
22
- static init<D extends IDatabaseDriver = AbstractSqlDriver, EM extends EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: Partial<Options<D, EM, Entities>>): Promise<MikroORM<D, EM, Entities>>;
43
+ export declare class SqlMikroORM<
44
+ D extends AbstractSqlDriver = AbstractSqlDriver,
45
+ EM extends SqlEntityManager<D> = SqlEntityManager<D>,
46
+ Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (
47
+ | string
48
+ | EntityClass<AnyEntity>
49
+ | EntitySchema
50
+ )[],
51
+ > extends MikroORM<D, EM, Entities> {
52
+ /**
53
+ * @inheritDoc
54
+ */
55
+ static init<
56
+ D extends IDatabaseDriver = AbstractSqlDriver,
57
+ EM extends EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>,
58
+ Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (
59
+ | string
60
+ | EntityClass<AnyEntity>
61
+ | EntitySchema
62
+ )[],
63
+ >(options: Partial<Options<D, EM, Entities>>): Promise<MikroORM<D, EM, Entities>>;
23
64
  }
package/SqlMikroORM.js CHANGED
@@ -1,10 +1,10 @@
1
- import { defineConfig, MikroORM, } from '@mikro-orm/core';
1
+ import { defineConfig, MikroORM } from '@mikro-orm/core';
2
2
  /**
3
3
  * Creates a type-safe configuration object for any SQL driver. The driver class
4
4
  * must be passed via `options.driver` (e.g. `SqliteDriver`, `MySqlDriver`, …).
5
5
  */
6
6
  export function defineSqlConfig(options) {
7
- return defineConfig(options);
7
+ return defineConfig(options);
8
8
  }
9
9
  /**
10
10
  * Generic entry point for SQL drivers. Use this when consuming `@mikro-orm/sql`
@@ -14,10 +14,10 @@ export function defineSqlConfig(options) {
14
14
  * @inheritDoc
15
15
  */
16
16
  export class SqlMikroORM extends MikroORM {
17
- /**
18
- * @inheritDoc
19
- */
20
- static async init(options) {
21
- return super.init(options);
22
- }
17
+ /**
18
+ * @inheritDoc
19
+ */
20
+ static async init(options) {
21
+ return super.init(options);
22
+ }
23
23
  }
@@ -1,16 +1,16 @@
1
1
  import { NativeQueryBuilder } from '../../query/NativeQueryBuilder.js';
2
2
  /** @internal */
3
3
  export declare class MsSqlNativeQueryBuilder extends NativeQueryBuilder {
4
- compile(): {
5
- sql: string;
6
- params: unknown[];
7
- };
8
- protected compileInsert(): void;
9
- private appendOutputTable;
10
- private compileUpsert;
11
- protected compileSelect(): void;
12
- protected addLockClause(): void;
13
- protected compileTruncate(): void;
14
- /** MSSQL has no RECURSIVE keyword — CTEs are implicitly recursive. */
15
- protected getCteKeyword(_hasRecursive: boolean): string;
4
+ compile(): {
5
+ sql: string;
6
+ params: unknown[];
7
+ };
8
+ protected compileInsert(): void;
9
+ private appendOutputTable;
10
+ private compileUpsert;
11
+ protected compileSelect(): void;
12
+ protected addLockClause(): void;
13
+ protected compileTruncate(): void;
14
+ /** MSSQL has no RECURSIVE keyword — CTEs are implicitly recursive. */
15
+ protected getCteKeyword(_hasRecursive: boolean): string;
16
16
  }
@@ -3,213 +3,211 @@ import { NativeQueryBuilder } from '../../query/NativeQueryBuilder.js';
3
3
  import { QueryType } from '../../query/enums.js';
4
4
  /** @internal */
5
5
  export class MsSqlNativeQueryBuilder extends NativeQueryBuilder {
6
- compile() {
7
- if (!this.type) {
8
- throw new Error('No query type provided');
9
- }
10
- this.parts.length = 0;
11
- this.params.length = 0;
12
- if (this.options.flags?.has(QueryFlag.IDENTITY_INSERT)) {
13
- this.parts.push(`set identity_insert ${this.getTableName()} on;`);
14
- }
15
- const { prefix, suffix } = this.appendOutputTable();
16
- if (prefix) {
17
- this.parts.push(prefix);
18
- }
19
- if (this.options.comment) {
20
- this.parts.push(...this.options.comment.map(comment => `/* ${comment} */`));
21
- }
22
- this.compileCtes();
23
- if (this.options.onConflict && !Utils.isEmpty(Utils.asArray(this.options.data)[0])) {
24
- this.compileUpsert();
25
- }
26
- else {
27
- switch (this.type) {
28
- case QueryType.SELECT:
29
- case QueryType.COUNT:
30
- this.compileSelect();
31
- break;
32
- case QueryType.INSERT:
33
- this.compileInsert();
34
- break;
35
- case QueryType.UPDATE:
36
- this.compileUpdate();
37
- break;
38
- case QueryType.DELETE:
39
- this.compileDelete();
40
- break;
41
- case QueryType.TRUNCATE:
42
- this.compileTruncate();
43
- break;
44
- }
45
- if (suffix) {
46
- this.parts[this.parts.length - 1] += ';';
47
- this.parts.push(suffix);
48
- }
49
- else if ([QueryType.INSERT, QueryType.UPDATE, QueryType.DELETE].includes(this.type)) {
50
- this.parts[this.parts.length - 1] += '; select @@rowcount;';
51
- }
52
- }
53
- if (this.options.flags?.has(QueryFlag.IDENTITY_INSERT)) {
54
- this.parts.push(`set identity_insert ${this.getTableName()} off;`);
55
- }
56
- return this.combineParts();
6
+ compile() {
7
+ if (!this.type) {
8
+ throw new Error('No query type provided');
57
9
  }
58
- compileInsert() {
59
- if (!this.options.data) {
60
- throw new Error('No data provided');
61
- }
62
- this.parts.push('insert');
63
- this.addHintComment();
64
- this.parts.push(`into ${this.getTableName()}`);
65
- if (Object.keys(this.options.data).length === 0) {
66
- this.addOutputClause('inserted');
67
- this.parts.push('default values');
68
- return;
69
- }
70
- const parts = this.processInsertData();
71
- if (this.options.flags?.has(QueryFlag.OUTPUT_TABLE)) {
72
- this.parts[this.parts.length - 2] += ' into #out ';
73
- }
74
- this.parts.push(parts.join(', '));
10
+ this.parts.length = 0;
11
+ this.params.length = 0;
12
+ if (this.options.flags?.has(QueryFlag.IDENTITY_INSERT)) {
13
+ this.parts.push(`set identity_insert ${this.getTableName()} on;`);
75
14
  }
76
- appendOutputTable() {
77
- if (!this.options.flags?.has(QueryFlag.OUTPUT_TABLE)) {
78
- return { prefix: '', suffix: '' };
79
- }
80
- const returningFields = this.options.returning;
81
- const selections = returningFields.map(field => `[t].${this.platform.quoteIdentifier(field)}`).join(',');
82
- return {
83
- prefix: `select top(0) ${selections} into #out from ${this.getTableName()} as t left join ${this.getTableName()} on 0 = 1;`,
84
- suffix: `select ${selections} from #out as t; drop table #out`,
85
- };
86
- }
87
- compileUpsert() {
88
- const clause = this.options.onConflict;
89
- const dataAsArray = Utils.asArray(this.options.data);
90
- const keys = Object.keys(dataAsArray[0]);
91
- const values = keys.map(() => '?');
92
- const parts = [];
93
- for (const data of dataAsArray) {
94
- for (const key of keys) {
95
- this.params.push(data[key]);
96
- }
97
- parts.push(`(${values.join(', ')})`);
98
- }
99
- this.parts.push(`merge into ${this.getTableName()}`);
100
- this.parts.push(`using (values ${parts.join(', ')}) as tsource(${keys.map(key => this.quote(key)).join(', ')})`);
101
- if (isRaw(clause.fields)) {
102
- this.parts.push(clause.fields.sql);
103
- this.params.push(...clause.fields.params);
104
- }
105
- else if (clause.fields.length > 0) {
106
- const fields = clause.fields.map(field => {
107
- const col = this.quote(field);
108
- return `${this.getTableName()}.${col} = tsource.${col}`;
109
- });
110
- this.parts.push(`on ${fields.join(' and ')}`);
111
- }
112
- const sourceColumns = keys.map(field => `tsource.${this.quote(field)}`).join(', ');
113
- const destinationColumns = keys.map(field => this.quote(field)).join(', ');
114
- this.parts.push(`when not matched then insert (${destinationColumns}) values (${sourceColumns})`);
115
- if (!clause.ignore) {
116
- this.parts.push('when matched');
117
- if (clause.where) {
118
- this.parts.push(`and ${clause.where.sql}`);
119
- this.params.push(...clause.where.params);
120
- }
121
- this.parts.push('then update set');
122
- if (!clause.merge || Array.isArray(clause.merge)) {
123
- const parts = (clause.merge || keys)
124
- .filter(field => !Array.isArray(clause.fields) || !clause.fields.includes(field))
125
- .map((column) => `${this.quote(column)} = tsource.${this.quote(column)}`);
126
- this.parts.push(parts.join(', '));
127
- }
128
- else if (typeof clause.merge === 'object') {
129
- const parts = Object.entries(clause.merge).map(([key, value]) => {
130
- this.params.push(value);
131
- return `${this.getTableName()}.${this.quote(key)} = ?`;
132
- });
133
- this.parts.push(parts.join(', '));
134
- }
135
- }
136
- this.addOutputClause('inserted');
15
+ const { prefix, suffix } = this.appendOutputTable();
16
+ if (prefix) {
17
+ this.parts.push(prefix);
18
+ }
19
+ if (this.options.comment) {
20
+ this.parts.push(...this.options.comment.map(comment => `/* ${comment} */`));
21
+ }
22
+ this.compileCtes();
23
+ if (this.options.onConflict && !Utils.isEmpty(Utils.asArray(this.options.data)[0])) {
24
+ this.compileUpsert();
25
+ } else {
26
+ switch (this.type) {
27
+ case QueryType.SELECT:
28
+ case QueryType.COUNT:
29
+ this.compileSelect();
30
+ break;
31
+ case QueryType.INSERT:
32
+ this.compileInsert();
33
+ break;
34
+ case QueryType.UPDATE:
35
+ this.compileUpdate();
36
+ break;
37
+ case QueryType.DELETE:
38
+ this.compileDelete();
39
+ break;
40
+ case QueryType.TRUNCATE:
41
+ this.compileTruncate();
42
+ break;
43
+ }
44
+ if (suffix) {
137
45
  this.parts[this.parts.length - 1] += ';';
46
+ this.parts.push(suffix);
47
+ } else if ([QueryType.INSERT, QueryType.UPDATE, QueryType.DELETE].includes(this.type)) {
48
+ this.parts[this.parts.length - 1] += '; select @@rowcount;';
49
+ }
138
50
  }
139
- compileSelect() {
140
- const wrapCountSubquery = this.needsCountSubquery();
141
- if (wrapCountSubquery) {
142
- this.parts.push(`select count(*) as ${this.quote('count')} from (`);
143
- }
144
- this.parts.push('select');
145
- // skip top(?) inside the count subquery — it would limit the distinct rows before counting
146
- if (this.options.limit != null && this.options.offset == null && !wrapCountSubquery) {
147
- this.parts.push(`top (?)`);
148
- this.params.push(this.options.limit);
149
- }
150
- this.addHintComment();
151
- this.parts.push(`${this.getFields(wrapCountSubquery)} from ${this.getTableName()}`);
152
- this.addLockClause();
153
- if (this.options.joins) {
154
- for (const join of this.options.joins) {
155
- this.parts.push(join.sql);
156
- this.params.push(...join.params);
157
- }
158
- }
159
- if (this.options.where?.sql.trim()) {
160
- this.parts.push(`where ${this.options.where.sql}`);
161
- this.params.push(...this.options.where.params);
162
- }
163
- if (this.options.groupBy) {
164
- const fields = this.options.groupBy.map(field => this.quote(field));
165
- this.parts.push(`group by ${fields.join(', ')}`);
166
- }
167
- if (this.options.having) {
168
- this.parts.push(`having ${this.options.having.sql}`);
169
- this.params.push(...this.options.having.params);
170
- }
171
- if (!wrapCountSubquery) {
172
- if (this.options.orderBy) {
173
- this.parts.push(`order by ${this.options.orderBy}`);
174
- }
175
- if (this.options.offset != null) {
176
- /* v8 ignore next */
177
- if (!this.options.orderBy) {
178
- throw new Error('Order by clause is required for pagination');
179
- }
180
- this.parts.push(`offset ? rows`);
181
- this.params.push(this.options.offset);
182
- if (this.options.limit != null) {
183
- this.parts.push(`fetch next ? rows only`);
184
- this.params.push(this.options.limit);
185
- }
186
- }
187
- }
188
- if (wrapCountSubquery) {
189
- const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
190
- this.parts.push(`)${asKeyword}${this.quote('dcnt')}`);
191
- }
51
+ if (this.options.flags?.has(QueryFlag.IDENTITY_INSERT)) {
52
+ this.parts.push(`set identity_insert ${this.getTableName()} off;`);
192
53
  }
193
- addLockClause() {
194
- if (!this.options.lockMode ||
195
- ![LockMode.PESSIMISTIC_READ, LockMode.PESSIMISTIC_WRITE].includes(this.options.lockMode)) {
196
- return;
197
- }
198
- const map = {
199
- [LockMode.PESSIMISTIC_READ]: 'with (holdlock)',
200
- [LockMode.PESSIMISTIC_WRITE]: 'with (updlock)',
201
- };
202
- if (this.options.lockMode !== LockMode.OPTIMISTIC) {
203
- this.parts.push(map[this.options.lockMode]);
204
- }
54
+ return this.combineParts();
55
+ }
56
+ compileInsert() {
57
+ if (!this.options.data) {
58
+ throw new Error('No data provided');
59
+ }
60
+ this.parts.push('insert');
61
+ this.addHintComment();
62
+ this.parts.push(`into ${this.getTableName()}`);
63
+ if (Object.keys(this.options.data).length === 0) {
64
+ this.addOutputClause('inserted');
65
+ this.parts.push('default values');
66
+ return;
67
+ }
68
+ const parts = this.processInsertData();
69
+ if (this.options.flags?.has(QueryFlag.OUTPUT_TABLE)) {
70
+ this.parts[this.parts.length - 2] += ' into #out ';
71
+ }
72
+ this.parts.push(parts.join(', '));
73
+ }
74
+ appendOutputTable() {
75
+ if (!this.options.flags?.has(QueryFlag.OUTPUT_TABLE)) {
76
+ return { prefix: '', suffix: '' };
77
+ }
78
+ const returningFields = this.options.returning;
79
+ const selections = returningFields.map(field => `[t].${this.platform.quoteIdentifier(field)}`).join(',');
80
+ return {
81
+ prefix: `select top(0) ${selections} into #out from ${this.getTableName()} as t left join ${this.getTableName()} on 0 = 1;`,
82
+ suffix: `select ${selections} from #out as t; drop table #out`,
83
+ };
84
+ }
85
+ compileUpsert() {
86
+ const clause = this.options.onConflict;
87
+ const dataAsArray = Utils.asArray(this.options.data);
88
+ const keys = Object.keys(dataAsArray[0]);
89
+ const values = keys.map(() => '?');
90
+ const parts = [];
91
+ for (const data of dataAsArray) {
92
+ for (const key of keys) {
93
+ this.params.push(data[key]);
94
+ }
95
+ parts.push(`(${values.join(', ')})`);
96
+ }
97
+ this.parts.push(`merge into ${this.getTableName()}`);
98
+ this.parts.push(`using (values ${parts.join(', ')}) as tsource(${keys.map(key => this.quote(key)).join(', ')})`);
99
+ if (isRaw(clause.fields)) {
100
+ this.parts.push(clause.fields.sql);
101
+ this.params.push(...clause.fields.params);
102
+ } else if (clause.fields.length > 0) {
103
+ const fields = clause.fields.map(field => {
104
+ const col = this.quote(field);
105
+ return `${this.getTableName()}.${col} = tsource.${col}`;
106
+ });
107
+ this.parts.push(`on ${fields.join(' and ')}`);
108
+ }
109
+ const sourceColumns = keys.map(field => `tsource.${this.quote(field)}`).join(', ');
110
+ const destinationColumns = keys.map(field => this.quote(field)).join(', ');
111
+ this.parts.push(`when not matched then insert (${destinationColumns}) values (${sourceColumns})`);
112
+ if (!clause.ignore) {
113
+ this.parts.push('when matched');
114
+ if (clause.where) {
115
+ this.parts.push(`and ${clause.where.sql}`);
116
+ this.params.push(...clause.where.params);
117
+ }
118
+ this.parts.push('then update set');
119
+ if (!clause.merge || Array.isArray(clause.merge)) {
120
+ const parts = (clause.merge || keys)
121
+ .filter(field => !Array.isArray(clause.fields) || !clause.fields.includes(field))
122
+ .map(column => `${this.quote(column)} = tsource.${this.quote(column)}`);
123
+ this.parts.push(parts.join(', '));
124
+ } else if (typeof clause.merge === 'object') {
125
+ const parts = Object.entries(clause.merge).map(([key, value]) => {
126
+ this.params.push(value);
127
+ return `${this.getTableName()}.${this.quote(key)} = ?`;
128
+ });
129
+ this.parts.push(parts.join(', '));
130
+ }
131
+ }
132
+ this.addOutputClause('inserted');
133
+ this.parts[this.parts.length - 1] += ';';
134
+ }
135
+ compileSelect() {
136
+ const wrapCountSubquery = this.needsCountSubquery();
137
+ if (wrapCountSubquery) {
138
+ this.parts.push(`select count(*) as ${this.quote('count')} from (`);
139
+ }
140
+ this.parts.push('select');
141
+ // skip top(?) inside the count subquery — it would limit the distinct rows before counting
142
+ if (this.options.limit != null && this.options.offset == null && !wrapCountSubquery) {
143
+ this.parts.push(`top (?)`);
144
+ this.params.push(this.options.limit);
145
+ }
146
+ this.addHintComment();
147
+ this.parts.push(`${this.getFields(wrapCountSubquery)} from ${this.getTableName()}`);
148
+ this.addLockClause();
149
+ if (this.options.joins) {
150
+ for (const join of this.options.joins) {
151
+ this.parts.push(join.sql);
152
+ this.params.push(...join.params);
153
+ }
154
+ }
155
+ if (this.options.where?.sql.trim()) {
156
+ this.parts.push(`where ${this.options.where.sql}`);
157
+ this.params.push(...this.options.where.params);
158
+ }
159
+ if (this.options.groupBy) {
160
+ const fields = this.options.groupBy.map(field => this.quote(field));
161
+ this.parts.push(`group by ${fields.join(', ')}`);
162
+ }
163
+ if (this.options.having) {
164
+ this.parts.push(`having ${this.options.having.sql}`);
165
+ this.params.push(...this.options.having.params);
166
+ }
167
+ if (!wrapCountSubquery) {
168
+ if (this.options.orderBy) {
169
+ this.parts.push(`order by ${this.options.orderBy}`);
170
+ }
171
+ if (this.options.offset != null) {
172
+ /* v8 ignore next */
173
+ if (!this.options.orderBy) {
174
+ throw new Error('Order by clause is required for pagination');
175
+ }
176
+ this.parts.push(`offset ? rows`);
177
+ this.params.push(this.options.offset);
178
+ if (this.options.limit != null) {
179
+ this.parts.push(`fetch next ? rows only`);
180
+ this.params.push(this.options.limit);
181
+ }
182
+ }
183
+ }
184
+ if (wrapCountSubquery) {
185
+ const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
186
+ this.parts.push(`)${asKeyword}${this.quote('dcnt')}`);
205
187
  }
206
- compileTruncate() {
207
- const tableName = this.getTableName();
208
- const sql = `delete from ${tableName}; declare @count int = case @@rowcount when 0 then 1 else 0 end; dbcc checkident ('${tableName.replace(/[[\]]/g, '')}', reseed, @count)`;
209
- this.parts.push(sql);
188
+ }
189
+ addLockClause() {
190
+ if (
191
+ !this.options.lockMode ||
192
+ ![LockMode.PESSIMISTIC_READ, LockMode.PESSIMISTIC_WRITE].includes(this.options.lockMode)
193
+ ) {
194
+ return;
210
195
  }
211
- /** MSSQL has no RECURSIVE keyword — CTEs are implicitly recursive. */
212
- getCteKeyword(_hasRecursive) {
213
- return 'with';
196
+ const map = {
197
+ [LockMode.PESSIMISTIC_READ]: 'with (holdlock)',
198
+ [LockMode.PESSIMISTIC_WRITE]: 'with (updlock)',
199
+ };
200
+ if (this.options.lockMode !== LockMode.OPTIMISTIC) {
201
+ this.parts.push(map[this.options.lockMode]);
214
202
  }
203
+ }
204
+ compileTruncate() {
205
+ const tableName = this.getTableName();
206
+ const sql = `delete from ${tableName}; declare @count int = case @@rowcount when 0 then 1 else 0 end; dbcc checkident ('${tableName.replace(/[[\]]/g, '')}', reseed, @count)`;
207
+ this.parts.push(sql);
208
+ }
209
+ /** MSSQL has no RECURSIVE keyword — CTEs are implicitly recursive. */
210
+ getCteKeyword(_hasRecursive) {
211
+ return 'with';
212
+ }
215
213
  }
@@ -1,53 +1,72 @@
1
- import { type SimpleColumnMeta, type Type, type TransformContext, type MikroORM, type IsolationLevel } from '@mikro-orm/core';
1
+ import {
2
+ type SimpleColumnMeta,
3
+ type Type,
4
+ type TransformContext,
5
+ type MikroORM,
6
+ type IsolationLevel,
7
+ } from '@mikro-orm/core';
2
8
  import { MySqlSchemaHelper } from './MySqlSchemaHelper.js';
3
9
  import { MySqlExceptionConverter } from './MySqlExceptionConverter.js';
4
10
  import { AbstractSqlPlatform } from '../../AbstractSqlPlatform.js';
5
11
  import type { IndexDef } from '../../typings.js';
6
12
  import { MySqlNativeQueryBuilder } from './MySqlNativeQueryBuilder.js';
7
13
  export declare class BaseMySqlPlatform extends AbstractSqlPlatform {
8
- #private;
9
- protected readonly schemaHelper: MySqlSchemaHelper;
10
- protected readonly exceptionConverter: MySqlExceptionConverter;
11
- protected readonly ORDER_BY_NULLS_TRANSLATE: {
12
- readonly "asc nulls first": "is not null";
13
- readonly "asc nulls last": "is null";
14
- readonly "desc nulls first": "is not null";
15
- readonly "desc nulls last": "is null";
16
- };
17
- supportsMultiColumnCountDistinct(): boolean;
18
- /** @internal */
19
- createNativeQueryBuilder(): MySqlNativeQueryBuilder;
20
- getDefaultCharset(): string;
21
- init(orm: MikroORM): void;
22
- getBeginTransactionSQL(options?: {
23
- isolationLevel?: IsolationLevel;
24
- readOnly?: boolean;
25
- }): string[];
26
- convertJsonToDatabaseValue(value: unknown, context?: TransformContext): unknown;
27
- getJsonIndexDefinition(index: IndexDef): string[];
28
- getBooleanTypeDeclarationSQL(): string;
29
- normalizeColumnType(type: string, options: {
30
- length?: number;
31
- precision?: number;
32
- scale?: number;
33
- }): string;
34
- getDefaultMappedType(type: string): Type<unknown>;
35
- isNumericColumn(mappedType: Type<unknown>): boolean;
36
- supportsUnsigned(): boolean;
37
- /**
38
- * Returns the default name of index for the given columns
39
- * cannot go past 64 character length for identifiers in MySQL
40
- */
41
- getIndexName(tableName: string, columns: string[], type: 'index' | 'unique' | 'foreign' | 'primary' | 'sequence'): string;
42
- getDefaultPrimaryName(tableName: string, columns: string[]): string;
43
- supportsCreatingFullTextIndex(): boolean;
44
- getFullTextWhereClause(): string;
45
- getFullTextIndexExpression(indexName: string, schemaName: string | undefined, tableName: string, columns: SimpleColumnMeta[]): string;
46
- getOrderByExpression(column: string, direction: string, collation?: string): string[];
47
- getJsonArrayFromSQL(column: string, alias: string, properties: {
48
- name: string;
49
- type: string;
50
- }[]): string;
51
- getJsonArrayExistsSQL(from: string, where: string): string;
52
- getDefaultClientUrl(): string;
14
+ #private;
15
+ protected readonly schemaHelper: MySqlSchemaHelper;
16
+ protected readonly exceptionConverter: MySqlExceptionConverter;
17
+ protected readonly ORDER_BY_NULLS_TRANSLATE: {
18
+ readonly 'asc nulls first': 'is not null';
19
+ readonly 'asc nulls last': 'is null';
20
+ readonly 'desc nulls first': 'is not null';
21
+ readonly 'desc nulls last': 'is null';
22
+ };
23
+ supportsMultiColumnCountDistinct(): boolean;
24
+ /** @internal */
25
+ createNativeQueryBuilder(): MySqlNativeQueryBuilder;
26
+ getDefaultCharset(): string;
27
+ init(orm: MikroORM): void;
28
+ getBeginTransactionSQL(options?: { isolationLevel?: IsolationLevel; readOnly?: boolean }): string[];
29
+ convertJsonToDatabaseValue(value: unknown, context?: TransformContext): unknown;
30
+ getJsonIndexDefinition(index: IndexDef): string[];
31
+ getBooleanTypeDeclarationSQL(): string;
32
+ normalizeColumnType(
33
+ type: string,
34
+ options: {
35
+ length?: number;
36
+ precision?: number;
37
+ scale?: number;
38
+ },
39
+ ): string;
40
+ getDefaultMappedType(type: string): Type<unknown>;
41
+ isNumericColumn(mappedType: Type<unknown>): boolean;
42
+ supportsUnsigned(): boolean;
43
+ /**
44
+ * Returns the default name of index for the given columns
45
+ * cannot go past 64 character length for identifiers in MySQL
46
+ */
47
+ getIndexName(
48
+ tableName: string,
49
+ columns: string[],
50
+ type: 'index' | 'unique' | 'foreign' | 'primary' | 'sequence',
51
+ ): string;
52
+ getDefaultPrimaryName(tableName: string, columns: string[]): string;
53
+ supportsCreatingFullTextIndex(): boolean;
54
+ getFullTextWhereClause(): string;
55
+ getFullTextIndexExpression(
56
+ indexName: string,
57
+ schemaName: string | undefined,
58
+ tableName: string,
59
+ columns: SimpleColumnMeta[],
60
+ ): string;
61
+ getOrderByExpression(column: string, direction: string, collation?: string): string[];
62
+ getJsonArrayFromSQL(
63
+ column: string,
64
+ alias: string,
65
+ properties: {
66
+ name: string;
67
+ type: string;
68
+ }[],
69
+ ): string;
70
+ getJsonArrayExistsSQL(from: string, where: string): string;
71
+ getDefaultClientUrl(): string;
53
72
  }