@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.
@@ -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;
@@ -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
- if (this.options.limit != null && this.options.offset == null) {
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 (this.options.orderBy) {
167
- this.parts.push(`order by ${this.options.orderBy}`);
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.parts.push(`offset ? rows`);
175
- this.params.push(this.options.offset);
176
- if (this.options.limit != null) {
177
- this.parts.push(`fetch next ? rows only`);
178
- this.params.push(this.options.limit);
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 (this.options.orderBy) {
238
- this.parts.push(`order by ${this.options.orderBy}`);
239
- }
240
- if (this.options.offset != null) {
241
- this.parts.push(`offset ? rows`);
242
- this.params.push(this.options.offset);
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 (this.options.limit != null) {
245
- this.parts.push(`fetch next ? rows only`);
246
- this.params.push(this.options.limit);
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
- }>): Promise<Dictionary<Column[]>>;
51
- getAllChecks(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]>): Promise<Dictionary<CheckDef[]>>;
52
- getAllForeignKeys(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]>): Promise<Dictionary<Dictionary<ForeignKey>>>;
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
- for (const view of views) {
62
- const definition = view.view_definition?.trim().replace(/;$/, '') ?? '';
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(view.view_name, view.schema_name, definition, true);
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;