@mikro-orm/sql 7.0.0-dev.174 → 7.0.0-dev.176

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.
@@ -12,6 +12,7 @@ export declare class BasePostgreSqlPlatform extends AbstractSqlPlatform {
12
12
  usesCascadeStatement(): boolean;
13
13
  supportsNativeEnums(): boolean;
14
14
  usesEnumCheckConstraints(): boolean;
15
+ supportsMaterializedViews(): boolean;
15
16
  supportsCustomPrimaryKeyNames(): boolean;
16
17
  getCurrentTimestampSQL(length: number): string;
17
18
  getDateTimeTypeDeclarationSQL(column: {
@@ -22,6 +22,9 @@ export class BasePostgreSqlPlatform extends AbstractSqlPlatform {
22
22
  usesEnumCheckConstraints() {
23
23
  return true;
24
24
  }
25
+ supportsMaterializedViews() {
26
+ return true;
27
+ }
25
28
  supportsCustomPrimaryKeyNames() {
26
29
  return true;
27
30
  }
@@ -19,6 +19,11 @@ export declare class PostgreSqlSchemaHelper extends SchemaHelper {
19
19
  getListTablesSQL(): string;
20
20
  getListViewsSQL(): string;
21
21
  loadViews(schema: DatabaseSchema, connection: AbstractSqlConnection): Promise<void>;
22
+ getListMaterializedViewsSQL(): string;
23
+ loadMaterializedViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string): Promise<void>;
24
+ createMaterializedView(name: string, schema: string | undefined, definition: string, withData?: boolean): string;
25
+ dropMaterializedViewIfExists(name: string, schema?: string): string;
26
+ refreshMaterializedView(name: string, schema?: string, concurrently?: boolean): string;
22
27
  getNamespaces(connection: AbstractSqlConnection): Promise<string[]>;
23
28
  private getIgnoredNamespacesConditionSQL;
24
29
  loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[]): Promise<void>;
@@ -44,6 +44,33 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
44
44
  }
45
45
  }
46
46
  }
47
+ getListMaterializedViewsSQL() {
48
+ return `select matviewname as view_name, schemaname as schema_name, definition as view_definition `
49
+ + `from pg_matviews `
50
+ + `where ${this.getIgnoredNamespacesConditionSQL('schemaname')} `
51
+ + `order by matviewname`;
52
+ }
53
+ async loadMaterializedViews(schema, connection, schemaName) {
54
+ const views = await connection.execute(this.getListMaterializedViewsSQL());
55
+ for (const view of views) {
56
+ const definition = view.view_definition?.trim().replace(/;$/, '') ?? '';
57
+ if (definition) {
58
+ schema.addView(view.view_name, view.schema_name, definition, true);
59
+ }
60
+ }
61
+ }
62
+ createMaterializedView(name, schema, definition, withData = true) {
63
+ const viewName = this.quote(this.getTableName(name, schema));
64
+ const dataClause = withData ? ' with data' : ' with no data';
65
+ return `create materialized view ${viewName} as ${definition}${dataClause}`;
66
+ }
67
+ dropMaterializedViewIfExists(name, schema) {
68
+ return `drop materialized view if exists ${this.quote(this.getTableName(name, schema))} cascade`;
69
+ }
70
+ refreshMaterializedView(name, schema, concurrently = false) {
71
+ const concurrent = concurrently ? ' concurrently' : '';
72
+ return `refresh materialized view${concurrent} ${this.quote(this.getTableName(name, schema))}`;
73
+ }
47
74
  async getNamespaces(connection) {
48
75
  const sql = `select schema_name from information_schema.schemata `
49
76
  + `where ${this.getIgnoredNamespacesConditionSQL()} `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/sql",
3
- "version": "7.0.0-dev.174",
3
+ "version": "7.0.0-dev.176",
4
4
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -56,6 +56,6 @@
56
56
  "@mikro-orm/core": "^6.6.4"
57
57
  },
58
58
  "peerDependencies": {
59
- "@mikro-orm/core": "7.0.0-dev.174"
59
+ "@mikro-orm/core": "7.0.0-dev.176"
60
60
  }
61
61
  }
@@ -136,7 +136,7 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
136
136
  /**
137
137
  * @internal
138
138
  */
139
- constructor(entityName: EntityName<Entity> | QueryBuilder<Entity, any, any>, metadata: MetadataStorage, driver: AbstractSqlDriver, context?: Transaction | undefined, alias?: string, connectionType?: ConnectionType | undefined, em?: SqlEntityManager | undefined, loggerContext?: (LoggingOptions & Dictionary) | undefined);
139
+ constructor(entityName: EntityName<Entity> | QueryBuilder<Entity, any, any, any>, metadata: MetadataStorage, driver: AbstractSqlDriver, context?: Transaction | undefined, alias?: string, connectionType?: ConnectionType | undefined, em?: SqlEntityManager | undefined, loggerContext?: (LoggingOptions & Dictionary) | undefined);
140
140
  select(fields: Field<Entity> | Field<Entity>[], distinct?: boolean): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
