feat: sql-tools overrides (#19796)

This commit is contained in:
Jason Rasmussen
2025-07-08 08:17:40 -04:00
committed by GitHub
parent 1f9813a28e
commit df4a27e8a7
114 changed files with 775 additions and 289 deletions

View File

@@ -1,13 +1,13 @@
import { asKey } from 'src/sql-tools/helpers';
import { ConstraintType, Processor } from 'src/sql-tools/types';
export const processCheckConstraints: Processor = (builder, items) => {
export const processCheckConstraints: Processor = (ctx, items) => {
for (const {
item: { object, options },
} of items.filter((item) => item.type === 'checkConstraint')) {
const table = builder.getTableByObject(object);
const table = ctx.getTableByObject(object);
if (!table) {
builder.warnMissingTable('@Check', object);
ctx.warnMissingTable('@Check', object);
continue;
}

View File

@@ -2,14 +2,14 @@ import { ColumnOptions } from 'src/sql-tools/decorators/column.decorator';
import { fromColumnValue } from 'src/sql-tools/helpers';
import { Processor } from 'src/sql-tools/types';
export const processColumns: Processor = (builder, items) => {
export const processColumns: Processor = (ctx, items) => {
for (const {
type,
item: { object, propertyName, options },
} of items.filter((item) => item.type === 'column' || item.type === 'foreignKeyColumn')) {
const table = builder.getTableByObject(object.constructor);
const table = ctx.getTableByObject(object.constructor);
if (!table) {
builder.warnMissingTable(type === 'column' ? '@Column' : '@ForeignKeyColumn', object, propertyName);
ctx.warnMissingTable(type === 'column' ? '@Column' : '@ForeignKeyColumn', object, propertyName);
continue;
}
@@ -31,7 +31,7 @@ export const processColumns: Processor = (builder, items) => {
const isEnum = !!(options as ColumnOptions).enum;
builder.addColumn(
ctx.addColumn(
table,
{
name: columnName,

View File

@@ -1,12 +1,12 @@
import { fromColumnValue } from 'src/sql-tools/helpers';
import { Processor } from 'src/sql-tools/types';
export const processConfigurationParameters: Processor = (builder, items) => {
export const processConfigurationParameters: Processor = (ctx, items) => {
for (const {
item: { options },
} of items.filter((item) => item.type === 'configurationParameter')) {
builder.parameters.push({
databaseName: builder.databaseName,
ctx.parameters.push({
databaseName: ctx.databaseName,
name: options.name,
value: fromColumnValue(options.value),
scope: options.scope,

View File

@@ -1,10 +1,10 @@
import { asSnakeCase } from 'src/sql-tools/helpers';
import { Processor } from 'src/sql-tools/types';
export const processDatabases: Processor = (builder, items) => {
export const processDatabases: Processor = (ctx, items) => {
for (const {
item: { object, options },
} of items.filter((item) => item.type === 'database')) {
builder.databaseName = options.name || asSnakeCase(object.name);
ctx.databaseName = options.name || asSnakeCase(object.name);
}
};

View File

@@ -1,8 +1,8 @@
import { Processor } from 'src/sql-tools/types';
export const processEnums: Processor = (builder, items) => {
export const processEnums: Processor = (ctx, items) => {
for (const { item } of items.filter((item) => item.type === 'enum')) {
// TODO log warnings if enum name is not unique
builder.enums.push(item);
ctx.enums.push(item);
}
};

View File

@@ -1,10 +1,14 @@
import { Processor } from 'src/sql-tools/types';
export const processExtensions: Processor = (builder, items) => {
export const processExtensions: Processor = (ctx, items) => {
if (ctx.options.extensions === false) {
return;
}
for (const {
item: { options },
} of items.filter((item) => item.type === 'extension')) {
builder.extensions.push({
ctx.extensions.push({
name: options.name,
synchronize: options.synchronize ?? true,
});

View File

@@ -1,25 +1,25 @@
import { asForeignKeyConstraintName, asKey } from 'src/sql-tools/helpers';
import { ActionType, ConstraintType, Processor } from 'src/sql-tools/types';
export const processForeignKeyColumns: Processor = (builder, items) => {
export const processForeignKeyColumns: Processor = (ctx, items) => {
for (const {
item: { object, propertyName, options, target },
} of items.filter((item) => item.type === 'foreignKeyColumn')) {
const { table, column } = builder.getColumnByObjectAndPropertyName(object, propertyName);
const { table, column } = ctx.getColumnByObjectAndPropertyName(object, propertyName);
if (!table) {
builder.warnMissingTable('@ForeignKeyColumn', object);
ctx.warnMissingTable('@ForeignKeyColumn', object);
continue;
}
if (!column) {
// should be impossible since they are pre-created in `column.processor.ts`
builder.warnMissingColumn('@ForeignKeyColumn', object, propertyName);
ctx.warnMissingColumn('@ForeignKeyColumn', object, propertyName);
continue;
}
const referenceTable = builder.getTableByObject(target());
const referenceTable = ctx.getTableByObject(target());
if (!referenceTable) {
builder.warnMissingTable('@ForeignKeyColumn', object, propertyName);
ctx.warnMissingTable('@ForeignKeyColumn', object, propertyName);
continue;
}

View File

@@ -1,20 +1,20 @@
import { asForeignKeyConstraintName } from 'src/sql-tools/helpers';
import { ActionType, ConstraintType, Processor } from 'src/sql-tools/types';
export const processForeignKeyConstraints: Processor = (builder, items, config) => {
export const processForeignKeyConstraints: Processor = (ctx, items) => {
for (const {
item: { object, options },
} of items.filter((item) => item.type === 'foreignKeyConstraint')) {
const table = builder.getTableByObject(object);
const table = ctx.getTableByObject(object);
if (!table) {
builder.warnMissingTable('@ForeignKeyConstraint', { name: 'referenceTable' });
ctx.warnMissingTable('@ForeignKeyConstraint', { name: 'referenceTable' });
continue;
}
const referenceTable = builder.getTableByObject(options.referenceTable());
const referenceTable = ctx.getTableByObject(options.referenceTable());
if (!referenceTable) {
const referenceTableName = options.referenceTable()?.name;
builder.warn(
ctx.warn(
'@ForeignKeyConstraint.referenceTable',
`Unable to find table` + (referenceTableName ? ` (${referenceTableName})` : ''),
);
@@ -25,16 +25,16 @@ export const processForeignKeyConstraints: Processor = (builder, items, config)
for (const columnName of options.columns) {
if (!table.columns.some(({ name }) => name === columnName)) {
const metadata = builder.getTableMetadata(table);
builder.warn('@ForeignKeyConstraint.columns', `Unable to find column (${metadata.object.name}.${columnName})`);
const metadata = ctx.getTableMetadata(table);
ctx.warn('@ForeignKeyConstraint.columns', `Unable to find column (${metadata.object.name}.${columnName})`);
missingColumn = true;
}
}
for (const columnName of options.referenceColumns || []) {
if (!referenceTable.columns.some(({ name }) => name === columnName)) {
const metadata = builder.getTableMetadata(referenceTable);
builder.warn(
const metadata = ctx.getTableMetadata(referenceTable);
ctx.warn(
'@ForeignKeyConstraint.referenceColumns',
`Unable to find column (${metadata.object.name}.${columnName})`,
);
@@ -67,9 +67,9 @@ export const processForeignKeyConstraints: Processor = (builder, items, config)
continue;
}
if (options.index || options.indexName || config.createForeignKeyIndexes) {
if (options.index || options.indexName || ctx.options.createForeignKeyIndexes) {
table.indexes.push({
name: options.indexName || builder.asIndexName(table.name, options.columns),
name: options.indexName || ctx.asIndexName(table.name, options.columns),
tableName: table.name,
columnNames: options.columns,
unique: false,

View File

@@ -1,8 +1,12 @@
import { Processor } from 'src/sql-tools/types';
export const processFunctions: Processor = (builder, items) => {
export const processFunctions: Processor = (ctx, items) => {
if (ctx.options.functions === false) {
return;
}
for (const { item } of items.filter((item) => item.type === 'function')) {
// TODO log warnings if function name is not unique
builder.functions.push(item);
ctx.functions.push(item);
}
};

View File

@@ -1,17 +1,17 @@
import { Processor } from 'src/sql-tools/types';
export const processIndexes: Processor = (builder, items, config) => {
export const processIndexes: Processor = (ctx, items) => {
for (const {
item: { object, options },
} of items.filter((item) => item.type === 'index')) {
const table = builder.getTableByObject(object);
const table = ctx.getTableByObject(object);
if (!table) {
builder.warnMissingTable('@Check', object);
ctx.warnMissingTable('@Check', object);
continue;
}
table.indexes.push({
name: options.name || builder.asIndexName(table.name, options.columns, options.where),
name: options.name || ctx.asIndexName(table.name, options.columns, options.where),
tableName: table.name,
unique: options.unique ?? false,
expression: options.expression,
@@ -28,15 +28,15 @@ export const processIndexes: Processor = (builder, items, config) => {
type,
item: { object, propertyName, options },
} of items.filter((item) => item.type === 'column' || item.type === 'foreignKeyColumn')) {
const { table, column } = builder.getColumnByObjectAndPropertyName(object, propertyName);
const { table, column } = ctx.getColumnByObjectAndPropertyName(object, propertyName);
if (!table) {
builder.warnMissingTable('@Column', object);
ctx.warnMissingTable('@Column', object);
continue;
}
if (!column) {
// should be impossible since they are created in `column.processor.ts`
builder.warnMissingColumn('@Column', object, propertyName);
ctx.warnMissingColumn('@Column', object, propertyName);
continue;
}
@@ -45,12 +45,12 @@ export const processIndexes: Processor = (builder, items, config) => {
}
const isIndexRequested =
options.indexName || options.index || (type === 'foreignKeyColumn' && config.createForeignKeyIndexes);
options.indexName || options.index || (type === 'foreignKeyColumn' && ctx.options.createForeignKeyIndexes);
if (!isIndexRequested) {
continue;
}
const indexName = options.indexName || builder.asIndexName(table.name, [column.name]);
const indexName = options.indexName || ctx.asIndexName(table.name, [column.name]);
const isIndexPresent = table.indexes.some((index) => index.name === indexName);
if (isIndexPresent) {

View File

@@ -8,6 +8,7 @@ import { processForeignKeyColumns } from 'src/sql-tools/processors/foreign-key-c
import { processForeignKeyConstraints } from 'src/sql-tools/processors/foreign-key-constraint.processor';
import { processFunctions } from 'src/sql-tools/processors/function.processor';
import { processIndexes } from 'src/sql-tools/processors/index.processor';
import { processOverrides } from 'src/sql-tools/processors/override.processor';
import { processPrimaryKeyConstraints } from 'src/sql-tools/processors/primary-key-contraint.processor';
import { processTables } from 'src/sql-tools/processors/table.processor';
import { processTriggers } from 'src/sql-tools/processors/trigger.processor';
@@ -29,4 +30,5 @@ export const processors: Processor[] = [
processPrimaryKeyConstraints,
processIndexes,
processTriggers,
processOverrides,
];

View File

@@ -0,0 +1,50 @@
import { asFunctionCreate } from 'src/sql-tools/transformers/function.transformer';
import { asIndexCreate } from 'src/sql-tools/transformers/index.transformer';
import { asTriggerCreate } from 'src/sql-tools/transformers/trigger.transformer';
import { Processor } from 'src/sql-tools/types';
export const processOverrides: Processor = (ctx) => {
if (ctx.options.overrides === false) {
return;
}
for (const func of ctx.functions) {
if (!func.synchronize) {
continue;
}
ctx.overrides.push({
name: `function_${func.name}`,
value: { type: 'function', name: func.name, sql: asFunctionCreate(func) },
synchronize: true,
});
}
for (const { triggers, indexes } of ctx.tables) {
for (const trigger of triggers) {
if (!trigger.synchronize) {
continue;
}
ctx.overrides.push({
name: `trigger_${trigger.name}`,
value: { type: 'trigger', name: trigger.name, sql: asTriggerCreate(trigger) },
synchronize: true,
});
}
for (const index of indexes) {
if (!index.synchronize) {
continue;
}
if (index.expression || index.using || index.with || index.where) {
ctx.overrides.push({
name: `index_${index.name}`,
value: { type: 'index', name: index.name, sql: asIndexCreate(index) },
synchronize: true,
});
}
}
}
};

View File

@@ -1,8 +1,8 @@
import { asKey } from 'src/sql-tools/helpers';
import { ConstraintType, Processor } from 'src/sql-tools/types';
export const processPrimaryKeyConstraints: Processor = (builder) => {
for (const table of builder.tables) {
export const processPrimaryKeyConstraints: Processor = (ctx) => {
for (const table of ctx.tables) {
const columnNames: string[] = [];
for (const column of table.columns) {
@@ -12,7 +12,7 @@ export const processPrimaryKeyConstraints: Processor = (builder) => {
}
if (columnNames.length > 0) {
const tableMetadata = builder.getTableMetadata(table);
const tableMetadata = ctx.getTableMetadata(table);
table.constraints.push({
type: ConstraintType.PRIMARY_KEY,
name: tableMetadata.options.primaryConstraintName || asPrimaryKeyConstraintName(table.name, columnNames),

View File

@@ -1,18 +1,18 @@
import { asSnakeCase } from 'src/sql-tools/helpers';
import { Processor } from 'src/sql-tools/types';
export const processTables: Processor = (builder, items) => {
export const processTables: Processor = (ctx, items) => {
for (const {
item: { options, object },
} of items.filter((item) => item.type === 'table')) {
const test = builder.getTableByObject(object);
const test = ctx.getTableByObject(object);
if (test) {
throw new Error(
`Table ${test.name} has already been registered. Does ${object.name} have two @Table() decorators?`,
);
}
builder.addTable(
ctx.addTable(
{
name: options.name || asSnakeCase(object.name),
columns: [],

View File

@@ -2,13 +2,13 @@ import { TriggerOptions } from 'src/sql-tools/decorators/trigger.decorator';
import { asKey } from 'src/sql-tools/helpers';
import { Processor } from 'src/sql-tools/types';
export const processTriggers: Processor = (builder, items) => {
export const processTriggers: Processor = (ctx, items) => {
for (const {
item: { object, options },
} of items.filter((item) => item.type === 'trigger')) {
const table = builder.getTableByObject(object);
const table = ctx.getTableByObject(object);
if (!table) {
builder.warnMissingTable('@Trigger', object);
ctx.warnMissingTable('@Trigger', object);
continue;
}

View File

@@ -1,13 +1,13 @@
import { asKey } from 'src/sql-tools/helpers';
import { ConstraintType, Processor } from 'src/sql-tools/types';
export const processUniqueConstraints: Processor = (builder, items) => {
export const processUniqueConstraints: Processor = (ctx, items) => {
for (const {
item: { object, options },
} of items.filter((item) => item.type === 'uniqueConstraint')) {
const table = builder.getTableByObject(object);
const table = ctx.getTableByObject(object);
if (!table) {
builder.warnMissingTable('@Unique', object);
ctx.warnMissingTable('@Unique', object);
continue;
}
@@ -28,15 +28,15 @@ export const processUniqueConstraints: Processor = (builder, items) => {
type,
item: { object, propertyName, options },
} of items.filter((item) => item.type === 'column' || item.type === 'foreignKeyColumn')) {
const { table, column } = builder.getColumnByObjectAndPropertyName(object, propertyName);
const { table, column } = ctx.getColumnByObjectAndPropertyName(object, propertyName);
if (!table) {
builder.warnMissingTable('@Column', object);
ctx.warnMissingTable('@Column', object);
continue;
}
if (!column) {
// should be impossible since they are created in `column.processor.ts`
builder.warnMissingColumn('@Column', object, propertyName);
ctx.warnMissingColumn('@Column', object, propertyName);
continue;
}