mirror of
https://github.com/immich-app/immich.git
synced 2025-12-24 09:14:58 +03:00
feat: sql-tools overrides (#19796)
This commit is contained in:
74
server/src/sql-tools/contexts/base-context.ts
Normal file
74
server/src/sql-tools/contexts/base-context.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import {
|
||||
BaseContextOptions,
|
||||
DatabaseEnum,
|
||||
DatabaseExtension,
|
||||
DatabaseFunction,
|
||||
DatabaseOverride,
|
||||
DatabaseParameter,
|
||||
DatabaseSchema,
|
||||
DatabaseTable,
|
||||
} from 'src/sql-tools/types';
|
||||
|
||||
const asOverrideKey = (type: string, name: string) => `${type}:${name}`;
|
||||
|
||||
export class BaseContext {
|
||||
databaseName: string;
|
||||
schemaName: string;
|
||||
overrideTableName: string;
|
||||
|
||||
tables: DatabaseTable[] = [];
|
||||
functions: DatabaseFunction[] = [];
|
||||
enums: DatabaseEnum[] = [];
|
||||
extensions: DatabaseExtension[] = [];
|
||||
parameters: DatabaseParameter[] = [];
|
||||
overrides: DatabaseOverride[] = [];
|
||||
warnings: string[] = [];
|
||||
|
||||
constructor(options: BaseContextOptions) {
|
||||
this.databaseName = options.databaseName ?? 'postgres';
|
||||
this.schemaName = options.schemaName ?? 'public';
|
||||
this.overrideTableName = options.overrideTableName ?? 'migration_overrides';
|
||||
}
|
||||
|
||||
getTableByName(name: string) {
|
||||
return this.tables.find((table) => table.name === name);
|
||||
}
|
||||
|
||||
warn(context: string, message: string) {
|
||||
this.warnings.push(`[${context}] ${message}`);
|
||||
}
|
||||
|
||||
build(): DatabaseSchema {
|
||||
const overrideMap = new Map<string, DatabaseOverride>();
|
||||
for (const override of this.overrides) {
|
||||
const { type, name } = override.value;
|
||||
overrideMap.set(asOverrideKey(type, name), override);
|
||||
}
|
||||
|
||||
for (const func of this.functions) {
|
||||
func.override = overrideMap.get(asOverrideKey('function', func.name));
|
||||
}
|
||||
|
||||
for (const { indexes, triggers } of this.tables) {
|
||||
for (const index of indexes) {
|
||||
index.override = overrideMap.get(asOverrideKey('index', index.name));
|
||||
}
|
||||
|
||||
for (const trigger of triggers) {
|
||||
trigger.override = overrideMap.get(asOverrideKey('trigger', trigger.name));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
databaseName: this.databaseName,
|
||||
schemaName: this.schemaName,
|
||||
tables: this.tables,
|
||||
functions: this.functions,
|
||||
enums: this.enums,
|
||||
extensions: this.extensions,
|
||||
parameters: this.parameters,
|
||||
overrides: this.overrides,
|
||||
warnings: this.warnings,
|
||||
};
|
||||
}
|
||||
}
|
||||
84
server/src/sql-tools/contexts/processor-context.ts
Normal file
84
server/src/sql-tools/contexts/processor-context.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
||||
import { BaseContext } from 'src/sql-tools/contexts/base-context';
|
||||
import { ColumnOptions, TableOptions } from 'src/sql-tools/decorators';
|
||||
import { asKey } from 'src/sql-tools/helpers';
|
||||
import { DatabaseColumn, DatabaseTable, SchemaFromCodeOptions } from 'src/sql-tools/types';
|
||||
|
||||
type TableMetadata = { options: TableOptions; object: Function; methodToColumn: Map<string | symbol, DatabaseColumn> };
|
||||
|
||||
export class ProcessorContext extends BaseContext {
|
||||
constructor(public options: SchemaFromCodeOptions) {
|
||||
options.createForeignKeyIndexes = options.createForeignKeyIndexes ?? true;
|
||||
options.overrides = options.overrides ?? false;
|
||||
super(options);
|
||||
}
|
||||
|
||||
classToTable: WeakMap<Function, DatabaseTable> = new WeakMap();
|
||||
tableToMetadata: WeakMap<DatabaseTable, TableMetadata> = new WeakMap();
|
||||
|
||||
getTableByObject(object: Function) {
|
||||
return this.classToTable.get(object);
|
||||
}
|
||||
|
||||
getTableMetadata(table: DatabaseTable) {
|
||||
const metadata = this.tableToMetadata.get(table);
|
||||
if (!metadata) {
|
||||
throw new Error(`Table metadata not found for table: ${table.name}`);
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
addTable(table: DatabaseTable, options: TableOptions, object: Function) {
|
||||
this.tables.push(table);
|
||||
this.classToTable.set(object, table);
|
||||
this.tableToMetadata.set(table, { options, object, methodToColumn: new Map() });
|
||||
}
|
||||
|
||||
getColumnByObjectAndPropertyName(
|
||||
object: object,
|
||||
propertyName: string | symbol,
|
||||
): { table?: DatabaseTable; column?: DatabaseColumn } {
|
||||
const table = this.getTableByObject(object.constructor);
|
||||
if (!table) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const tableMetadata = this.tableToMetadata.get(table);
|
||||
if (!tableMetadata) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const column = tableMetadata.methodToColumn.get(propertyName);
|
||||
|
||||
return { table, column };
|
||||
}
|
||||
|
||||
addColumn(table: DatabaseTable, column: DatabaseColumn, options: ColumnOptions, propertyName: string | symbol) {
|
||||
table.columns.push(column);
|
||||
const tableMetadata = this.getTableMetadata(table);
|
||||
tableMetadata.methodToColumn.set(propertyName, column);
|
||||
}
|
||||
|
||||
asIndexName(table: string, columns?: string[], where?: string) {
|
||||
const items: string[] = [];
|
||||
for (const columnName of columns ?? []) {
|
||||
items.push(columnName);
|
||||
}
|
||||
|
||||
if (where) {
|
||||
items.push(where);
|
||||
}
|
||||
|
||||
return asKey('IDX_', table, items);
|
||||
}
|
||||
|
||||
warnMissingTable(context: string, object: object, propertyName?: symbol | string) {
|
||||
const label = object.constructor.name + (propertyName ? '.' + String(propertyName) : '');
|
||||
this.warn(context, `Unable to find table (${label})`);
|
||||
}
|
||||
|
||||
warnMissingColumn(context: string, object: object, propertyName?: symbol | string) {
|
||||
const label = object.constructor.name + (propertyName ? '.' + String(propertyName) : '');
|
||||
this.warn(context, `Unable to find column (${label})`);
|
||||
}
|
||||
}
|
||||
8
server/src/sql-tools/contexts/reader-context.ts
Normal file
8
server/src/sql-tools/contexts/reader-context.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { BaseContext } from 'src/sql-tools/contexts/base-context';
|
||||
import { SchemaFromDatabaseOptions } from 'src/sql-tools/types';
|
||||
|
||||
export class ReaderContext extends BaseContext {
|
||||
constructor(public options: SchemaFromDatabaseOptions) {
|
||||
super(options);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user