Skip to content

Commit

Permalink
chore: add Reversible type (#1095)
Browse files Browse the repository at this point in the history
  • Loading branch information
Shinigami92 committed Apr 17, 2024
1 parent 289cea9 commit d49217a
Show file tree
Hide file tree
Showing 42 changed files with 172 additions and 127 deletions.
6 changes: 6 additions & 0 deletions src/index.ts
Expand Up @@ -33,7 +33,13 @@ export type {
DropOptions,
IfExistsOption,
IfNotExistsOption,
LiteralUnion,
Name,
Nullable,
Operation,
OperationFn,
PublicPart,
Reversible,
Type,
Value,
} from './operations/generalTypes';
Expand Down
25 changes: 11 additions & 14 deletions src/migration-builder.ts
Expand Up @@ -12,6 +12,7 @@
import * as domains from './operations/domains';
import * as extensions from './operations/extensions';
import * as functions from './operations/functions';
import type { Operation } from './operations/generalTypes';
import * as indexes from './operations/indexes';
import * as mViews from './operations/materializedViews';
import * as operators from './operations/operators';
Expand Down Expand Up @@ -311,19 +312,15 @@ export default class MigrationBuilderImpl implements MigrationBuilder {
) {
this._steps = [];
this._REVERSE_MODE = false;
// by default, all migrations are wrapped in a transaction
// By default, all migrations are wrapped in a transaction
this._useTransaction = true;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type OperationFn = (...args: any[]) => string | string[];
type Operation = OperationFn & { reverse?: OperationFn };

// this function wraps each operation within a function that either
// calls the operation or its reverse, and appends the result (array of sql statements)
// to the steps array
// This function wraps each operation within a function that either calls
// the operation or its reverse, and appends the result
// (array of sql statements) to the steps array
const wrap =
<T extends Operation>(operation: T) =>
(...args: Parameters<T>) => {
<TOperation extends Operation>(operation: TOperation) =>
(...args: Parameters<TOperation>) => {
if (this._REVERSE_MODE) {
if (typeof operation.reverse !== 'function') {
const name = `pgm.${operation.name}()`;
Expand All @@ -345,8 +342,8 @@ export default class MigrationBuilderImpl implements MigrationBuilder {
logger,
};

// defines the methods that are accessible via pgm in each migrations
// there are some convenience aliases to make usage easier
// Defines the methods that are accessible via pgm in each migrations there
// are some convenience aliases to make usage easier
this.createExtension = wrap(extensions.createExtension(options));
this.dropExtension = wrap(extensions.dropExtension(options));
this.addExtension = this.createExtension;
Expand Down Expand Up @@ -452,7 +449,7 @@ export default class MigrationBuilderImpl implements MigrationBuilder {
// common uses are for PG functions, ex: { ... default: pgm.func('NOW()') }
this.func = PgLiteral.create;

// expose DB so we can access database within transaction
// Expose DB so we can access database within transaction
/* eslint-disable @typescript-eslint/no-explicit-any */
const wrapDB =
<T extends any[], TResult>(operation: (...args: T) => TResult) =>
Expand Down Expand Up @@ -490,7 +487,7 @@ export default class MigrationBuilderImpl implements MigrationBuilder {
}

getSqlSteps(): string[] {
// in reverse mode, we flip the order of the statements
// In reverse mode, we flip the order of the statements
return this._REVERSE_MODE ? this._steps.slice().reverse() : this._steps;
}
}
4 changes: 2 additions & 2 deletions src/operations/domains/createDomain.ts
@@ -1,6 +1,6 @@
import type { MigrationOptions } from '../../types';
import { applyType, escapeValue } from '../../utils';
import type { DropOptions, Name, Type } from '../generalTypes';
import type { DropOptions, Name, Reversible, Type } from '../generalTypes';
import { dropDomain } from './dropDomain';
import type { DomainOptions } from './shared';

Expand All @@ -14,7 +14,7 @@ export type CreateDomainFn = (
domainOptions?: DomainOptionsCreate & DropOptions
) => string | string[];

export type CreateDomain = CreateDomainFn & { reverse: CreateDomainFn };
export type CreateDomain = Reversible<CreateDomainFn>;

export function createDomain(mOptions: MigrationOptions): CreateDomain {
const _create: CreateDomain = (domainName, type, options = {}) => {
Expand Down
4 changes: 2 additions & 2 deletions src/operations/domains/renameDomain.ts
@@ -1,12 +1,12 @@
import type { MigrationOptions } from '../../types';
import type { Name } from '../generalTypes';
import type { Name, Reversible } from '../generalTypes';

export type RenameDomainFn = (
oldDomainName: Name,
newDomainName: Name
) => string | string[];

export type RenameDomain = RenameDomainFn & { reverse: RenameDomainFn };
export type RenameDomain = Reversible<RenameDomainFn>;

export function renameDomain(mOptions: MigrationOptions): RenameDomain {
const _rename: RenameDomain = (domainName, newDomainName) => {
Expand Down
10 changes: 6 additions & 4 deletions src/operations/extensions/createExtension.ts
@@ -1,5 +1,9 @@
import type { MigrationOptions } from '../../types';
import type { DropOptions, IfNotExistsOption } from '../generalTypes';
import type {
DropOptions,
IfNotExistsOption,
Reversible,
} from '../generalTypes';
import { dropExtension } from './dropExtension';
import type { StringExtension } from './shared';

Expand All @@ -12,9 +16,7 @@ export type CreateExtensionFn = (
options?: CreateExtensionOptions & DropOptions
) => string | string[];

export type CreateExtension = CreateExtensionFn & {
reverse: CreateExtensionFn;
};
export type CreateExtension = Reversible<CreateExtensionFn>;

export function createExtension(mOptions: MigrationOptions): CreateExtension {
const _create: CreateExtension = (_extensions, options = {}) => {
Expand Down
4 changes: 2 additions & 2 deletions src/operations/functions/createFunction.ts
@@ -1,6 +1,6 @@
import type { MigrationOptions } from '../../types';
import { escapeValue, formatParams } from '../../utils';
import type { DropOptions, Name, Value } from '../generalTypes';
import type { DropOptions, Name, Reversible, Value } from '../generalTypes';
import { dropFunction } from './dropFunction';
import type { FunctionOptions, FunctionParam } from './shared';

Expand All @@ -11,7 +11,7 @@ export type CreateFunctionFn = (
definition: Value
) => string | string[];

export type CreateFunction = CreateFunctionFn & { reverse: CreateFunctionFn };
export type CreateFunction = Reversible<CreateFunctionFn>;

export function createFunction(mOptions: MigrationOptions): CreateFunction {
const _create: CreateFunction = (
Expand Down
4 changes: 2 additions & 2 deletions src/operations/functions/renameFunction.ts
@@ -1,6 +1,6 @@
import type { MigrationOptions } from '../../types';
import { formatParams } from '../../utils';
import type { Name } from '../generalTypes';
import type { Name, Reversible } from '../generalTypes';
import type { FunctionParam } from './shared';

export type RenameFunctionFn = (
Expand All @@ -9,7 +9,7 @@ export type RenameFunctionFn = (
newFunctionName: Name
) => string | string[];

export type RenameFunction = RenameFunctionFn & { reverse: RenameFunctionFn };
export type RenameFunction = Reversible<RenameFunctionFn>;

export function renameFunction(mOptions: MigrationOptions): RenameFunction {
const _rename: RenameFunction = (
Expand Down
46 changes: 46 additions & 0 deletions src/operations/generalTypes.ts
Expand Up @@ -39,3 +39,49 @@ export interface CascadeOption {
}

export type DropOptions = IfExistsOption & CascadeOption;

/**
* A function that returns a normal SQL statement or an array of SQL statements.
*
* The array is useful for operations that need to return multiple SQL statements like an additional `COMMENT`.
*/
export type OperationFn = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...args: any[]
) => string | string[];

/**
* A function that returns a normal SQL statement or an array of SQL statements.
*
* The array is useful for operations that need to return multiple SQL statements like an additional `COMMENT`.
*
* The `reverse` property is a function that takes the same arguments and try to infer the reverse SQL statement with that.
*/
export type Operation = OperationFn & {
/**
* Reverse the operation if provided.
*/
reverse?: OperationFn;
};

/**
* A function that returns a normal SQL statement or an array of SQL statements.
*
* The array is useful for operations that need to return multiple SQL statements like an additional `COMMENT`.
*
* The `reverse` property is a function that takes the same arguments and try to infer the reverse SQL statement with that.
*/
export type Reversible<
TFunction extends (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...args: any[]
) => string | string[],
> = TFunction & {
/**
* Reverse the operation.
*
* Needs to be the same function definition, because it takes the same
* arguments and try to infer the reverse SQL statement with that.
*/
reverse: TFunction;
};
4 changes: 2 additions & 2 deletions src/operations/indexes/createIndex.ts
@@ -1,5 +1,5 @@
import type { MigrationOptions } from '../../types';
import type { Name } from '../generalTypes';
import type { Name, Reversible } from '../generalTypes';
import type { DropIndexOptions } from './dropIndex';
import { dropIndex } from './dropIndex';
import type { IndexColumn } from './shared';
Expand Down Expand Up @@ -32,7 +32,7 @@ export type CreateIndexFn = (
options?: CreateIndexOptions & DropIndexOptions
) => string | string[];

export type CreateIndex = CreateIndexFn & { reverse: CreateIndexFn };
export type CreateIndex = Reversible<CreateIndexFn>;

export function createIndex(mOptions: MigrationOptions): CreateIndex {
const _create: CreateIndex = (tableName, rawColumns, options = {}) => {
Expand Down
11 changes: 7 additions & 4 deletions src/operations/materializedViews/createMaterializedView.ts
@@ -1,5 +1,10 @@
import type { MigrationOptions } from '../../types';
import type { DropOptions, IfNotExistsOption, Name } from '../generalTypes';
import type {
DropOptions,
IfNotExistsOption,
Name,
Reversible,
} from '../generalTypes';
import { dropMaterializedView } from './dropMaterializedView';
import type { StorageParameters } from './shared';
import { dataClause, storageParameterStr } from './shared';
Expand All @@ -20,9 +25,7 @@ export type CreateMaterializedViewFn = (
definition: string
) => string | string[];

export type CreateMaterializedView = CreateMaterializedViewFn & {
reverse: CreateMaterializedViewFn;
};
export type CreateMaterializedView = Reversible<CreateMaterializedViewFn>;

export function createMaterializedView(
mOptions: MigrationOptions
Expand Down
6 changes: 2 additions & 4 deletions src/operations/materializedViews/refreshMaterializedView.ts
@@ -1,5 +1,5 @@
import type { MigrationOptions } from '../../types';
import type { Name } from '../generalTypes';
import type { Name, Reversible } from '../generalTypes';
import { dataClause } from './shared';

export interface RefreshMaterializedViewOptions {
Expand All @@ -13,9 +13,7 @@ export type RefreshMaterializedViewFn = (
options?: RefreshMaterializedViewOptions
) => string | string[];

export type RefreshMaterializedView = RefreshMaterializedViewFn & {
reverse: RefreshMaterializedViewFn;
};
export type RefreshMaterializedView = Reversible<RefreshMaterializedViewFn>;

export function refreshMaterializedView(
mOptions: MigrationOptions
Expand Down
6 changes: 2 additions & 4 deletions src/operations/materializedViews/renameMaterializedView.ts
@@ -1,14 +1,12 @@
import type { MigrationOptions } from '../../types';
import type { Name } from '../generalTypes';
import type { Name, Reversible } from '../generalTypes';

export type RenameMaterializedViewFn = (
viewName: Name,
newViewName: Name
) => string | string[];

export type RenameMaterializedView = RenameMaterializedViewFn & {
reverse: RenameMaterializedViewFn;
};
export type RenameMaterializedView = Reversible<RenameMaterializedViewFn>;

export function renameMaterializedView(
mOptions: MigrationOptions
Expand Down
@@ -1,15 +1,14 @@
import type { MigrationOptions } from '../../types';
import type { Name } from '../generalTypes';
import type { Name, Reversible } from '../generalTypes';

export type RenameMaterializedViewColumnFn = (
viewName: Name,
columnName: string,
newColumnName: string
) => string | string[];

export type RenameMaterializedViewColumn = RenameMaterializedViewColumnFn & {
reverse: RenameMaterializedViewColumnFn;
};
export type RenameMaterializedViewColumn =
Reversible<RenameMaterializedViewColumnFn>;

export function renameMaterializedViewColumn(
mOptions: MigrationOptions
Expand Down
6 changes: 2 additions & 4 deletions src/operations/operators/addToOperatorFamily.ts
@@ -1,5 +1,5 @@
import type { MigrationOptions } from '../../types';
import type { Name } from '../generalTypes';
import type { Name, Reversible } from '../generalTypes';
import { removeFromOperatorFamily } from './removeFromOperatorFamily';
import type { OperatorListDefinition } from './shared';
import { operatorMap } from './shared';
Expand All @@ -10,9 +10,7 @@ export type AddToOperatorFamilyFn = (
operatorList: OperatorListDefinition[]
) => string | string[];

export type AddToOperatorFamily = AddToOperatorFamilyFn & {
reverse: AddToOperatorFamilyFn;
};
export type AddToOperatorFamily = Reversible<AddToOperatorFamilyFn>;

export const addToOperatorFamily = (
mOptions: MigrationOptions
Expand Down
4 changes: 2 additions & 2 deletions src/operations/operators/createOperator.ts
@@ -1,5 +1,5 @@
import type { MigrationOptions } from '../../types';
import type { Name } from '../generalTypes';
import type { Name, Reversible } from '../generalTypes';
import type { DropOperatorOptions } from './dropOperator';
import { dropOperator } from './dropOperator';

Expand Down Expand Up @@ -28,7 +28,7 @@ export type CreateOperatorFn = (
options: CreateOperatorOptions & DropOperatorOptions
) => string | string[];

export type CreateOperator = CreateOperatorFn & { reverse: CreateOperatorFn };
export type CreateOperator = Reversible<CreateOperatorFn>;

export function createOperator(mOptions: MigrationOptions): CreateOperator {
const _create: CreateOperator = (operatorName, options) => {
Expand Down
6 changes: 2 additions & 4 deletions src/operations/operators/createOperatorClass.ts
@@ -1,6 +1,6 @@
import type { MigrationOptions } from '../../types';
import { applyType } from '../../utils';
import type { DropOptions, Name, Type } from '../generalTypes';
import type { DropOptions, Name, Reversible, Type } from '../generalTypes';
import { dropOperatorClass } from './dropOperatorClass';
import type { OperatorListDefinition } from './shared';
import { operatorMap } from './shared';
Expand All @@ -19,9 +19,7 @@ export type CreateOperatorClassFn = (
options: CreateOperatorClassOptions & DropOptions
) => string | string[];

export type CreateOperatorClass = CreateOperatorClassFn & {
reverse: CreateOperatorClassFn;
};
export type CreateOperatorClass = Reversible<CreateOperatorClassFn>;

export function createOperatorClass(
mOptions: MigrationOptions
Expand Down
6 changes: 2 additions & 4 deletions src/operations/operators/createOperatorFamily.ts
@@ -1,5 +1,5 @@
import type { MigrationOptions } from '../../types';
import type { DropOptions, Name } from '../generalTypes';
import type { DropOptions, Name, Reversible } from '../generalTypes';
import { dropOperatorFamily } from './dropOperatorFamily';

export type CreateOperatorFamilyFn = (
Expand All @@ -8,9 +8,7 @@ export type CreateOperatorFamilyFn = (
options?: DropOptions
) => string | string[];

export type CreateOperatorFamily = CreateOperatorFamilyFn & {
reverse: CreateOperatorFamilyFn;
};
export type CreateOperatorFamily = Reversible<CreateOperatorFamilyFn>;

export function createOperatorFamily(
mOptions: MigrationOptions
Expand Down
6 changes: 2 additions & 4 deletions src/operations/operators/renameOperatorClass.ts
@@ -1,15 +1,13 @@
import type { MigrationOptions } from '../../types';
import type { Name } from '../generalTypes';
import type { Name, Reversible } from '../generalTypes';

export type RenameOperatorClassFn = (
oldOperatorClassName: Name,
indexMethod: Name,
newOperatorClassName: Name
) => string | string[];

export type RenameOperatorClass = RenameOperatorClassFn & {
reverse: RenameOperatorClassFn;
};
export type RenameOperatorClass = Reversible<RenameOperatorClassFn>;

export function renameOperatorClass(
mOptions: MigrationOptions
Expand Down

0 comments on commit d49217a

Please sign in to comment.