refactor: sql-tools (#19717)

This commit is contained in:
Jason Rasmussen
2025-07-03 10:59:17 -04:00
committed by GitHub
parent 484529e61e
commit 6044663e26
160 changed files with 1120 additions and 1186 deletions

View File

@@ -0,0 +1,8 @@
import { TriggerFunction, TriggerFunctionOptions } from 'src/sql-tools/decorators/trigger-function.decorator';
export const AfterDeleteTrigger = (options: Omit<TriggerFunctionOptions, 'timing' | 'actions'>) =>
TriggerFunction({
timing: 'after',
actions: ['delete'],
...options,
});

View File

@@ -0,0 +1,8 @@
import { TriggerFunction, TriggerFunctionOptions } from 'src/sql-tools/decorators/trigger-function.decorator';
export const AfterInsertTrigger = (options: Omit<TriggerFunctionOptions, 'timing' | 'actions'>) =>
TriggerFunction({
timing: 'after',
actions: ['insert'],
...options,
});

View File

@@ -0,0 +1,8 @@
import { TriggerFunction, TriggerFunctionOptions } from 'src/sql-tools/decorators/trigger-function.decorator';
export const BeforeUpdateTrigger = (options: Omit<TriggerFunctionOptions, 'timing' | 'actions'>) =>
TriggerFunction({
timing: 'before',
actions: ['update'],
...options,
});

View File

@@ -0,0 +1,11 @@
import { register } from 'src/sql-tools/register';
export type CheckOptions = {
name?: string;
expression: string;
synchronize?: boolean;
};
export const Check = (options: CheckOptions): ClassDecorator => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
return (object: Function) => void register({ type: 'checkConstraint', item: { object, options } });
};

View File

@@ -0,0 +1,32 @@
import { asOptions } from 'src/sql-tools/helpers';
import { register } from 'src/sql-tools/register';
import { ColumnStorage, ColumnType, DatabaseEnum } from 'src/sql-tools/types';
export type ColumnValue = null | boolean | string | number | object | Date | (() => string);
export type ColumnBaseOptions = {
name?: string;
primary?: boolean;
type?: ColumnType;
nullable?: boolean;
length?: number;
default?: ColumnValue;
comment?: string;
synchronize?: boolean;
storage?: ColumnStorage;
identity?: boolean;
index?: boolean;
indexName?: string;
unique?: boolean;
uniqueConstraintName?: string;
};
export type ColumnOptions = ColumnBaseOptions & {
enum?: DatabaseEnum;
array?: boolean;
};
export const Column = (options: string | ColumnOptions = {}): PropertyDecorator => {
return (object: object, propertyName: string | symbol) =>
void register({ type: 'column', item: { object, propertyName, options: asOptions(options) } });
};

View File

@@ -0,0 +1,14 @@
import { ColumnValue } from 'src/sql-tools/decorators/column.decorator';
import { register } from 'src/sql-tools/register';
import { ParameterScope } from 'src/sql-tools/types';
export type ConfigurationParameterOptions = {
name: string;
value: ColumnValue;
scope: ParameterScope;
synchronize?: boolean;
};
export const ConfigurationParameter = (options: ConfigurationParameterOptions): ClassDecorator => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
return (object: Function) => void register({ type: 'configurationParameter', item: { object, options } });
};

View File

@@ -0,0 +1,9 @@
import { Column, ColumnOptions } from 'src/sql-tools/decorators/column.decorator';
export const CreateDateColumn = (options: ColumnOptions = {}): PropertyDecorator => {
return Column({
type: 'timestamp with time zone',
default: () => 'now()',
...options,
});
};

View File

@@ -0,0 +1,10 @@
import { register } from 'src/sql-tools/register';
export type DatabaseOptions = {
name?: string;
synchronize?: boolean;
};
export const Database = (options: DatabaseOptions): ClassDecorator => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
return (object: Function) => void register({ type: 'database', item: { object, options } });
};

View File

@@ -0,0 +1,9 @@
import { Column, ColumnOptions } from 'src/sql-tools/decorators/column.decorator';
export const DeleteDateColumn = (options: ColumnOptions = {}): PropertyDecorator => {
return Column({
type: 'timestamp with time zone',
nullable: true,
...options,
});
};