141
141
  addSelect(fields: Field<Entity> | Field<Entity>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
142
142
  distinct(): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
@@ -352,7 +352,7 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
352
352
  private ensureFromClause;
353
353
  private ensureNotFinalized;
354
354
  }
355
- export interface RunQueryBuilder<Entity extends object> extends Omit<QueryBuilder<Entity, any, any>, 'getResult' | 'getSingleResult' | 'getResultList' | 'where'> {
355
+ export interface RunQueryBuilder<Entity extends object> extends Omit<QueryBuilder<Entity, any, any, any>, 'getResult' | 'getSingleResult' | 'getResultList' | 'where'> {
356
356
  where(cond: QBFilterQuery<Entity> | string, params?: keyof typeof GroupOperator | any[], operator?: keyof typeof GroupOperator): this;
357
357
  execute<Result = QueryResult<Entity>>(method?: 'all' | 'get' | 'run', mapResults?: boolean): Promise<Result>;
358
358
  }
@@ -18,7 +18,7 @@ export declare class DatabaseSchema {
18
18
  getTables(): DatabaseTable[];
19
19
  getTable(name: string): DatabaseTable | undefined;
20
20
  hasTable(name: string): boolean;
21
- addView(name: string, schema: string | undefined | null, definition: string): DatabaseView;
21
+ addView(name: string, schema: string | undefined | null, definition: string, materialized?: boolean, withData?: boolean): DatabaseView;
22
22
  getViews(): DatabaseView[];
23
23
  getView(name: string): DatabaseView | undefined;
24
24
  hasView(name: string): boolean;
@@ -34,9 +34,9 @@ export class DatabaseSchema {
34
34
  hasTable(name) {
35
35
  return !!this.getTable(name);
36
36
  }
37
- addView(name, schema, definition) {
37
+ addView(name, schema, definition, materialized, withData) {
38
38
  const namespaceName = schema ?? this.name;
39
- const view = { name, schema: namespaceName, definition };
39
+ const view = { name, schema: namespaceName, definition, materialized, withData };
40
40
  this.views.push(view);
41
41
  if (namespaceName != null) {
42
42
  this.namespaces.add(namespaceName);
@@ -85,6 +85,10 @@ export class DatabaseSchema {
85
85
  await platform.getSchemaHelper().loadInformationSchema(schema, connection, tables, schemas && schemas.length > 0 ? schemas : undefined);
86
86
  // Load views from database
87
87
  await platform.getSchemaHelper().loadViews(schema, connection);
88
+ // Load materialized views (PostgreSQL only)
89
+ if (platform.supportsMaterializedViews()) {
90
+ await platform.getSchemaHelper().loadMaterializedViews(schema, connection, schemaName);
91
+ }
88
92
  return schema;
89
93
  }
90
94
  static fromMetadata(metadata, platform, config, schemaName, em) {
@@ -124,7 +128,7 @@ export class DatabaseSchema {
124
128
  if (meta.view) {
125
129
  const viewDefinition = this.getViewDefinition(meta, em, platform);
126
130
  if (viewDefinition) {
127
- schema.addView(meta.collection, this.getSchemaName(meta, config, schemaName), viewDefinition);
131
+ schema.addView(meta.collection, this.getSchemaName(meta, config, schemaName), viewDefinition, meta.materialized, meta.withData);
128
132
  }
129
133
  continue;
130
134
  }
@@ -79,4 +79,9 @@ export declare abstract class SchemaHelper {
79
79
  dropTableIfExists(name: string, schema?: string): string;
80
80
  createView(name: string, schema: string | undefined, definition: string): string;
81
81
  dropViewIfExists(name: string, schema?: string): string;
82
+ createMaterializedView(name: string, schema: string | undefined, definition: string, withData?: boolean): string;
83
+ dropMaterializedViewIfExists(name: string, schema?: string): string;
84
+ refreshMaterializedView(name: string, schema?: string, concurrently?: boolean): string;
85
+ getListMaterializedViewsSQL(): string;
86
+ loadMaterializedViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string): Promise<void>;
82
87
  }
@@ -558,4 +558,19 @@ export class SchemaHelper {
558
558
  }
559
559
  return sql;
560
560
  }
561
+ createMaterializedView(name, schema, definition, withData = true) {
562
+ throw new Error('Not supported by given driver');
563
+ }
564
+ dropMaterializedViewIfExists(name, schema) {
565
+ throw new Error('Not supported by given driver');
566
+ }
567
+ refreshMaterializedView(name, schema, concurrently = false) {
568
+ throw new Error('Not supported by given driver');
569
+ }
570
+ getListMaterializedViewsSQL() {
571
+ throw new Error('Not supported by given driver');
572
+ }
573
+ async loadMaterializedViews(schema, connection, schemaName) {
574
+ throw new Error('Not supported by given driver');
575
+ }
561
576
  }
@@ -91,7 +91,12 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
91
91
  // Sort views by dependencies (views depending on other views come later)
92
92
  const sortedViews = this.sortViewsByDependencies(toSchema.getViews());
93
93
  for (const view of sortedViews) {
94
- this.append(ret, this.helper.createView(view.name, view.schema, view.definition), true);
94
+ if (view.materialized) {
95
+ this.append(ret, this.helper.createMaterializedView(view.name, view.schema, view.definition, view.withData ?? true));
96
+ }
97
+ else {
98
+ this.append(ret, this.helper.createView(view.name, view.schema, view.definition), true);
99
+ }
95
100
  }
96
101
  return this.wrapSchema(ret, options);
97
102
  }
@@ -141,7 +146,12 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
141
146
  const targetSchema = this.getTargetSchema(options.schema);
142
147
  const sortedViews = this.sortViewsByDependencies(targetSchema.getViews()).reverse();
143
148
  for (const view of sortedViews) {
144
- this.append(ret, this.helper.dropViewIfExists(view.name, view.schema));
149
+ if (view.materialized) {
150
+ this.append(ret, this.helper.dropMaterializedViewIfExists(view.name, view.schema));
151
+ }
152
+ else {
153
+ this.append(ret, this.helper.dropViewIfExists(view.name, view.schema));
154
+ }
145
155
  }
146
156
  // remove FKs explicitly if we can't use a cascading statement and we don't disable FK checks (we need this for circular relations)
147
157
  for (const meta of metadata) {
@@ -235,7 +245,12 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
235
245
  if (options.dropTables && !options.safe) {
236
246
  const sortedRemovedViews = this.sortViewsByDependencies(Object.values(schemaDiff.removedViews)).reverse();
237
247
  for (const view of sortedRemovedViews) {
238
- this.append(ret, this.helper.dropViewIfExists(view.name, view.schema));
248
+ if (view.materialized) {
249
+ this.append(ret, this.helper.dropMaterializedViewIfExists(view.name, view.schema));
250
+ }
251
+ else {
252
+ this.append(ret, this.helper.dropViewIfExists(view.name, view.schema));
253
+ }
239
254
  }
240
255
  }
241
256
  // Drop changed views (they will be recreated after table changes)
@@ -243,7 +258,12 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
243
258
  const changedViewsFrom = Object.values(schemaDiff.changedViews).map(v => v.from);
244
259
  const sortedChangedViewsFrom = this.sortViewsByDependencies(changedViewsFrom).reverse();
245
260
  for (const view of sortedChangedViewsFrom) {
246
- this.append(ret, this.helper.dropViewIfExists(view.name, view.schema));
261
+ if (view.materialized) {
262
+ this.append(ret, this.helper.dropMaterializedViewIfExists(view.name, view.schema));
263
+ }
264
+ else {
265
+ this.append(ret, this.helper.dropViewIfExists(view.name, view.schema));
266
+ }
247
267
  }
248
268
  if (!options.safe && this.options.createForeignKeyConstraints) {
249
269
  for (const orphanedForeignKey of schemaDiff.orphanedForeignKeys) {
@@ -304,13 +324,23 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
304
324
  // Sort views by dependencies (views depending on other views come later)
305
325
  const sortedNewViews = this.sortViewsByDependencies(Object.values(schemaDiff.newViews));
306
326
  for (const view of sortedNewViews) {
307
- this.append(ret, this.helper.createView(view.name, view.schema, view.definition), true);
327
+ if (view.materialized) {
328
+ this.append(ret, this.helper.createMaterializedView(view.name, view.schema, view.definition, view.withData ?? true));
329
+ }
330
+ else {
331
+ this.append(ret, this.helper.createView(view.name, view.schema, view.definition), true);
332
+ }
308
333
  }
309
334
  // Recreate changed views (also sorted by dependencies)
310
335
  const changedViews = Object.values(schemaDiff.changedViews).map(v => v.to);
311
336
  const sortedChangedViews = this.sortViewsByDependencies(changedViews);
312
337
  for (const view of sortedChangedViews) {
313
- this.append(ret, this.helper.createView(view.name, view.schema, view.definition), true);
338
+ if (view.materialized) {
339
+ this.append(ret, this.helper.createMaterializedView(view.name, view.schema, view.definition, view.withData ?? true));
340
+ }
341
+ else {
342
+ this.append(ret, this.helper.createView(view.name, view.schema, view.definition), true);
343
+ }
314
344
  }
315
345
  return this.wrapSchema(ret, options);
316
346
  }