Socket
Book a DemoSign in
Socket

@mikro-orm/sql

Package Overview
Dependencies
Maintainers
1
Versions
348
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mikro-orm/sql - npm Package Compare versions

Comparing version
7.0.7-dev.10
to
7.0.7-dev.11
+13
-4
dialects/postgresql/PostgreSqlSchemaHelper.js

@@ -54,3 +54,3 @@ import { DeferMode, EnumType, Type, Utils, } from '@mikro-orm/core';

getListMaterializedViewsSQL() {
return (`select matviewname as view_name, schemaname as schema_name, definition as view_definition ` +
return (`select matviewname as view_name, schemaname as schema_name, definition as view_definition, ispopulated as is_populated ` +
`from pg_matviews ` +

@@ -62,6 +62,15 @@ `where ${this.getIgnoredNamespacesConditionSQL('schemaname')} ` +

const views = await connection.execute(this.getListMaterializedViewsSQL());
for (const view of views) {
const definition = view.view_definition?.trim().replace(/;$/, '') ?? '';
if (views.length === 0) {
return;
}
const tables = views.map(v => ({ table_name: v.view_name, schema_name: v.schema_name }));
const indexes = await this.getAllIndexes(connection, tables);
for (let i = 0; i < views.length; i++) {
const definition = views[i].view_definition?.trim().replace(/;$/, '') ?? '';
if (definition) {
schema.addView(view.view_name, view.schema_name, definition, true);
const dbView = schema.addView(views[i].view_name, views[i].schema_name, definition, true, views[i].is_populated);
const key = this.getTableKey(tables[i]);
if (indexes[key]?.length) {
dbView.indexes = indexes[key];
}
}

@@ -68,0 +77,0 @@ }

{
"name": "@mikro-orm/sql",
"version": "7.0.7-dev.10",
"version": "7.0.7-dev.11",
"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.",

@@ -56,3 +56,3 @@ "keywords": [

"peerDependencies": {
"@mikro-orm/core": "7.0.7-dev.10"
"@mikro-orm/core": "7.0.7-dev.11"
},

@@ -59,0 +59,0 @@ "engines": {

@@ -150,3 +150,23 @@ import { ReferenceKind, isRaw, } from '@mikro-orm/core';

if (viewDefinition) {
schema.addView(meta.collection, this.getSchemaName(meta, config, schemaName), viewDefinition, meta.materialized, meta.withData);
const view = schema.addView(meta.collection, this.getSchemaName(meta, config, schemaName), viewDefinition, meta.materialized, meta.withData);
if (meta.materialized) {
// Use a DatabaseTable to resolve property names → field names for indexes.
// addIndex only needs meta + table name, not actual columns.
const indexTable = new DatabaseTable(platform, meta.collection, this.getSchemaName(meta, config, schemaName));
meta.indexes.forEach(index => indexTable.addIndex(meta, index, 'index'));
meta.uniques.forEach(index => indexTable.addIndex(meta, index, 'unique'));
const pkProps = meta.props.filter(prop => prop.primary);
indexTable.addIndex(meta, { properties: pkProps.map(prop => prop.name) }, 'primary');
// Materialized views don't have primary keys or constraints in the DB,
// convert to match what PostgreSQL stores.
view.indexes = indexTable.getIndexes().map(idx => {
if (idx.primary) {
return { ...idx, primary: false, unique: true, constraint: false };
}
if (idx.constraint) {
return { ...idx, constraint: false };
}
return idx;
});
}
}

@@ -153,0 +173,0 @@ continue;

import { type Dictionary } from '@mikro-orm/core';
import type { Column, ForeignKey, IndexDef, SchemaDifference, TableDifference } from '../typings.js';
import type { DatabaseSchema } from './DatabaseSchema.js';
import type { DatabaseTable } from './DatabaseTable.js';
import { DatabaseTable } from './DatabaseTable.js';
import type { AbstractSqlPlatform } from '../AbstractSqlPlatform.js';

@@ -6,0 +6,0 @@ /**

import { ArrayType, BooleanType, DateTimeType, inspect, JsonType, parseJsonSafe, Utils, } from '@mikro-orm/core';
import { DatabaseTable } from './DatabaseTable.js';
/**

@@ -117,6 +118,7 @@ * Compares two Schemas and return an instance of SchemaDifference.

}
// Compare views
// Compare views — prefer schema-qualified lookup to avoid matching
// views with the same name in different schemas
for (const toView of toSchema.getViews()) {
const viewName = toView.schema ? `${toView.schema}.${toView.name}` : toView.name;
if (!fromSchema.hasView(toView.name) && !fromSchema.hasView(viewName)) {
if (!fromSchema.hasView(viewName) && !fromSchema.hasView(toView.name)) {
diff.newViews[viewName] = toView;

@@ -126,3 +128,3 @@ this.log(`view ${viewName} added`);

else {
const fromView = fromSchema.getView(toView.name) ?? fromSchema.getView(viewName);
const fromView = fromSchema.getView(viewName) ?? fromSchema.getView(toView.name);
if (fromView && this.diffViewExpression(fromView.definition, toView.definition)) {

@@ -137,3 +139,3 @@ diff.changedViews[viewName] = { from: fromView, to: toView };

const viewName = fromView.schema ? `${fromView.schema}.${fromView.name}` : fromView.name;
if (!toSchema.hasView(fromView.name) && !toSchema.hasView(viewName)) {
if (!toSchema.hasView(viewName) && !toSchema.hasView(fromView.name)) {
diff.removedViews[viewName] = fromView;

@@ -143,2 +145,25 @@ this.log(`view ${viewName} removed`);

}
// Diff materialized view indexes using the existing table diff infrastructure.
// Build transient DatabaseTable objects from view indexes so diffTable handles
// added/removed/changed/renamed index detection and alterTable emits correct DDL.
for (const toView of toSchema.getViews()) {
if (!toView.materialized || toView.withData === false) {
continue;
}
const viewName = toView.schema ? `${toView.schema}.${toView.name}` : toView.name;
// New or definition-changed views have indexes handled during create/recreate
if (diff.newViews[viewName] || diff.changedViews[viewName]) {
continue;
}
// If we get here, the view exists in fromSchema (otherwise it would be in diff.newViews)
const fromView = fromSchema.getView(viewName) ?? fromSchema.getView(toView.name);
const fromTable = new DatabaseTable(this.#platform, fromView.name, fromView.schema);
fromTable.init([], fromView.indexes ?? [], [], []);
const toTable = new DatabaseTable(this.#platform, toView.name, toView.schema);
toTable.init([], toView.indexes ?? [], [], []);
const tableDiff = this.diffTable(fromTable, toTable);
if (tableDiff) {
diff.changedTables[viewName] = tableDiff;
}
}
return diff;

@@ -145,0 +170,0 @@ }

@@ -87,3 +87,4 @@ import { type Connection, type Dictionary, type Options, RawQueryFragment } from '@mikro-orm/core';

createCheck(table: DatabaseTable, check: CheckDef): string;
protected getTableName(table: string, schema?: string): string;
/** @internal */
getTableName(table: string, schema?: string): string;
getTablesGroupedBySchemas(tables: Table[]): Map<string | undefined, Table[]>;

@@ -90,0 +91,0 @@ get options(): NonNullable<Options['schemaGenerator']>;

@@ -596,2 +596,3 @@ import { RawQueryFragment, Utils } from '@mikro-orm/core';

}
/** @internal */
getTableName(table, schema) {

@@ -598,0 +599,0 @@ if (schema && schema !== this.platform.getDefaultSchemaName()) {

@@ -65,4 +65,5 @@ import { type ClearDatabaseOptions, type CreateSchemaOptions, type DropSchemaOptions, type EnsureDatabaseOptions, type EntityMetadata, type ISchemaGenerator, type MikroORM, type Options, type Transaction, type UpdateSchemaOptions } from '@mikro-orm/core';

private sortViewsByDependencies;
private appendViewCreation;
private escapeRegExp;
}
export { SqlSchemaGenerator as SchemaGenerator };

@@ -92,12 +92,5 @@ import { CommitOrderCalculator, TableNotFoundException, Utils, } from '@mikro-orm/core';

}
// Create views after tables (views may depend on tables)
// Sort views by dependencies (views depending on other views come later)
const sortedViews = this.sortViewsByDependencies(toSchema.getViews());
for (const view of sortedViews) {
if (view.materialized) {
this.append(ret, this.helper.createMaterializedView(view.name, view.schema, view.definition, view.withData ?? true));
}
else {
this.append(ret, this.helper.createView(view.name, view.schema, view.definition), true);
}
this.appendViewCreation(ret, view);
}

@@ -342,23 +335,10 @@ return this.wrapSchema(ret, options);

}
// Create new views after all table changes are done
// Sort views by dependencies (views depending on other views come later)
const sortedNewViews = this.sortViewsByDependencies(Object.values(schemaDiff.newViews));
for (const view of sortedNewViews) {
if (view.materialized) {
this.append(ret, this.helper.createMaterializedView(view.name, view.schema, view.definition, view.withData ?? true));
}
else {
this.append(ret, this.helper.createView(view.name, view.schema, view.definition), true);
}
this.appendViewCreation(ret, view);
}
// Recreate changed views (also sorted by dependencies)
const changedViews = Object.values(schemaDiff.changedViews).map(v => v.to);
const sortedChangedViews = this.sortViewsByDependencies(changedViews);
for (const view of sortedChangedViews) {
if (view.materialized) {
this.append(ret, this.helper.createMaterializedView(view.name, view.schema, view.definition, view.withData ?? true));
}
else {
this.append(ret, this.helper.createView(view.name, view.schema, view.definition), true);
}
this.appendViewCreation(ret, view);
}

@@ -516,2 +496,18 @@ return this.wrapSchema(ret, options);

}
appendViewCreation(ret, view) {
if (view.materialized) {
this.append(ret, this.helper.createMaterializedView(view.name, view.schema, view.definition, view.withData ?? true));
// Skip indexes for WITH NO DATA views — they have no data to index yet.
// Indexes will be created on the next schema:update after REFRESH populates data.
if (view.withData !== false) {
const viewName = this.helper.getTableName(view.name, view.schema);
for (const index of view.indexes ?? []) {
this.append(ret, this.helper.getCreateIndexSQL(viewName, index));
}
}
}
else {
this.append(ret, this.helper.createView(view.name, view.schema, view.definition), true);
}
}
escapeRegExp(string) {

@@ -518,0 +514,0 @@ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

@@ -145,2 +145,4 @@ import type { Generated, Kysely } from 'kysely';

withData?: boolean;
/** Indexes on the materialized view. Only materialized views support indexes. */
indexes?: IndexDef[];
}

@@ -147,0 +149,0 @@ export interface SchemaDifference {