-
Notifications
You must be signed in to change notification settings - Fork 168
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(indexes): reorganize operations indexes (#1075)
- Loading branch information
1 parent
c58dcdb
commit 2c37894
Showing
8 changed files
with
218 additions
and
208 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './createIndex'; | ||
export * from './dropIndex'; | ||
export * from './shared'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(', '); | ||
} |
Oops, something went wrong.