Skip to content

Commit

Permalink
refactor(indexes): reorganize operations indexes (#1075)
Browse files Browse the repository at this point in the history
  • Loading branch information
Shinigami92 committed Apr 9, 2024
1 parent c58dcdb commit 2c37894
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 208 deletions.
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ export type {
} from './operations/generalTypes';
export type {
CreateIndex,
CreateIndexFn,
CreateIndexOptions,
DropIndex,
DropIndexOptions,
} from './operations/indexesTypes';
IndexColumn,
} from './operations/indexes';
export type {
AddToOperatorFamily,
CreateOperator,
Expand Down
154 changes: 0 additions & 154 deletions src/operations/indexes.ts

This file was deleted.

101 changes: 101 additions & 0 deletions src/operations/indexes/createIndex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import type { MigrationOptions } from '../../types';
import type { Name } from '../generalTypes';
import type { DropIndexOptions } from './dropIndex';
import { dropIndex } from './dropIndex';
import type { IndexColumn } from './shared';
import { generateColumnsString, generateIndexName } from './shared';

export interface CreateIndexOptions {
name?: string;

unique?: boolean;

where?: string;

concurrently?: boolean;

ifNotExists?: boolean;

/**
* @deprecated should be parameter of IndexColumn
*/
opclass?: Name;

method?: 'btree' | 'hash' | 'gist' | 'spgist' | 'gin';

include?: string | string[];
}

export type CreateIndexFn = (
tableName: Name,
columns: string | Array<string | IndexColumn>,
options?: CreateIndexOptions & DropIndexOptions
) => string | string[];

export type CreateIndex = CreateIndexFn & { reverse: CreateIndexFn };

export function createIndex(mOptions: MigrationOptions): CreateIndex {
const _create: CreateIndex = (tableName, rawColumns, options = {}) => {
/*
columns - the column, columns, or expression to create the index on
Options
name - explicitly specify the name for the index
unique - is this a unique index
where - where clause
concurrently -
ifNotExists - optionally create index
options.method - [ btree | hash | gist | spgist | gin ]
*/
const columns = Array.isArray(rawColumns)
? rawColumns.slice()
: [rawColumns];

if (options.opclass) {
mOptions.logger.warn(
"Using opclass is deprecated. You should use it as part of column definition e.g. pgm.createIndex('table', [['column', 'opclass', 'ASC']])"
);
const lastIndex = columns.length - 1;
const lastColumn = columns[lastIndex];

if (typeof lastColumn === 'string') {
columns[lastIndex] = { name: lastColumn, opclass: options.opclass };
} else if (lastColumn.opclass) {
throw new Error(
"There is already defined opclass on column, can't override it with global one"
);
} else {
columns[lastIndex] = { ...lastColumn, opclass: options.opclass };
}
}

const indexName = generateIndexName(
typeof tableName === 'object' ? tableName.name : tableName,
columns,
options,
mOptions.schemalize
);
const columnsString = generateColumnsString(columns, mOptions);
const unique = options.unique ? ' UNIQUE' : '';
const concurrently = options.concurrently ? ' CONCURRENTLY' : '';
const ifNotExistsStr = options.ifNotExists ? ' IF NOT EXISTS' : '';
const method = options.method ? ` USING ${options.method}` : '';
const where = options.where ? ` WHERE ${options.where}` : '';
const include = options.include
? ` INCLUDE (${(Array.isArray(options.include)
? options.include
: [options.include]
)
.map(mOptions.literal)
.join(', ')})`
: '';
const indexNameStr = mOptions.literal(indexName);
const tableNameStr = mOptions.literal(tableName);

return `CREATE${unique} INDEX${concurrently}${ifNotExistsStr} ${indexNameStr} ON ${tableNameStr}${method} (${columnsString})${include}${where};`;
};

_create.reverse = dropIndex(mOptions);

return _create;
}
42 changes: 42 additions & 0 deletions src/operations/indexes/dropIndex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { MigrationOptions } from '../../types';
import type { DropOptions, Name } from '../generalTypes';
import type { IndexColumn } from './shared';
import { generateIndexName } from './shared';

export interface DropIndexOptions extends DropOptions {
unique?: boolean;

name?: string;

concurrently?: boolean;
}

export type DropIndex = (
tableName: Name,
columns: string | Array<string | IndexColumn>,
options?: DropIndexOptions
) => string | string[];

export function dropIndex(mOptions: MigrationOptions): DropIndex {
const _drop: DropIndex = (tableName, rawColumns, options = {}) => {
const { concurrently, ifExists, cascade } = options;

const columns = Array.isArray(rawColumns)
? rawColumns.slice()
: [rawColumns];
const concurrentlyStr = concurrently ? ' CONCURRENTLY' : '';
const ifExistsStr = ifExists ? ' IF EXISTS' : '';
const indexName = generateIndexName(
tableName,
columns,
options,
mOptions.schemalize
);
const cascadeStr = cascade ? ' CASCADE' : '';
const indexNameStr = mOptions.literal(indexName);

return `DROP INDEX${concurrentlyStr}${ifExistsStr} ${indexNameStr}${cascadeStr};`;
};

return _drop;
}
3 changes: 3 additions & 0 deletions src/operations/indexes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './createIndex';
export * from './dropIndex';
export * from './shared';
68 changes: 68 additions & 0 deletions src/operations/indexes/shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type { Literal, MigrationOptions } from '../../types';
import type { Name } from '../generalTypes';
import type { CreateIndexOptions } from './createIndex';
import type { DropIndexOptions } from './dropIndex';

export interface IndexColumn {
name: string;

opclass?: Name;

sort?: 'ASC' | 'DESC';
}

export function generateIndexName(
table: Name,
columns: Array<string | IndexColumn>,
options: CreateIndexOptions | DropIndexOptions,
schemalize: Literal
): Name {
if (options.name) {
return typeof table === 'object'
? { schema: table.schema, name: options.name }
: options.name;
}

const cols = columns
.map((col) => schemalize(typeof col === 'string' ? col : col.name))
.join('_');
const uniq = 'unique' in options && options.unique ? '_unique' : '';

return typeof table === 'object'
? {
schema: table.schema,
name: `${table.name}_${cols}${uniq}_index`,
}
: `${table}_${cols}${uniq}_index`;
}

export function generateColumnString(
column: Name,
mOptions: MigrationOptions
): string {
const name = mOptions.schemalize(column);
const isSpecial = /[. ()]/.test(name);

return isSpecial
? name // expression
: mOptions.literal(name); // single column
}

export function generateColumnsString(
columns: Array<string | IndexColumn>,
mOptions: MigrationOptions
): string {
return columns
.map((column) =>
typeof column === 'string'
? generateColumnString(column, mOptions)
: [
generateColumnString(column.name, mOptions),
column.opclass ? mOptions.literal(column.opclass) : undefined,
column.sort,
]
.filter((s) => typeof s === 'string' && s !== '')
.join(' ')
)
.join(', ');
}

0 comments on commit 2c37894

Please sign in to comment.