View File

@@ -0,0 +1,11 @@
import { asOptions } from 'src/sql-tools/helpers';
import { register } from 'src/sql-tools/register';
export type ExtensionOptions = {
name: string;
synchronize?: boolean;
};
export const Extension = (options: string | ExtensionOptions): ClassDecorator => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
return (object: Function) => void register({ type: 'extension', item: { object, options: asOptions(options) } });
};

View File

@@ -0,0 +1,15 @@
import { asOptions } from 'src/sql-tools/helpers';
import { register } from 'src/sql-tools/register';
export type ExtensionsOptions = {
name: string;
synchronize?: boolean;
};
export const Extensions = (options: Array<string | ExtensionsOptions>): ClassDecorator => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
return (object: Function) => {
for (const option of options) {
register({ type: 'extension', item: { object, options: asOptions(option) } });
}
};
};

View File

@@ -0,0 +1,16 @@
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
import { ForeignKeyAction } from 'src/sql-tools//decorators/foreign-key-constraint.decorator';
import { ColumnBaseOptions } from 'src/sql-tools/decorators/column.decorator';
import { register } from 'src/sql-tools/register';
export type ForeignKeyColumnOptions = ColumnBaseOptions & {
onUpdate?: ForeignKeyAction;
onDelete?: ForeignKeyAction;
constraintName?: string;
};
export const ForeignKeyColumn = (target: () => Function, options: ForeignKeyColumnOptions): PropertyDecorator => {
return (object: object, propertyName: string | symbol) => {
register({ type: 'foreignKeyColumn', item: { object, propertyName, options, target } });
};
};

View File

@@ -0,0 +1,23 @@
import { register } from 'src/sql-tools/register';
export type ForeignKeyAction = 'CASCADE' | 'SET NULL' | 'SET DEFAULT' | 'RESTRICT' | 'NO ACTION';
export type ForeignKeyConstraintOptions = {
name?: string;
index?: boolean;
indexName?: string;
columns: string[];
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
referenceTable: () => Function;
referenceColumns?: string[];
onUpdate?: ForeignKeyAction;
onDelete?: ForeignKeyAction;
synchronize?: boolean;
};
export const ForeignKeyConstraint = (options: ForeignKeyConstraintOptions): ClassDecorator => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
return (target: Function) => {
register({ type: 'foreignKeyConstraint', item: { object: target, options } });
};
};

View File

@@ -0,0 +1,37 @@
import { Column, ColumnOptions, ColumnValue } from 'src/sql-tools/decorators/column.decorator';
import { ColumnType } from 'src/sql-tools/types';
export type GeneratedColumnStrategy = 'uuid' | 'identity';
export type GenerateColumnOptions = Omit<ColumnOptions, 'type'> & {
strategy?: GeneratedColumnStrategy;
};
export const GeneratedColumn = ({ strategy = 'uuid', ...options }: GenerateColumnOptions): PropertyDecorator => {
let columnType: ColumnType | undefined;
let columnDefault: ColumnValue | undefined;
switch (strategy) {
case 'uuid': {
columnType = 'uuid';
columnDefault = () => 'uuid_generate_v4()';
break;
}
case 'identity': {
columnType = 'integer';
options.identity = true;
break;
}
default: {
throw new Error(`Unsupported strategy for @GeneratedColumn ${strategy}`);
}
}
return Column({
type: columnType,
default: columnDefault,
...options,
});
};

View File

@@ -0,0 +1,17 @@
import { asOptions } from 'src/sql-tools/helpers';
import { register } from 'src/sql-tools/register';
export type IndexOptions = {
name?: string;
unique?: boolean;
expression?: string;
using?: string;
with?: string;
where?: string;
columns?: string[];
synchronize?: boolean;
};
export const Index = (options: string | IndexOptions = {}): ClassDecorator => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
return (object: Function) => void register({ type: 'index', item: { object, options: asOptions(options) } });
};

View File

