@mikro-orm/sql 7.0.7-dev.2 → 7.0.7-dev.20
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/AbstractSqlPlatform.d.ts +2 -0
- package/AbstractSqlPlatform.js +4 -0
- package/dialects/mssql/MsSqlNativeQueryBuilder.js +25 -14
- package/dialects/mysql/BaseMySqlPlatform.d.ts +1 -0
- package/dialects/mysql/BaseMySqlPlatform.js +3 -0
- package/dialects/mysql/MySqlSchemaHelper.d.ts +8 -8
- package/dialects/mysql/MySqlSchemaHelper.js +22 -22
- package/dialects/oracledb/OracleNativeQueryBuilder.js +20 -10
- package/dialects/postgresql/PostgreSqlSchemaHelper.d.ts +10 -10
- package/dialects/postgresql/PostgreSqlSchemaHelper.js +38 -26
- package/dialects/sqlite/SqliteSchemaHelper.d.ts +6 -6
- package/dialects/sqlite/SqliteSchemaHelper.js +38 -38
- package/package.json +3 -3
- package/query/NativeQueryBuilder.d.ts +3 -1
- package/query/NativeQueryBuilder.js +32 -11
- package/query/QueryBuilderHelper.js +1 -1
- package/schema/DatabaseSchema.d.ts +2 -2
- package/schema/DatabaseSchema.js +26 -6
- package/schema/SchemaComparator.d.ts +1 -1
- package/schema/SchemaComparator.js +29 -4
- package/schema/SchemaHelper.d.ts +8 -7
- package/schema/SchemaHelper.js +15 -7
- package/schema/SqlSchemaGenerator.d.ts +1 -0
- package/schema/SqlSchemaGenerator.js +21 -25
- package/typings.d.ts +7 -2
package/AbstractSqlPlatform.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export declare abstract class AbstractSqlPlatform extends Platform {
|
|
|
36
36
|
quoteJsonKey(key: string): string;
|
|
37
37
|
getJsonIndexDefinition(index: IndexDef): string[];
|
|
38
38
|
supportsUnionWhere(): boolean;
|
|
39
|
+
/** Whether the platform supports `count(distinct col1, col2)` with multiple columns. If false, a subquery wrapper is used instead. */
|
|
40
|
+
supportsMultiColumnCountDistinct(): boolean;
|
|
39
41
|
supportsSchemas(): boolean;
|
|
40
42
|
/** @inheritDoc */
|
|
41
43
|
generateCustomOrder(escapedColumn: string, values: unknown[]): string;
|
package/AbstractSqlPlatform.js
CHANGED
|
@@ -91,6 +91,10 @@ export class AbstractSqlPlatform extends Platform {
|
|
|
91
91
|
supportsUnionWhere() {
|
|
92
92
|
return true;
|
|
93
93
|
}
|
|
94
|
+
/** Whether the platform supports `count(distinct col1, col2)` with multiple columns. If false, a subquery wrapper is used instead. */
|
|
95
|
+
supportsMultiColumnCountDistinct() {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
94
98
|
supportsSchemas() {
|
|
95
99
|
return false;
|
|
96
100
|
}
|
|
@@ -137,13 +137,18 @@ export class MsSqlNativeQueryBuilder extends NativeQueryBuilder {
|
|
|
137
137
|
this.parts[this.parts.length - 1] += ';';
|
|
138
138
|
}
|
|
139
139
|
compileSelect() {
|
|
140
|
+
const wrapCountSubquery = this.needsCountSubquery();
|
|
141
|
+
if (wrapCountSubquery) {
|
|
142
|
+
this.parts.push(`select count(*) as ${this.quote('count')} from (`);
|
|
143
|
+
}
|
|
140
144
|
this.parts.push('select');
|
|
141
|
-
|
|
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) {
|
|
142
147
|
this.parts.push(`top (?)`);
|
|
143
148
|
this.params.push(this.options.limit);
|
|
144
149
|
}
|
|
145
150
|
this.addHintComment();
|
|
146
|
-
this.parts.push(`${this.getFields()} from ${this.getTableName()}`);
|
|
151
|
+
this.parts.push(`${this.getFields(wrapCountSubquery)} from ${this.getTableName()}`);
|
|
147
152
|
this.addLockClause();
|
|
148
153
|
if (this.options.joins) {
|
|
149
154
|
for (const join of this.options.joins) {
|
|
@@ -163,21 +168,27 @@ export class MsSqlNativeQueryBuilder extends NativeQueryBuilder {
|
|
|
163
168
|
this.parts.push(`having ${this.options.having.sql}`);
|
|
164
169
|
this.params.push(...this.options.having.params);
|
|
165
170
|
}
|
|
166
|
-
if (
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (this.options.offset != null) {
|
|
170
|
-
/* v8 ignore next */
|
|
171
|
-
if (!this.options.orderBy) {
|
|
172
|
-
throw new Error('Order by clause is required for pagination');
|
|
171
|
+
if (!wrapCountSubquery) {
|
|
172
|
+
if (this.options.orderBy) {
|
|
173
|
+
this.parts.push(`order by ${this.options.orderBy}`);
|
|
173
174
|
}
|
|
174
|
-
this.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
+
}
|
|
179
186
|
}
|
|
180
187
|
}
|
|
188
|
+
if (wrapCountSubquery) {
|
|
189
|
+
const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
|
|
190
|
+
this.parts.push(`)${asKeyword}${this.quote('dcnt')}`);
|
|
191
|
+
}
|
|
181
192
|
}
|
|
182
193
|
addLockClause() {
|
|
183
194
|
if (!this.options.lockMode ||
|
|
@@ -14,6 +14,7 @@ export declare class BaseMySqlPlatform extends AbstractSqlPlatform {
|
|
|
14
14
|
readonly "desc nulls first": "is not null";
|
|
15
15
|
readonly "desc nulls last": "is null";
|
|
16
16
|
};
|
|
17
|
+
supportsMultiColumnCountDistinct(): boolean;
|
|
17
18
|
/** @internal */
|
|
18
19
|
createNativeQueryBuilder(): MySqlNativeQueryBuilder;
|
|
19
20
|
getDefaultCharset(): string;
|
|
@@ -18,6 +18,9 @@ export class BaseMySqlPlatform extends AbstractSqlPlatform {
|
|
|
18
18
|
[QueryOrder.desc_nulls_first]: 'is not null',
|
|
19
19
|
[QueryOrder.desc_nulls_last]: 'is null',
|
|
20
20
|
};
|
|
21
|
+
supportsMultiColumnCountDistinct() {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
21
24
|
/** @internal */
|
|
22
25
|
createNativeQueryBuilder() {
|
|
23
26
|
return new MySqlNativeQueryBuilder(this);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Dictionary, type Type } from '@mikro-orm/core';
|
|
1
|
+
import { type Dictionary, type Transaction, type Type } from '@mikro-orm/core';
|
|
2
2
|
import type { CheckDef, Column, ForeignKey, IndexDef, Table, TableDifference } from '../../typings.js';
|
|
3
3
|
import type { AbstractSqlConnection } from '../../AbstractSqlConnection.js';
|
|
4
4
|
import { SchemaHelper } from '../../schema/SchemaHelper.js';
|
|
@@ -17,9 +17,9 @@ export declare class MySqlSchemaHelper extends SchemaHelper {
|
|
|
17
17
|
finalizeTable(table: DatabaseTable, charset: string, collate?: string): string;
|
|
18
18
|
getListTablesSQL(): string;
|
|
19
19
|
getListViewsSQL(): string;
|
|
20
|
-
loadViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string): Promise<void>;
|
|
21
|
-
loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[]): Promise<void>;
|
|
22
|
-
getAllIndexes(connection: AbstractSqlConnection, tables: Table[]): Promise<Dictionary<IndexDef[]>>;
|
|
20
|
+
loadViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string, ctx?: Transaction): Promise<void>;
|
|
21
|
+
loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[], ctx?: Transaction): Promise<void>;
|
|
22
|
+
getAllIndexes(connection: AbstractSqlConnection, tables: Table[], ctx?: Transaction): Promise<Dictionary<IndexDef[]>>;
|
|
23
23
|
getCreateIndexSQL(tableName: string, index: IndexDef, partialExpression?: boolean): string;
|
|
24
24
|
/**
|
|
25
25
|
* Build the column list for a MySQL index, with MySQL-specific handling for collation.
|
|
@@ -30,16 +30,16 @@ export declare class MySqlSchemaHelper extends SchemaHelper {
|
|
|
30
30
|
* Append MySQL-specific index suffixes like INVISIBLE.
|
|
31
31
|
*/
|
|
32
32
|
protected appendMySqlIndexSuffix(sql: string, index: IndexDef): string;
|
|
33
|
-
getAllColumns(connection: AbstractSqlConnection, tables: Table[]): Promise<Dictionary<Column[]>>;
|
|
34
|
-
getAllChecks(connection: AbstractSqlConnection, tables: Table[]): Promise<Dictionary<CheckDef[]>>;
|
|
35
|
-
getAllForeignKeys(connection: AbstractSqlConnection, tables: Table[]): Promise<Dictionary<Dictionary<ForeignKey>>>;
|
|
33
|
+
getAllColumns(connection: AbstractSqlConnection, tables: Table[], ctx?: Transaction): Promise<Dictionary<Column[]>>;
|
|
34
|
+
getAllChecks(connection: AbstractSqlConnection, tables: Table[], ctx?: Transaction): Promise<Dictionary<CheckDef[]>>;
|
|
35
|
+
getAllForeignKeys(connection: AbstractSqlConnection, tables: Table[], ctx?: Transaction): Promise<Dictionary<Dictionary<ForeignKey>>>;
|
|
36
36
|
getPreAlterTable(tableDiff: TableDifference, safe: boolean): string[];
|
|
37
37
|
getRenameColumnSQL(tableName: string, oldColumnName: string, to: Column): string;
|
|
38
38
|
getRenameIndexSQL(tableName: string, index: IndexDef, oldIndexName: string): string[];
|
|
39
39
|
getChangeColumnCommentSQL(tableName: string, to: Column, schemaName?: string): string;
|
|
40
40
|
alterTableColumn(column: Column, table: DatabaseTable, changedProperties: Set<string>): string[];
|
|
41
41
|
private getColumnDeclarationSQL;
|
|
42
|
-
getAllEnumDefinitions(connection: AbstractSqlConnection, tables: Table[]): Promise<Dictionary<Dictionary<string[]>>>;
|
|
42
|
+
getAllEnumDefinitions(connection: AbstractSqlConnection, tables: Table[], ctx?: Transaction): Promise<Dictionary<Dictionary<string[]>>>;
|
|
43
43
|
private supportsCheckConstraints;
|
|
44
44
|
protected getChecksSQL(tables: Table[]): string;
|
|
45
45
|
normalizeDefaultValue(defaultValue: string, length: number): string | number;
|
|
@@ -36,14 +36,14 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
36
36
|
getListViewsSQL() {
|
|
37
37
|
return `select table_name as view_name, nullif(table_schema, schema()) as schema_name, view_definition from information_schema.views where table_schema = schema()`;
|
|
38
38
|
}
|
|
39
|
-
async loadViews(schema, connection, schemaName) {
|
|
40
|
-
const views = await connection.execute(this.getListViewsSQL());
|
|
39
|
+
async loadViews(schema, connection, schemaName, ctx) {
|
|
40
|
+
const views = await connection.execute(this.getListViewsSQL(), [], 'all', ctx);
|
|
41
41
|
for (const view of views) {
|
|
42
42
|
// MySQL information_schema.views.view_definition requires SHOW VIEW privilege
|
|
43
43
|
// and may return NULL. Use SHOW CREATE VIEW as fallback.
|
|
44
44
|
let definition = view.view_definition?.trim();
|
|
45
45
|
if (!definition) {
|
|
46
|
-
const createView = await connection.execute(`show create view \`${view.view_name}
|
|
46
|
+
const createView = await connection.execute(`show create view \`${view.view_name}\``, [], 'all', ctx);
|
|
47
47
|
if (createView[0]?.['Create View']) {
|
|
48
48
|
// Extract SELECT statement from CREATE VIEW ... AS SELECT ...
|
|
49
49
|
const match = /\bAS\s+(.+)$/is.exec(createView[0]['Create View']);
|
|
@@ -55,15 +55,15 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
async loadInformationSchema(schema, connection, tables) {
|
|
58
|
+
async loadInformationSchema(schema, connection, tables, schemas, ctx) {
|
|
59
59
|
if (tables.length === 0) {
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
|
-
const columns = await this.getAllColumns(connection, tables);
|
|
63
|
-
const indexes = await this.getAllIndexes(connection, tables);
|
|
64
|
-
const checks = await this.getAllChecks(connection, tables);
|
|
65
|
-
const fks = await this.getAllForeignKeys(connection, tables);
|
|
66
|
-
const enums = await this.getAllEnumDefinitions(connection, tables);
|
|
62
|
+
const columns = await this.getAllColumns(connection, tables, ctx);
|
|
63
|
+
const indexes = await this.getAllIndexes(connection, tables, ctx);
|
|
64
|
+
const checks = await this.getAllChecks(connection, tables, ctx);
|
|
65
|
+
const fks = await this.getAllForeignKeys(connection, tables, ctx);
|
|
66
|
+
const enums = await this.getAllEnumDefinitions(connection, tables, ctx);
|
|
67
67
|
for (const t of tables) {
|
|
68
68
|
const key = this.getTableKey(t);
|
|
69
69
|
const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
|
|
@@ -71,12 +71,12 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
71
71
|
table.init(columns[key], indexes[key], checks[key], pks, fks[key], enums[key]);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
async getAllIndexes(connection, tables) {
|
|
74
|
+
async getAllIndexes(connection, tables, ctx) {
|
|
75
75
|
const sql = `select table_name as table_name, nullif(table_schema, schema()) as schema_name, index_name as index_name, non_unique as non_unique, column_name as column_name, index_type as index_type, sub_part as sub_part, collation as sort_order /*!80013 , expression as expression, is_visible as is_visible */
|
|
76
76
|
from information_schema.statistics where table_schema = database()
|
|
77
77
|
and table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(', ')})
|
|
78
78
|
order by schema_name, table_name, index_name, seq_in_index`;
|
|
79
|
-
const allIndexes = await connection.execute(sql);
|
|
79
|
+
const allIndexes = await connection.execute(sql, [], 'all', ctx);
|
|
80
80
|
const ret = {};
|
|
81
81
|
for (const index of allIndexes) {
|
|
82
82
|
const key = this.getTableKey(index);
|
|
@@ -191,7 +191,7 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
191
191
|
}
|
|
192
192
|
return sql;
|
|
193
193
|
}
|
|
194
|
-
async getAllColumns(connection, tables) {
|
|
194
|
+
async getAllColumns(connection, tables, ctx) {
|
|
195
195
|
const sql = `select table_name as table_name,
|
|
196
196
|
nullif(table_schema, schema()) as schema_name,
|
|
197
197
|
column_name as column_name,
|
|
@@ -208,7 +208,7 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
208
208
|
ifnull(datetime_precision, character_maximum_length) length
|
|
209
209
|
from information_schema.columns where table_schema = database() and table_name in (${tables.map(t => this.platform.quoteValue(t.table_name))})
|
|
210
210
|
order by ordinal_position`;
|
|
211
|
-
const allColumns = await connection.execute(sql);
|
|
211
|
+
const allColumns = await connection.execute(sql, [], 'all', ctx);
|
|
212
212
|
const str = (val) => (val != null ? '' + val : val);
|
|
213
213
|
const extra = (val) => val.replace(/auto_increment|default_generated|(stored|virtual) generated/i, '').trim() || undefined;
|
|
214
214
|
const ret = {};
|
|
@@ -244,13 +244,13 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
244
244
|
}
|
|
245
245
|
return ret;
|
|
246
246
|
}
|
|
247
|
-
async getAllChecks(connection, tables) {
|
|
247
|
+
async getAllChecks(connection, tables, ctx) {
|
|
248
248
|
/* v8 ignore next */
|
|
249
|
-
if (!(await this.supportsCheckConstraints(connection))) {
|
|
249
|
+
if (!(await this.supportsCheckConstraints(connection, ctx))) {
|
|
250
250
|
return {};
|
|
251
251
|
}
|
|
252
252
|
const sql = this.getChecksSQL(tables);
|
|
253
|
-
const allChecks = await connection.execute(sql);
|
|
253
|
+
const allChecks = await connection.execute(sql, [], 'all', ctx);
|
|
254
254
|
const ret = {};
|
|
255
255
|
for (const check of allChecks) {
|
|
256
256
|
const key = this.getTableKey(check);
|
|
@@ -264,14 +264,14 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
264
264
|
}
|
|
265
265
|
return ret;
|
|
266
266
|
}
|
|
267
|
-
async getAllForeignKeys(connection, tables) {
|
|
267
|
+
async getAllForeignKeys(connection, tables, ctx) {
|
|
268
268
|
const sql = `select k.constraint_name as constraint_name, nullif(k.table_schema, schema()) as schema_name, k.table_name as table_name, k.column_name as column_name, k.referenced_table_name as referenced_table_name, k.referenced_column_name as referenced_column_name, c.update_rule as update_rule, c.delete_rule as delete_rule
|
|
269
269
|
from information_schema.key_column_usage k
|
|
270
270
|
inner join information_schema.referential_constraints c on c.constraint_name = k.constraint_name and c.table_name = k.table_name
|
|
271
271
|
where k.table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(', ')})
|
|
272
272
|
and k.table_schema = database() and c.constraint_schema = database() and k.referenced_column_name is not null
|
|
273
273
|
order by constraint_name, k.ordinal_position`;
|
|
274
|
-
const allFks = await connection.execute(sql);
|
|
274
|
+
const allFks = await connection.execute(sql, [], 'all', ctx);
|
|
275
275
|
const ret = {};
|
|
276
276
|
for (const fk of allFks) {
|
|
277
277
|
const key = this.getTableKey(fk);
|
|
@@ -329,11 +329,11 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
329
329
|
ret += col.comment ? ` comment ${this.platform.quoteValue(col.comment)}` : '';
|
|
330
330
|
return ret;
|
|
331
331
|
}
|
|
332
|
-
async getAllEnumDefinitions(connection, tables) {
|
|
332
|
+
async getAllEnumDefinitions(connection, tables, ctx) {
|
|
333
333
|
const sql = `select column_name as column_name, column_type as column_type, table_name as table_name
|
|
334
334
|
from information_schema.columns
|
|
335
335
|
where data_type = 'enum' and table_name in (${tables.map(t => `'${t.table_name}'`).join(', ')}) and table_schema = database()`;
|
|
336
|
-
const enums = await connection.execute(sql);
|
|
336
|
+
const enums = await connection.execute(sql, [], 'all', ctx);
|
|
337
337
|
return enums.reduce((o, item) => {
|
|
338
338
|
o[item.table_name] ??= {};
|
|
339
339
|
o[item.table_name][item.column_name] = item.column_type
|
|
@@ -343,12 +343,12 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
343
343
|
return o;
|
|
344
344
|
}, {});
|
|
345
345
|
}
|
|
346
|
-
async supportsCheckConstraints(connection) {
|
|
346
|
+
async supportsCheckConstraints(connection, ctx) {
|
|
347
347
|
if (this.#cache.supportsCheckConstraints != null) {
|
|
348
348
|
return this.#cache.supportsCheckConstraints;
|
|
349
349
|
}
|
|
350
350
|
const sql = `select 1 from information_schema.tables where table_name = 'CHECK_CONSTRAINTS' and table_schema = 'information_schema'`;
|
|
351
|
-
const res = await connection.execute(sql);
|
|
351
|
+
const res = await connection.execute(sql, [], 'all', ctx);
|
|
352
352
|
return (this.#cache.supportsCheckConstraints = res.length > 0);
|
|
353
353
|
}
|
|
354
354
|
getChecksSQL(tables) {
|
|
@@ -213,9 +213,13 @@ export class OracleNativeQueryBuilder extends NativeQueryBuilder {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
compileSelect() {
|
|
216
|
+
const wrapCountSubquery = this.needsCountSubquery();
|
|
217
|
+
if (wrapCountSubquery) {
|
|
218
|
+
this.parts.push(`select count(*) as ${this.quote('count')} from (`);
|
|
219
|
+
}
|
|
216
220
|
this.parts.push('select');
|
|
217
221
|
this.addHintComment();
|
|
218
|
-
this.parts.push(`${this.getFields()} from ${this.getTableName()}`);
|
|
222
|
+
this.parts.push(`${this.getFields(wrapCountSubquery)} from ${this.getTableName()}`);
|
|
219
223
|
if (this.options.joins) {
|
|
220
224
|
for (const join of this.options.joins) {
|
|
221
225
|
this.parts.push(join.sql);
|
|
@@ -234,16 +238,22 @@ export class OracleNativeQueryBuilder extends NativeQueryBuilder {
|
|
|
234
238
|
this.parts.push(`having ${this.options.having.sql}`);
|
|
235
239
|
this.params.push(...this.options.having.params);
|
|
236
240
|
}
|
|
237
|
-
if (
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
this.
|
|
242
|
-
|
|
241
|
+
if (!wrapCountSubquery) {
|
|
242
|
+
if (this.options.orderBy) {
|
|
243
|
+
this.parts.push(`order by ${this.options.orderBy}`);
|
|
244
|
+
}
|
|
245
|
+
if (this.options.offset != null) {
|
|
246
|
+
this.parts.push(`offset ? rows`);
|
|
247
|
+
this.params.push(this.options.offset);
|
|
248
|
+
}
|
|
249
|
+
if (this.options.limit != null) {
|
|
250
|
+
this.parts.push(`fetch next ? rows only`);
|
|
251
|
+
this.params.push(this.options.limit);
|
|
252
|
+
}
|
|
243
253
|
}
|
|
244
|
-
if (
|
|
245
|
-
this.
|
|
246
|
-
this.
|
|
254
|
+
if (wrapCountSubquery) {
|
|
255
|
+
const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
|
|
256
|
+
this.parts.push(`)${asKeyword}${this.quote('dcnt')}`);
|
|
247
257
|
}
|
|
248
258
|
}
|
|
249
259
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Dictionary } from '@mikro-orm/core';
|
|
1
|
+
import { type Dictionary, type Transaction } from '@mikro-orm/core';
|
|
2
2
|
import { SchemaHelper } from '../../schema/SchemaHelper.js';
|
|
3
3
|
import type { AbstractSqlConnection } from '../../AbstractSqlConnection.js';
|
|
4
4
|
import type { CheckDef, Column, ForeignKey, IndexDef, Table, TableDifference } from '../../typings.js';
|
|
@@ -19,16 +19,16 @@ export declare class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
19
19
|
getListTablesSQL(): string;
|
|
20
20
|
private getIgnoredViewsCondition;
|
|
21
21
|
getListViewsSQL(): string;
|
|
22
|
-
loadViews(schema: DatabaseSchema, connection: AbstractSqlConnection): Promise<void>;
|
|
22
|
+
loadViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string, ctx?: Transaction): Promise<void>;
|
|
23
23
|
getListMaterializedViewsSQL(): string;
|
|
24
|
-
loadMaterializedViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string): Promise<void>;
|
|
24
|
+
loadMaterializedViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string, ctx?: Transaction): Promise<void>;
|
|
25
25
|
createMaterializedView(name: string, schema: string | undefined, definition: string, withData?: boolean): string;
|
|
26
26
|
dropMaterializedViewIfExists(name: string, schema?: string): string;
|
|
27
27
|
refreshMaterializedView(name: string, schema?: string, concurrently?: boolean): string;
|
|
28
|
-
getNamespaces(connection: AbstractSqlConnection): Promise<string[]>;
|
|
28
|
+
getNamespaces(connection: AbstractSqlConnection, ctx?: Transaction): Promise<string[]>;
|
|
29
29
|
private getIgnoredNamespacesConditionSQL;
|
|
30
|
-
loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[]): Promise<void>;
|
|
31
|
-
getAllIndexes(connection: AbstractSqlConnection, tables: Table[]): Promise<Dictionary<IndexDef[]>>;
|
|
30
|
+
loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[], ctx?: Transaction): Promise<void>;
|
|
31
|
+
getAllIndexes(connection: AbstractSqlConnection, tables: Table[], ctx?: Transaction): Promise<Dictionary<IndexDef[]>>;
|
|
32
32
|
/**
|
|
33
33
|
* Parses column definitions from the full CREATE INDEX expression.
|
|
34
34
|
* Since pg_get_indexdef(oid, col_num, true) doesn't include sort modifiers,
|
|
@@ -47,10 +47,10 @@ export declare class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
47
47
|
name: string;
|
|
48
48
|
schema?: string;
|
|
49
49
|
items: string[];
|
|
50
|
-
}
|
|
51
|
-
getAllChecks(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]
|
|
52
|
-
getAllForeignKeys(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]
|
|
53
|
-
getNativeEnumDefinitions(connection: AbstractSqlConnection, schemas: string[]): Promise<Dictionary<{
|
|
50
|
+
}>, ctx?: Transaction): Promise<Dictionary<Column[]>>;
|
|
51
|
+
getAllChecks(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]>, ctx?: Transaction): Promise<Dictionary<CheckDef[]>>;
|
|
52
|
+
getAllForeignKeys(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]>, ctx?: Transaction): Promise<Dictionary<Dictionary<ForeignKey>>>;
|
|
53
|
+
getNativeEnumDefinitions(connection: AbstractSqlConnection, schemas: string[], ctx?: Transaction): Promise<Dictionary<{
|
|
54
54
|
name: string;
|
|
55
55
|
schema?: string;
|
|
56
56
|
items: string[];
|
|
@@ -41,8 +41,8 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
41
41
|
`and ${this.getIgnoredViewsCondition()} ` +
|
|
42
42
|
`order by table_name`);
|
|
43
43
|
}
|
|
44
|
-
async loadViews(schema, connection) {
|
|
45
|
-
const views = await connection.execute(this.getListViewsSQL());
|
|
44
|
+
async loadViews(schema, connection, schemaName, ctx) {
|
|
45
|
+
const views = await connection.execute(this.getListViewsSQL(), [], 'all', ctx);
|
|
46
46
|
for (const view of views) {
|
|
47
47
|
const definition = view.view_definition?.trim().replace(/;$/, '') ?? '';
|
|
48
48
|
if (definition) {
|
|
@@ -51,17 +51,26 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
getListMaterializedViewsSQL() {
|
|
54
|
-
return (`select matviewname as view_name, schemaname as schema_name, definition as view_definition ` +
|
|
54
|
+
return (`select matviewname as view_name, schemaname as schema_name, definition as view_definition, ispopulated as is_populated ` +
|
|
55
55
|
`from pg_matviews ` +
|
|
56
56
|
`where ${this.getIgnoredNamespacesConditionSQL('schemaname')} ` +
|
|
57
57
|
`order by matviewname`);
|
|
58
58
|
}
|
|
59
|
-
async loadMaterializedViews(schema, connection, schemaName) {
|
|
60
|
-
const views = await connection.execute(this.getListMaterializedViewsSQL());
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
async loadMaterializedViews(schema, connection, schemaName, ctx) {
|
|
60
|
+
const views = await connection.execute(this.getListMaterializedViewsSQL(), [], 'all', ctx);
|
|
61
|
+
if (views.length === 0) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const tables = views.map(v => ({ table_name: v.view_name, schema_name: v.schema_name }));
|
|
65
|
+
const indexes = await this.getAllIndexes(connection, tables, ctx);
|
|
66
|
+
for (let i = 0; i < views.length; i++) {
|
|
67
|
+
const definition = views[i].view_definition?.trim().replace(/;$/, '') ?? '';
|
|
63
68
|
if (definition) {
|
|
64
|
-
schema.addView(
|
|
69
|
+
const dbView = schema.addView(views[i].view_name, views[i].schema_name, definition, true, views[i].is_populated);
|
|
70
|
+
const key = this.getTableKey(tables[i]);
|
|
71
|
+
if (indexes[key]?.length) {
|
|
72
|
+
dbView.indexes = indexes[key];
|
|
73
|
+
}
|
|
65
74
|
}
|
|
66
75
|
}
|
|
67
76
|
}
|
|
@@ -77,11 +86,11 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
77
86
|
const concurrent = concurrently ? ' concurrently' : '';
|
|
78
87
|
return `refresh materialized view${concurrent} ${this.quote(this.getTableName(name, schema))}`;
|
|
79
88
|
}
|
|
80
|
-
async getNamespaces(connection) {
|
|
89
|
+
async getNamespaces(connection, ctx) {
|
|
81
90
|
const sql = `select schema_name from information_schema.schemata ` +
|
|
82
91
|
`where ${this.getIgnoredNamespacesConditionSQL()} ` +
|
|
83
92
|
`order by schema_name`;
|
|
84
|
-
const res = await connection.execute(sql);
|
|
93
|
+
const res = await connection.execute(sql, [], 'all', ctx);
|
|
85
94
|
return res.map(row => row.schema_name);
|
|
86
95
|
}
|
|
87
96
|
getIgnoredNamespacesConditionSQL(column = 'schema_name') {
|
|
@@ -97,18 +106,18 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
97
106
|
const ignoredPrefixes = ['pg_', 'crdb_', '_timescaledb_'].map(p => `"${column}" not like '${p}%'`).join(' and ');
|
|
98
107
|
return `${ignoredPrefixes} and "${column}" not in (${ignored})`;
|
|
99
108
|
}
|
|
100
|
-
async loadInformationSchema(schema, connection, tables, schemas) {
|
|
109
|
+
async loadInformationSchema(schema, connection, tables, schemas, ctx) {
|
|
101
110
|
schemas ??= tables.length === 0 ? [schema.name] : tables.map(t => t.schema_name);
|
|
102
|
-
const nativeEnums = await this.getNativeEnumDefinitions(connection, schemas);
|
|
111
|
+
const nativeEnums = await this.getNativeEnumDefinitions(connection, schemas, ctx);
|
|
103
112
|
schema.setNativeEnums(nativeEnums);
|
|
104
113
|
if (tables.length === 0) {
|
|
105
114
|
return;
|
|
106
115
|
}
|
|
107
116
|
const tablesBySchema = this.getTablesGroupedBySchemas(tables);
|
|
108
|
-
const columns = await this.getAllColumns(connection, tablesBySchema, nativeEnums);
|
|
109
|
-
const indexes = await this.getAllIndexes(connection, tables);
|
|
110
|
-
const checks = await this.getAllChecks(connection, tablesBySchema);
|
|
111
|
-
const fks = await this.getAllForeignKeys(connection, tablesBySchema);
|
|
117
|
+
const columns = await this.getAllColumns(connection, tablesBySchema, nativeEnums, ctx);
|
|
118
|
+
const indexes = await this.getAllIndexes(connection, tables, ctx);
|
|
119
|
+
const checks = await this.getAllChecks(connection, tablesBySchema, ctx);
|
|
120
|
+
const fks = await this.getAllForeignKeys(connection, tablesBySchema, ctx);
|
|
112
121
|
for (const t of tables) {
|
|
113
122
|
const key = this.getTableKey(t);
|
|
114
123
|
const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
|
|
@@ -119,10 +128,10 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
119
128
|
}
|
|
120
129
|
}
|
|
121
130
|
}
|
|
122
|
-
async getAllIndexes(connection, tables) {
|
|
131
|
+
async getAllIndexes(connection, tables, ctx) {
|
|
123
132
|
const sql = this.getIndexesSQL(tables);
|
|
124
133
|
const unquote = (str) => str.replace(/['"`]/g, '');
|
|
125
|
-
const allIndexes = await connection.execute(sql);
|
|
134
|
+
const allIndexes = await connection.execute(sql, [], 'all', ctx);
|
|
126
135
|
const ret = {};
|
|
127
136
|
for (const index of allIndexes) {
|
|
128
137
|
const key = this.getTableKey(index);
|
|
@@ -243,7 +252,7 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
243
252
|
/* v8 ignore next - pg_get_indexdef always returns balanced parentheses */
|
|
244
253
|
return '';
|
|
245
254
|
}
|
|
246
|
-
async getAllColumns(connection, tablesBySchemas, nativeEnums) {
|
|
255
|
+
async getAllColumns(connection, tablesBySchemas, nativeEnums, ctx) {
|
|
247
256
|
const sql = `select table_schema as schema_name, table_name, column_name,
|
|
248
257
|
column_default,
|
|
249
258
|
is_nullable,
|
|
@@ -263,7 +272,7 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
263
272
|
join pg_attribute pga on pgc.oid = pga.attrelid and cols.column_name = pga.attname
|
|
264
273
|
where (${[...tablesBySchemas.entries()].map(([schema, tables]) => `(table_schema = ${this.platform.quoteValue(schema)} and table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(',')}))`).join(' or ')})
|
|
265
274
|
order by ordinal_position`;
|
|
266
|
-
const allColumns = await connection.execute(sql);
|
|
275
|
+
const allColumns = await connection.execute(sql, [], 'all', ctx);
|
|
267
276
|
const str = (val) => (val != null ? '' + val : val);
|
|
268
277
|
const ret = {};
|
|
269
278
|
for (const col of allColumns) {
|
|
@@ -342,9 +351,9 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
342
351
|
}
|
|
343
352
|
return ret;
|
|
344
353
|
}
|
|
345
|
-
async getAllChecks(connection, tablesBySchemas) {
|
|
354
|
+
async getAllChecks(connection, tablesBySchemas, ctx) {
|
|
346
355
|
const sql = this.getChecksSQL(tablesBySchemas);
|
|
347
|
-
const allChecks = await connection.execute(sql);
|
|
356
|
+
const allChecks = await connection.execute(sql, [], 'all', ctx);
|
|
348
357
|
const ret = {};
|
|
349
358
|
const seen = new Set();
|
|
350
359
|
for (const check of allChecks) {
|
|
@@ -366,7 +375,7 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
366
375
|
}
|
|
367
376
|
return ret;
|
|
368
377
|
}
|
|
369
|
-
async getAllForeignKeys(connection, tablesBySchemas) {
|
|
378
|
+
async getAllForeignKeys(connection, tablesBySchemas, ctx) {
|
|
370
379
|
const sql = `select nsp1.nspname schema_name, cls1.relname table_name, nsp2.nspname referenced_schema_name,
|
|
371
380
|
cls2.relname referenced_table_name, a.attname column_name, af.attname referenced_column_name, conname constraint_name,
|
|
372
381
|
confupdtype update_rule, confdeltype delete_rule, array_position(con.conkey,a.attnum) as ord, condeferrable, condeferred,
|
|
@@ -381,7 +390,7 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
381
390
|
where (${[...tablesBySchemas.entries()].map(([schema, tables]) => `(cls1.relname in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(',')}) and nsp1.nspname = ${this.platform.quoteValue(schema)})`).join(' or ')})
|
|
382
391
|
and confrelid > 0
|
|
383
392
|
order by nsp1.nspname, cls1.relname, constraint_name, ord`;
|
|
384
|
-
const allFks = await connection.execute(sql);
|
|
393
|
+
const allFks = await connection.execute(sql, [], 'all', ctx);
|
|
385
394
|
const ret = {};
|
|
386
395
|
function mapReferentialIntegrity(value, def) {
|
|
387
396
|
const match = ['n', 'd'].includes(value) && /ON DELETE (SET (NULL|DEFAULT) \(.*?\))/.exec(def);
|
|
@@ -419,14 +428,14 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
419
428
|
});
|
|
420
429
|
return ret;
|
|
421
430
|
}
|
|
422
|
-
async getNativeEnumDefinitions(connection, schemas) {
|
|
431
|
+
async getNativeEnumDefinitions(connection, schemas, ctx) {
|
|
423
432
|
const uniqueSchemas = Utils.unique(schemas);
|
|
424
433
|
const res = await connection.execute(`select t.typname as enum_name, n.nspname as schema_name, array_agg(e.enumlabel order by e.enumsortorder) as enum_value
|
|
425
434
|
from pg_type t
|
|
426
435
|
join pg_enum e on t.oid = e.enumtypid
|
|
427
436
|
join pg_catalog.pg_namespace n on n.oid = t.typnamespace
|
|
428
437
|
where n.nspname in (${Array(uniqueSchemas.length).fill('?').join(', ')})
|
|
429
|
-
group by t.typname, n.nspname`, uniqueSchemas);
|
|
438
|
+
group by t.typname, n.nspname`, uniqueSchemas, 'all', ctx);
|
|
430
439
|
return res.reduce((o, row) => {
|
|
431
440
|
let name = row.enum_name;
|
|
432
441
|
if (row.schema_name && row.schema_name !== this.platform.getDefaultSchemaName()) {
|
|
@@ -511,6 +520,9 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
511
520
|
if (parts.length === 2 && parts[0] === '*') {
|
|
512
521
|
columnType = `${table.schema}.${parts[1]}`;
|
|
513
522
|
}
|
|
523
|
+
else if (parts.length === 1) {
|
|
524
|
+
columnType = this.getTableName(column.type, table.schema);
|
|
525
|
+
}
|
|
514
526
|
if (columnType.endsWith('[]')) {
|
|
515
527
|
columnType = this.quote(columnType.substring(0, columnType.length - 2)) + '[]';
|
|
516
528
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Connection } from '@mikro-orm/core';
|
|
1
|
+
import { type Connection, type Transaction } from '@mikro-orm/core';
|
|
2
2
|
import type { AbstractSqlConnection } from '../../AbstractSqlConnection.js';
|
|
3
3
|
import { SchemaHelper } from '../../schema/SchemaHelper.js';
|
|
4
4
|
import type { Column, IndexDef, Table, TableDifference } from '../../typings.js';
|
|
@@ -11,13 +11,13 @@ export declare class SqliteSchemaHelper extends SchemaHelper {
|
|
|
11
11
|
getCreateNamespaceSQL(name: string): string;
|
|
12
12
|
getDropNamespaceSQL(name: string): string;
|
|
13
13
|
getListTablesSQL(): string;
|
|
14
|
-
getAllTables(connection: AbstractSqlConnection, schemas?: string[]): Promise<Table[]>;
|
|
15
|
-
getNamespaces(connection: AbstractSqlConnection): Promise<string[]>;
|
|
14
|
+
getAllTables(connection: AbstractSqlConnection, schemas?: string[], ctx?: Transaction): Promise<Table[]>;
|
|
15
|
+
getNamespaces(connection: AbstractSqlConnection, ctx?: Transaction): Promise<string[]>;
|
|
16
16
|
private getIgnoredViewsCondition;
|
|
17
17
|
getListViewsSQL(): string;
|
|
18
|
-
loadViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string): Promise<void>;
|
|
18
|
+
loadViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string, ctx?: Transaction): Promise<void>;
|
|
19
19
|
getDropDatabaseSQL(name: string): string;
|
|
20
|
-
loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[]): Promise<void>;
|
|
20
|
+
loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[], ctx?: Transaction): Promise<void>;
|
|
21
21
|
createTable(table: DatabaseTable, alter?: boolean): string[];
|
|
22
22
|
createTableColumn(column: Column, table: DatabaseTable, _changedProperties?: Set<string>): string | undefined;
|
|
23
23
|
getAddColumnsSQL(table: DatabaseTable, columns: Column[], diff?: TableDifference): string[];
|
|
@@ -45,7 +45,7 @@ export declare class SqliteSchemaHelper extends SchemaHelper {
|
|
|
45
45
|
*/
|
|
46
46
|
private wrapExpressionDefault;
|
|
47
47
|
private getEnumDefinitions;
|
|
48
|
-
getPrimaryKeys(connection: AbstractSqlConnection, indexes: IndexDef[], tableName: string, schemaName?: string): Promise<string[]>;
|
|
48
|
+
getPrimaryKeys(connection: AbstractSqlConnection, indexes: IndexDef[], tableName: string, schemaName?: string, ctx?: Transaction): Promise<string[]>;
|
|
49
49
|
private getIndexes;
|
|
50
50
|
private getChecks;
|
|
51
51
|
private getColumnDefinitions;
|