-
Notifications
You must be signed in to change notification settings - Fork 168
/
indexes.ts
154 lines (135 loc) · 4.72 KB
/
indexes.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import type { Literal, MigrationOptions } from '../types';
import type { Name } from './generalTypes';
import type {
CreateIndex,
CreateIndexOptions,
DropIndex,
DropIndexOptions,
IndexColumn,
} from './indexesTypes';
export type { CreateIndex, DropIndex };
function generateIndexName(
table: Name,
columns: Array<string | IndexColumn>,
options: CreateIndexOptions | DropIndexOptions,
schemalize: Literal
) {
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`;
}
function generateColumnString(column: Name, mOptions: MigrationOptions) {
const name = mOptions.schemalize(column);
const isSpecial = /[. ()]/.test(name);
return isSpecial
? name // expression
: mOptions.literal(name); // single column
}
function generateColumnsString(
columns: Array<string | IndexColumn>,
mOptions: MigrationOptions
) {
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(', ');
}
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;
}
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;
}