Initial commit - Event Planner application
This commit is contained in:
553
node_modules/@mikro-orm/sql/schema/SqlSchemaGenerator.js
generated
vendored
Normal file
553
node_modules/@mikro-orm/sql/schema/SqlSchemaGenerator.js
generated
vendored
Normal file
@@ -0,0 +1,553 @@
|
||||
import { CommitOrderCalculator, TableNotFoundException, Utils } from '@mikro-orm/core';
|
||||
import { AbstractSchemaGenerator } from '@mikro-orm/core/schema';
|
||||
import { DatabaseSchema } from './DatabaseSchema.js';
|
||||
import { SchemaComparator } from './SchemaComparator.js';
|
||||
/** Generates and manages SQL database schemas based on entity metadata. Supports create, update, and drop operations. */
|
||||
export class SqlSchemaGenerator extends AbstractSchemaGenerator {
|
||||
helper = this.platform.getSchemaHelper();
|
||||
options = this.config.get('schemaGenerator');
|
||||
lastEnsuredDatabase;
|
||||
static register(orm) {
|
||||
orm.config.registerExtension('@mikro-orm/schema-generator', () => new SqlSchemaGenerator(orm.em));
|
||||
}
|
||||
async create(options) {
|
||||
await this.ensureDatabase();
|
||||
const sql = await this.getCreateSchemaSQL(options);
|
||||
await this.execute(sql);
|
||||
}
|
||||
/**
|
||||
* Returns true if the database was created.
|
||||
*/
|
||||
async ensureDatabase(options) {
|
||||
await this.connection.ensureConnection();
|
||||
const dbName = this.config.get('dbName');
|
||||
if (this.lastEnsuredDatabase === dbName && !options?.forceCheck) {
|
||||
return true;
|
||||
}
|
||||
const exists = await this.helper.databaseExists(this.connection, dbName);
|
||||
this.lastEnsuredDatabase = dbName;
|
||||
if (!exists) {
|
||||
const managementDbName = this.helper.getManagementDbName();
|
||||
if (managementDbName) {
|
||||
this.config.set('dbName', managementDbName);
|
||||
await this.driver.reconnect({ skipOnConnect: true });
|
||||
await this.createDatabase(dbName, { skipOnConnect: true });
|
||||
}
|
||||
if (options?.create) {
|
||||
await this.create(options);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/* v8 ignore next */
|
||||
if (options?.clear) {
|
||||
await this.clear({ ...options, clearIdentityMap: false });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
getTargetSchema(schema) {
|
||||
const metadata = this.getOrderedMetadata(schema);
|
||||
const schemaName = schema ?? this.config.get('schema') ?? this.platform.getDefaultSchemaName();
|
||||
return DatabaseSchema.fromMetadata(metadata, this.platform, this.config, schemaName, this.em);
|
||||
}
|
||||
getOrderedMetadata(schema) {
|
||||
const metadata = super.getOrderedMetadata(schema);
|
||||
// Filter out skipped tables
|
||||
return metadata.filter(meta => {
|
||||
const tableName = meta.tableName;
|
||||
const tableSchema = meta.schema ?? schema ?? this.config.get('schema');
|
||||
return !this.isTableSkipped(tableName, tableSchema);
|
||||
});
|
||||
}
|
||||
async getCreateSchemaSQL(options = {}) {
|
||||
const toSchema = this.getTargetSchema(options.schema);
|
||||
const ret = [];
|
||||
for (const namespace of toSchema.getNamespaces()) {
|
||||
if (namespace === this.platform.getDefaultSchemaName()) {
|
||||
continue;
|
||||
}
|
||||
const sql = this.helper.getCreateNamespaceSQL(namespace);
|
||||
this.append(ret, sql);
|
||||
}
|
||||
if (this.platform.supportsNativeEnums()) {
|
||||
const created = [];
|
||||
for (const [enumName, enumOptions] of Object.entries(toSchema.getNativeEnums())) {
|
||||
/* v8 ignore next */
|
||||
if (created.includes(enumName)) {
|
||||
continue;
|
||||
}
|
||||
created.push(enumName);
|
||||
const sql = this.helper.getCreateNativeEnumSQL(
|
||||
enumOptions.name,
|
||||
enumOptions.items,
|
||||
this.getSchemaName(enumOptions, options),
|
||||
);
|
||||
this.append(ret, sql);
|
||||
}
|
||||
}
|
||||
for (const table of toSchema.getTables()) {
|
||||
this.append(ret, this.helper.createTable(table), true);
|
||||
}
|
||||
if (this.helper.supportsSchemaConstraints()) {
|
||||
for (const table of toSchema.getTables()) {
|
||||
const fks = Object.values(table.getForeignKeys()).map(fk => this.helper.createForeignKey(table, fk));
|
||||
this.append(ret, fks, true);
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
return this.wrapSchema(ret, options);
|
||||
}
|
||||
async drop(options = {}) {
|
||||
if (options.dropDb) {
|
||||
const name = this.config.get('dbName');
|
||||
return this.dropDatabase(name);
|
||||
}
|
||||
const sql = await this.getDropSchemaSQL(options);
|
||||
await this.execute(sql);
|
||||
}
|
||||
async createNamespace(name) {
|
||||
const sql = this.helper.getCreateNamespaceSQL(name);
|
||||
await this.execute(sql);
|
||||
}
|
||||
async dropNamespace(name) {
|
||||
const sql = this.helper.getDropNamespaceSQL(name);
|
||||
await this.execute(sql);
|
||||
}
|
||||
async clear(options) {
|
||||
// truncate by default, so no value is considered as true
|
||||
/* v8 ignore next */
|
||||
if (options?.truncate === false) {
|
||||
return super.clear(options);
|
||||
}
|
||||
if (this.options.disableForeignKeysForClear) {
|
||||
await this.execute(this.helper.disableForeignKeysSQL());
|
||||
}
|
||||
const schema = options?.schema ?? this.config.get('schema', this.platform.getDefaultSchemaName());
|
||||
for (const meta of this.getOrderedMetadata(schema).reverse()) {
|
||||
try {
|
||||
await this.driver
|
||||
.createQueryBuilder(meta.class, this.em?.getTransactionContext(), 'write', false)
|
||||
.withSchema(schema)
|
||||
.truncate()
|
||||
.execute();
|
||||
} catch (e) {
|
||||
if (this.platform.getExceptionConverter().convertException(e) instanceof TableNotFoundException) {
|
||||
continue;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (this.options.disableForeignKeysForClear) {
|
||||
await this.execute(this.helper.enableForeignKeysSQL());
|
||||
}
|
||||
if (options?.clearIdentityMap ?? true) {
|
||||
this.clearIdentityMap();
|
||||
}
|
||||
}
|
||||
async getDropSchemaSQL(options = {}) {
|
||||
await this.ensureDatabase();
|
||||
const metadata = this.getOrderedMetadata(options.schema).reverse();
|
||||
const schemas = this.getTargetSchema(options.schema).getNamespaces();
|
||||
const schema = await DatabaseSchema.create(
|
||||
this.connection,
|
||||
this.platform,
|
||||
this.config,
|
||||
options.schema,
|
||||
schemas,
|
||||
undefined,
|
||||
this.options.skipTables,
|
||||
this.options.skipViews,
|
||||
);
|
||||
const ret = [];
|
||||
// Drop views first (views may depend on tables)
|
||||
// Drop in reverse dependency order (dependent views first)
|
||||
const targetSchema = this.getTargetSchema(options.schema);
|
||||
const sortedViews = this.sortViewsByDependencies(targetSchema.getViews()).reverse();
|
||||
for (const view of sortedViews) {
|
||||
if (view.materialized) {
|
||||
this.append(ret, this.helper.dropMaterializedViewIfExists(view.name, view.schema));
|
||||
} else {
|
||||
this.append(ret, this.helper.dropViewIfExists(view.name, view.schema));
|
||||
}
|
||||
}
|
||||
// remove FKs explicitly if we can't use a cascading statement and we don't disable FK checks (we need this for circular relations)
|
||||
for (const meta of metadata) {
|
||||
if (!this.platform.usesCascadeStatement() && (!this.options.disableForeignKeys || options.dropForeignKeys)) {
|
||||
const table = schema.getTable(meta.tableName);
|
||||
if (!table) {
|
||||
continue;
|
||||
}
|
||||
const foreignKeys = Object.values(table.getForeignKeys());
|
||||
for (const fk of foreignKeys) {
|
||||
this.append(ret, this.helper.dropForeignKey(table.getShortestName(), fk.constraintName));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const meta of metadata) {
|
||||
this.append(ret, this.helper.dropTableIfExists(meta.tableName, this.getSchemaName(meta, options)));
|
||||
}
|
||||
if (this.platform.supportsNativeEnums()) {
|
||||
for (const columnName of Object.keys(schema.getNativeEnums())) {
|
||||
const sql = this.helper.getDropNativeEnumSQL(columnName, options.schema ?? this.config.get('schema'));
|
||||
this.append(ret, sql);
|
||||
}
|
||||
}
|
||||
if (options.dropMigrationsTable) {
|
||||
this.append(
|
||||
ret,
|
||||
this.helper.dropTableIfExists(this.config.get('migrations').tableName, this.config.get('schema')),
|
||||
);
|
||||
}
|
||||
return this.wrapSchema(ret, options);
|
||||
}
|
||||
getSchemaName(meta, options) {
|
||||
const schemaName = options.schema ?? this.config.get('schema');
|
||||
/* v8 ignore next */
|
||||
const resolvedName = meta.schema && meta.schema === '*' ? schemaName : (meta.schema ?? schemaName);
|
||||
// skip default schema name
|
||||
if (resolvedName === this.platform.getDefaultSchemaName()) {
|
||||
return undefined;
|
||||
}
|
||||
return resolvedName;
|
||||
}
|
||||
async update(options = {}) {
|
||||
const sql = await this.getUpdateSchemaSQL(options);
|
||||
await this.execute(sql);
|
||||
}
|
||||
async getUpdateSchemaSQL(options = {}) {
|
||||
await this.ensureDatabase();
|
||||
const { fromSchema, toSchema } = await this.prepareSchemaForComparison(options);
|
||||
const comparator = new SchemaComparator(this.platform);
|
||||
const diffUp = comparator.compare(fromSchema, toSchema);
|
||||
return this.diffToSQL(diffUp, options);
|
||||
}
|
||||
async getUpdateSchemaMigrationSQL(options = {}) {
|
||||
if (!options.fromSchema) {
|
||||
await this.ensureDatabase();
|
||||
}
|
||||
const { fromSchema, toSchema } = await this.prepareSchemaForComparison(options);
|
||||
const comparator = new SchemaComparator(this.platform);
|
||||
const diffUp = comparator.compare(fromSchema, toSchema);
|
||||
const diffDown = comparator.compare(toSchema, fromSchema, diffUp);
|
||||
return {
|
||||
up: this.diffToSQL(diffUp, options),
|
||||
down: this.platform.supportsDownMigrations() ? this.diffToSQL(diffDown, options) : '',
|
||||
};
|
||||
}
|
||||
async prepareSchemaForComparison(options) {
|
||||
options.safe ??= false;
|
||||
options.dropTables ??= true;
|
||||
const toSchema = this.getTargetSchema(options.schema);
|
||||
const schemas = toSchema.getNamespaces();
|
||||
const fromSchema =
|
||||
options.fromSchema ??
|
||||
(await DatabaseSchema.create(
|
||||
this.connection,
|
||||
this.platform,
|
||||
this.config,
|
||||
options.schema,
|
||||
schemas,
|
||||
undefined,
|
||||
this.options.skipTables,
|
||||
this.options.skipViews,
|
||||
));
|
||||
const wildcardSchemaTables = [...this.metadata.getAll().values()]
|
||||
.filter(meta => meta.schema === '*')
|
||||
.map(meta => meta.tableName);
|
||||
fromSchema.prune(options.schema, wildcardSchemaTables);
|
||||
toSchema.prune(options.schema, wildcardSchemaTables);
|
||||
return { fromSchema, toSchema };
|
||||
}
|
||||
diffToSQL(schemaDiff, options) {
|
||||
const ret = [];
|
||||
globalThis.idx = 0;
|
||||
if (this.platform.supportsSchemas()) {
|
||||
for (const newNamespace of schemaDiff.newNamespaces) {
|
||||
const sql = this.helper.getCreateNamespaceSQL(newNamespace);
|
||||
this.append(ret, sql);
|
||||
}
|
||||
}
|
||||
if (this.platform.supportsNativeEnums()) {
|
||||
for (const newNativeEnum of schemaDiff.newNativeEnums) {
|
||||
const sql = this.helper.getCreateNativeEnumSQL(
|
||||
newNativeEnum.name,
|
||||
newNativeEnum.items,
|
||||
this.getSchemaName(newNativeEnum, options),
|
||||
);
|
||||
this.append(ret, sql);
|
||||
}
|
||||
}
|
||||
// Drop removed and changed views first (before modifying tables they may depend on)
|
||||
// Drop in reverse dependency order (dependent views first)
|
||||
if (options.dropTables && !options.safe) {
|
||||
const sortedRemovedViews = this.sortViewsByDependencies(Object.values(schemaDiff.removedViews)).reverse();
|
||||
for (const view of sortedRemovedViews) {
|
||||
if (view.materialized) {
|
||||
this.append(ret, this.helper.dropMaterializedViewIfExists(view.name, view.schema));
|
||||
} else {
|
||||
this.append(ret, this.helper.dropViewIfExists(view.name, view.schema));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Drop changed views (they will be recreated after table changes)
|
||||
// Also in reverse dependency order
|
||||
const changedViewsFrom = Object.values(schemaDiff.changedViews).map(v => v.from);
|
||||
const sortedChangedViewsFrom = this.sortViewsByDependencies(changedViewsFrom).reverse();
|
||||
for (const view of sortedChangedViewsFrom) {
|
||||
if (view.materialized) {
|
||||
this.append(ret, this.helper.dropMaterializedViewIfExists(view.name, view.schema));
|
||||
} else {
|
||||
this.append(ret, this.helper.dropViewIfExists(view.name, view.schema));
|
||||
}
|
||||
}
|
||||
if (!options.safe && this.options.createForeignKeyConstraints) {
|
||||
for (const orphanedForeignKey of schemaDiff.orphanedForeignKeys) {
|
||||
const [schemaName, tableName] = this.helper.splitTableName(orphanedForeignKey.localTableName, true);
|
||||
/* v8 ignore next */
|
||||
const name = (schemaName ? schemaName + '.' : '') + tableName;
|
||||
this.append(ret, this.helper.dropForeignKey(name, orphanedForeignKey.constraintName));
|
||||
}
|
||||
if (schemaDiff.orphanedForeignKeys.length > 0) {
|
||||
ret.push('');
|
||||
}
|
||||
}
|
||||
for (const newTable of Object.values(schemaDiff.newTables)) {
|
||||
this.append(ret, this.helper.createTable(newTable, true), true);
|
||||
}
|
||||
if (this.helper.supportsSchemaConstraints()) {
|
||||
for (const newTable of Object.values(schemaDiff.newTables)) {
|
||||
const sql = [];
|
||||
if (this.options.createForeignKeyConstraints) {
|
||||
const fks = Object.values(newTable.getForeignKeys()).map(fk => this.helper.createForeignKey(newTable, fk));
|
||||
this.append(sql, fks);
|
||||
}
|
||||
for (const check of newTable.getChecks()) {
|
||||
this.append(sql, this.helper.createCheck(newTable, check));
|
||||
}
|
||||
this.append(ret, sql, true);
|
||||
}
|
||||
}
|
||||
if (options.dropTables && !options.safe) {
|
||||
for (const table of Object.values(schemaDiff.removedTables)) {
|
||||
this.append(ret, this.helper.dropTableIfExists(table.name, table.schema));
|
||||
}
|
||||
if (Utils.hasObjectKeys(schemaDiff.removedTables)) {
|
||||
ret.push('');
|
||||
}
|
||||
}
|
||||
for (const changedTable of Object.values(schemaDiff.changedTables)) {
|
||||
this.append(ret, this.preAlterTable(changedTable, options.safe), true);
|
||||
}
|
||||
for (const changedTable of Object.values(schemaDiff.changedTables)) {
|
||||
this.append(ret, this.helper.alterTable(changedTable, options.safe), true);
|
||||
}
|
||||
for (const changedTable of Object.values(schemaDiff.changedTables)) {
|
||||
this.append(ret, this.helper.getPostAlterTable(changedTable, options.safe), true);
|
||||
}
|
||||
if (!options.safe && this.platform.supportsNativeEnums()) {
|
||||
for (const removedNativeEnum of schemaDiff.removedNativeEnums) {
|
||||
this.append(ret, this.helper.getDropNativeEnumSQL(removedNativeEnum.name, removedNativeEnum.schema));
|
||||
}
|
||||
}
|
||||
if (options.dropTables && !options.safe) {
|
||||
for (const removedNamespace of schemaDiff.removedNamespaces) {
|
||||
const sql = this.helper.getDropNamespaceSQL(removedNamespace);
|
||||
this.append(ret, sql);
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
return this.wrapSchema(ret, options);
|
||||
}
|
||||
/**
|
||||
* We need to drop foreign keys first for all tables to allow dropping PK constraints.
|
||||
*/
|
||||
preAlterTable(diff, safe) {
|
||||
const ret = [];
|
||||
this.append(ret, this.helper.getPreAlterTable(diff, safe));
|
||||
for (const foreignKey of Object.values(diff.removedForeignKeys)) {
|
||||
ret.push(this.helper.dropForeignKey(diff.toTable.getShortestName(), foreignKey.constraintName));
|
||||
}
|
||||
for (const foreignKey of Object.values(diff.changedForeignKeys)) {
|
||||
ret.push(this.helper.dropForeignKey(diff.toTable.getShortestName(), foreignKey.constraintName));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* creates new database and connects to it
|
||||
*/
|
||||
async createDatabase(name, options) {
|
||||
name ??= this.config.get('dbName');
|
||||
const sql = this.helper.getCreateDatabaseSQL(name);
|
||||
if (sql) {
|
||||
await this.execute(sql);
|
||||
}
|
||||
this.config.set('dbName', name);
|
||||
await this.driver.reconnect(options);
|
||||
}
|
||||
async dropDatabase(name) {
|
||||
name ??= this.config.get('dbName');
|
||||
this.config.set('dbName', this.helper.getManagementDbName());
|
||||
await this.driver.reconnect();
|
||||
await this.execute(this.helper.getDropDatabaseSQL(name));
|
||||
this.config.set('dbName', name);
|
||||
}
|
||||
async execute(sql, options = {}) {
|
||||
options.wrap ??= false;
|
||||
const lines = this.wrapSchema(sql, options).split('\n');
|
||||
const groups = [];
|
||||
let i = 0;
|
||||
for (const line of lines) {
|
||||
if (line.trim() === '') {
|
||||
if (groups[i]?.length > 0) {
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
groups[i] ??= [];
|
||||
groups[i].push(line.trim());
|
||||
}
|
||||
if (groups.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (this.platform.supportsMultipleStatements()) {
|
||||
for (const group of groups) {
|
||||
const query = group.join('\n');
|
||||
await this.driver.execute(query);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const statements = groups.flatMap(group => {
|
||||
return group
|
||||
.join('\n')
|
||||
.split(';\n')
|
||||
.map(s => s.trim())
|
||||
.filter(s => s);
|
||||
});
|
||||
await Utils.runSerial(statements, stmt => this.driver.execute(stmt));
|
||||
}
|
||||
async dropTableIfExists(name, schema) {
|
||||
const sql = this.helper.dropTableIfExists(name, schema);
|
||||
return this.execute(sql);
|
||||
}
|
||||
wrapSchema(sql, options) {
|
||||
const array = Utils.asArray(sql);
|
||||
if (array.length === 0) {
|
||||
return '';
|
||||
}
|
||||
if (array[array.length - 1] === '') {
|
||||
array.pop();
|
||||
}
|
||||
if (options.wrap === false) {
|
||||
return array.join('\n') + '\n';
|
||||
}
|
||||
let ret = this.helper.getSchemaBeginning(this.config.get('charset'), this.options.disableForeignKeys);
|
||||
ret += array.join('\n') + '\n';
|
||||
ret += this.helper.getSchemaEnd(this.options.disableForeignKeys);
|
||||
return ret;
|
||||
}
|
||||
append(array, sql, pad) {
|
||||
return this.helper.append(array, sql, pad);
|
||||
}
|
||||
matchName(name, nameToMatch) {
|
||||
return typeof nameToMatch === 'string'
|
||||
? name.toLocaleLowerCase() === nameToMatch.toLocaleLowerCase()
|
||||
: nameToMatch.test(name);
|
||||
}
|
||||
isTableSkipped(tableName, schemaName) {
|
||||
const skipTables = this.options.skipTables;
|
||||
if (!skipTables || skipTables.length === 0) {
|
||||
return false;
|
||||
}
|
||||
const fullTableName = schemaName ? `${schemaName}.${tableName}` : tableName;
|
||||
return skipTables.some(pattern => this.matchName(tableName, pattern) || this.matchName(fullTableName, pattern));
|
||||
}
|
||||
/**
|
||||
* Sorts views by their dependencies so that views depending on other views are created after their dependencies.
|
||||
* Uses topological sort based on view definition string matching.
|
||||
*/
|
||||
sortViewsByDependencies(views) {
|
||||
if (views.length <= 1) {
|
||||
return views;
|
||||
}
|
||||
// Use CommitOrderCalculator for topological sort
|
||||
const calc = new CommitOrderCalculator();
|
||||
// Map views to numeric indices for the calculator
|
||||
const viewToIndex = new Map();
|
||||
const indexToView = new Map();
|
||||
for (let i = 0; i < views.length; i++) {
|
||||
viewToIndex.set(views[i], i);
|
||||
indexToView.set(i, views[i]);
|
||||
calc.addNode(i);
|
||||
}
|
||||
// Check each view's definition for references to other view names
|
||||
for (const view of views) {
|
||||
const definition = view.definition.toLowerCase();
|
||||
const viewIndex = viewToIndex.get(view);
|
||||
for (const otherView of views) {
|
||||
if (otherView === view) {
|
||||
continue;
|
||||
}
|
||||
// Check if the definition references the other view's name
|
||||
// Use word boundary matching to avoid false positives
|
||||
const patterns = [new RegExp(`\\b${this.escapeRegExp(otherView.name.toLowerCase())}\\b`)];
|
||||
if (otherView.schema) {
|
||||
patterns.push(
|
||||
new RegExp(`\\b${this.escapeRegExp(`${otherView.schema}.${otherView.name}`.toLowerCase())}\\b`),
|
||||
);
|
||||
}
|
||||
for (const pattern of patterns) {
|
||||
if (pattern.test(definition)) {
|
||||
// view depends on otherView, so otherView must come first
|
||||
// addDependency(from, to) puts `from` before `to` in result
|
||||
const otherIndex = viewToIndex.get(otherView);
|
||||
calc.addDependency(otherIndex, viewIndex, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort and map back to views
|
||||
return calc.sort().map(index => indexToView.get(index));
|
||||
}
|
||||
escapeRegExp(string) {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
}
|
||||
// for back compatibility
|
||||
export { SqlSchemaGenerator as SchemaGenerator };
|
||||
Reference in New Issue
Block a user