@@ -0,0 +1,22 @@
export * from 'src/sql-tools/decorators/after-delete.decorator';
export * from 'src/sql-tools/decorators/after-insert.decorator';
export * from 'src/sql-tools/decorators/before-update.decorator';
export * from 'src/sql-tools/decorators/check.decorator';
export * from 'src/sql-tools/decorators/column.decorator';
export * from 'src/sql-tools/decorators/configuration-parameter.decorator';
export * from 'src/sql-tools/decorators/create-date-column.decorator';
export * from 'src/sql-tools/decorators/database.decorator';
export * from 'src/sql-tools/decorators/delete-date-column.decorator';
export * from 'src/sql-tools/decorators/extension.decorator';
export * from 'src/sql-tools/decorators/extensions.decorator';
export * from 'src/sql-tools/decorators/foreign-key-column.decorator';
export * from 'src/sql-tools/decorators/foreign-key-constraint.decorator';
export * from 'src/sql-tools/decorators/generated-column.decorator';
export * from 'src/sql-tools/decorators/index.decorator';
export * from 'src/sql-tools/decorators/primary-column.decorator';
export * from 'src/sql-tools/decorators/primary-generated-column.decorator';
export * from 'src/sql-tools/decorators/table.decorator';
export * from 'src/sql-tools/decorators/trigger-function.decorator';
export * from 'src/sql-tools/decorators/trigger.decorator';
export * from 'src/sql-tools/decorators/unique.decorator';
export * from 'src/sql-tools/decorators/update-date-column.decorator';

View File

@@ -0,0 +1,3 @@
import { Column, ColumnOptions } from 'src/sql-tools/decorators/column.decorator';
export const PrimaryColumn = (options: Omit<ColumnOptions, 'primary'> = {}) => Column({ ...options, primary: true });

View File

@@ -0,0 +1,4 @@
import { GenerateColumnOptions, GeneratedColumn } from 'src/sql-tools/decorators/generated-column.decorator';
export const PrimaryGeneratedColumn = (options: Omit<GenerateColumnOptions, 'primary'> = {}) =>
GeneratedColumn({ ...options, primary: true });

View File

@@ -0,0 +1,14 @@
import { asOptions } from 'src/sql-tools/helpers';
import { register } from 'src/sql-tools/register';
export type TableOptions = {
name?: string;
primaryConstraintName?: string;
synchronize?: boolean;
};
/** Table comments here */
export const Table = (options: string | TableOptions = {}): ClassDecorator => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
return (object: Function) => void register({ type: 'table', item: { object, options: asOptions(options) } });
};

View File

@@ -0,0 +1,10 @@
import { Trigger, TriggerOptions } from 'src/sql-tools/decorators/trigger.decorator';
import { DatabaseFunction } from 'src/sql-tools/types';
export type TriggerFunctionOptions = Omit<TriggerOptions, 'functionName'> & { function: DatabaseFunction };
export const TriggerFunction = (options: TriggerFunctionOptions) =>
Trigger({
name: options.function.name,
...options,
functionName: options.function.name,
});

View File

@@ -0,0 +1,19 @@
import { register } from 'src/sql-tools/register';
import { TriggerAction, TriggerScope, TriggerTiming } from 'src/sql-tools/types';
export type TriggerOptions = {
name?: string;
timing: TriggerTiming;
actions: TriggerAction[];
scope: TriggerScope;
functionName: string;
referencingNewTableAs?: string;
referencingOldTableAs?: string;
when?: string;
synchronize?: boolean;
};
export const Trigger = (options: TriggerOptions): ClassDecorator => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
return (object: Function) => void register({ type: 'trigger', item: { object, options } });
};

View File

@@ -0,0 +1,11 @@
import { register } from 'src/sql-tools/register';
export type UniqueOptions = {
name?: string;
columns: string[];
synchronize?: boolean;
};
export const Unique = (options: UniqueOptions): ClassDecorator => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
return (object: Function) => void register({ type: 'uniqueConstraint', item: { object, options } });
};

View File

@@ -0,0 +1,9 @@
import { Column, ColumnOptions } from 'src/sql-tools/decorators/column.decorator';
export const UpdateDateColumn = (options: ColumnOptions = {}): PropertyDecorator => {
return Column({
type: 'timestamp with time zone',
default: () => 'now()',
...options,
});
};