@yandjin-mikro-orm/postgresql 6.1.4-rc-sti-changes-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/PostgreSqlConnection.d.ts +15 -0
- package/PostgreSqlConnection.js +162 -0
- package/PostgreSqlDriver.d.ts +6 -0
- package/PostgreSqlDriver.js +15 -0
- package/PostgreSqlExceptionConverter.d.ts +8 -0
- package/PostgreSqlExceptionConverter.js +45 -0
- package/PostgreSqlMikroORM.d.ts +19 -0
- package/PostgreSqlMikroORM.js +29 -0
- package/PostgreSqlPlatform.d.ts +96 -0
- package/PostgreSqlPlatform.js +314 -0
- package/PostgreSqlSchemaHelper.d.ts +44 -0
- package/PostgreSqlSchemaHelper.js +490 -0
- package/README.md +383 -0
- package/index.d.ts +8 -0
- package/index.js +27 -0
- package/index.mjs +221 -0
- package/package.json +73 -0
- package/types/FullTextType.d.ts +14 -0
- package/types/FullTextType.js +63 -0
- package/types/index.d.ts +1 -0
- package/types/index.js +17 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PostgreSqlSchemaHelper = void 0;
|
|
4
|
+
const core_1 = require("@yandjin-mikro-orm/core");
|
|
5
|
+
const knex_1 = require("@yandjin-mikro-orm/knex");
|
|
6
|
+
class PostgreSqlSchemaHelper extends knex_1.SchemaHelper {
|
|
7
|
+
static DEFAULT_VALUES = {
|
|
8
|
+
"now()": ["now()", "current_timestamp"],
|
|
9
|
+
"current_timestamp(?)": ["current_timestamp(?)"],
|
|
10
|
+
"('now'::text)::timestamp(?) with time zone": ["current_timestamp(?)"],
|
|
11
|
+
"('now'::text)::timestamp(?) without time zone": ["current_timestamp(?)"],
|
|
12
|
+
"null::character varying": ["null"],
|
|
13
|
+
"null::timestamp with time zone": ["null"],
|
|
14
|
+
"null::timestamp without time zone": ["null"],
|
|
15
|
+
};
|
|
16
|
+
getSchemaBeginning(charset) {
|
|
17
|
+
return `set names '${charset}';\n${this.disableForeignKeysSQL()}\n\n`;
|
|
18
|
+
}
|
|
19
|
+
getListTablesSQL() {
|
|
20
|
+
return (`select table_name, table_schema as schema_name, ` +
|
|
21
|
+
`(select pg_catalog.obj_description(c.oid) from pg_catalog.pg_class c
|
|
22
|
+
where c.oid = (select ('"' || table_schema || '"."' || table_name || '"')::regclass::oid) and c.relname = table_name) as table_comment ` +
|
|
23
|
+
`from information_schema.tables ` +
|
|
24
|
+
`where ${this.getIgnoredNamespacesConditionSQL("table_schema")} ` +
|
|
25
|
+
`and table_name != 'geometry_columns' and table_name != 'spatial_ref_sys' and table_type != 'VIEW' ` +
|
|
26
|
+
`order by table_name`);
|
|
27
|
+
}
|
|
28
|
+
async getNamespaces(connection) {
|
|
29
|
+
const sql = `select schema_name from information_schema.schemata ` +
|
|
30
|
+
`where ${this.getIgnoredNamespacesConditionSQL()} ` +
|
|
31
|
+
`order by schema_name`;
|
|
32
|
+
const res = await connection.execute(sql);
|
|
33
|
+
return res.map((row) => row.schema_name);
|
|
34
|
+
}
|
|
35
|
+
getIgnoredNamespacesConditionSQL(column = "schema_name") {
|
|
36
|
+
/* istanbul ignore next */
|
|
37
|
+
const ignored = [
|
|
38
|
+
"information_schema",
|
|
39
|
+
"tiger",
|
|
40
|
+
"topology",
|
|
41
|
+
...(this.platform.getConfig().get("schemaGenerator").ignoreSchema ?? []),
|
|
42
|
+
]
|
|
43
|
+
.map((s) => this.platform.quoteValue(s))
|
|
44
|
+
.join(", ");
|
|
45
|
+
const ignoredPrefixes = ["pg_", "crdb_", "_timescaledb_"]
|
|
46
|
+
.map((p) => `"${column}" not like '${p}%'`)
|
|
47
|
+
.join(" and ");
|
|
48
|
+
return `${ignoredPrefixes} and "${column}" not in (${ignored})`;
|
|
49
|
+
}
|
|
50
|
+
async loadInformationSchema(schema, connection, tables, schemas) {
|
|
51
|
+
schemas ??=
|
|
52
|
+
tables.length === 0
|
|
53
|
+
? [schema.name]
|
|
54
|
+
: tables.map((t) => t.schema_name ?? schema.name);
|
|
55
|
+
const nativeEnums = await this.getNativeEnumDefinitions(connection, schemas);
|
|
56
|
+
schema.setNativeEnums(nativeEnums);
|
|
57
|
+
if (tables.length === 0) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const columns = await this.getAllColumns(connection, tables, nativeEnums);
|
|
61
|
+
const indexes = await this.getAllIndexes(connection, tables);
|
|
62
|
+
const checks = await this.getAllChecks(connection, tables);
|
|
63
|
+
const fks = await this.getAllForeignKeys(connection, tables);
|
|
64
|
+
for (const t of tables) {
|
|
65
|
+
const key = this.getTableKey(t);
|
|
66
|
+
const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
|
|
67
|
+
const pks = await this.getPrimaryKeys(connection, indexes[key], table.name, table.schema);
|
|
68
|
+
const enums = await this.getEnumDefinitions(connection, checks[key] ?? []);
|
|
69
|
+
table.init(columns[key], indexes[key], checks[key], pks, fks[key], enums);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async getAllIndexes(connection, tables) {
|
|
73
|
+
const sql = this.getIndexesSQL(tables);
|
|
74
|
+
const unquote = (str) => str.replace(/['"`]/g, "");
|
|
75
|
+
const allIndexes = await connection.execute(sql);
|
|
76
|
+
const ret = {};
|
|
77
|
+
for (const index of allIndexes) {
|
|
78
|
+
const key = this.getTableKey(index);
|
|
79
|
+
const indexDef = {
|
|
80
|
+
columnNames: index.index_def.map((name) => unquote(name)),
|
|
81
|
+
composite: index.index_def.length > 1,
|
|
82
|
+
// JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
|
|
83
|
+
constraint: index.contype === "u",
|
|
84
|
+
keyName: index.constraint_name,
|
|
85
|
+
unique: index.unique,
|
|
86
|
+
primary: index.primary,
|
|
87
|
+
};
|
|
88
|
+
if (index.index_def.some((col) => col.match(/[(): ,"'`]/)) ||
|
|
89
|
+
index.expression?.match(/ where /i)) {
|
|
90
|
+
indexDef.expression = index.expression;
|
|
91
|
+
}
|
|
92
|
+
ret[key] ??= [];
|
|
93
|
+
ret[key].push(indexDef);
|
|
94
|
+
}
|
|
95
|
+
return ret;
|
|
96
|
+
}
|
|
97
|
+
async getAllColumns(connection, tables, nativeEnums) {
|
|
98
|
+
const sql = `select table_schema as schema_name, table_name, column_name,
|
|
99
|
+
column_default,
|
|
100
|
+
is_nullable,
|
|
101
|
+
udt_name,
|
|
102
|
+
coalesce(datetime_precision, character_maximum_length) length,
|
|
103
|
+
numeric_precision,
|
|
104
|
+
numeric_scale,
|
|
105
|
+
data_type,
|
|
106
|
+
is_identity,
|
|
107
|
+
identity_generation,
|
|
108
|
+
generation_expression,
|
|
109
|
+
(select pg_catalog.col_description(c.oid, cols.ordinal_position::int)
|
|
110
|
+
from pg_catalog.pg_class c
|
|
111
|
+
where c.oid = (select ('"' || cols.table_schema || '"."' || cols.table_name || '"')::regclass::oid) and c.relname = cols.table_name) as column_comment
|
|
112
|
+
from information_schema.columns cols
|
|
113
|
+
where (${tables.map((t) => `(table_schema = '${t.schema_name}' and table_name = '${t.table_name}')`).join(" or ")})
|
|
114
|
+
order by ordinal_position`;
|
|
115
|
+
const allColumns = await connection.execute(sql);
|
|
116
|
+
const str = (val) => val != null ? "" + val : val;
|
|
117
|
+
const ret = {};
|
|
118
|
+
for (const col of allColumns) {
|
|
119
|
+
const mappedType = connection.getPlatform().getMappedType(col.data_type);
|
|
120
|
+
const increments = (col.column_default?.includes("nextval") ||
|
|
121
|
+
col.is_identity === "YES") &&
|
|
122
|
+
connection.getPlatform().isNumericColumn(mappedType);
|
|
123
|
+
const key = this.getTableKey(col);
|
|
124
|
+
ret[key] ??= [];
|
|
125
|
+
let type = col.data_type.toLowerCase() === "array"
|
|
126
|
+
? col.udt_name.replace(/^_(.*)$/, "$1[]")
|
|
127
|
+
: col.udt_name;
|
|
128
|
+
if (col.length != null && !type.endsWith(`(${col.length})`)) {
|
|
129
|
+
type += `(${col.length})`;
|
|
130
|
+
}
|
|
131
|
+
if (type === "numeric" &&
|
|
132
|
+
col.numeric_precision != null &&
|
|
133
|
+
col.numeric_scale != null) {
|
|
134
|
+
type += `(${col.numeric_precision},${col.numeric_scale})`;
|
|
135
|
+
}
|
|
136
|
+
const column = {
|
|
137
|
+
name: col.column_name,
|
|
138
|
+
type,
|
|
139
|
+
mappedType,
|
|
140
|
+
length: col.length,
|
|
141
|
+
precision: col.numeric_precision,
|
|
142
|
+
scale: col.numeric_scale,
|
|
143
|
+
nullable: col.is_nullable === "YES",
|
|
144
|
+
default: str(this.normalizeDefaultValue(col.column_default, col.length)),
|
|
145
|
+
unsigned: increments,
|
|
146
|
+
autoincrement: increments,
|
|
147
|
+
generated: col.is_identity === "YES"
|
|
148
|
+
? col.identity_generation === "BY DEFAULT"
|
|
149
|
+
? "by default as identity"
|
|
150
|
+
: "identity"
|
|
151
|
+
: col.generation_expression
|
|
152
|
+
? col.generation_expression + " stored"
|
|
153
|
+
: undefined,
|
|
154
|
+
comment: col.column_comment,
|
|
155
|
+
};
|
|
156
|
+
if (nativeEnums?.[column.type]) {
|
|
157
|
+
column.mappedType = core_1.Type.getType(core_1.EnumType);
|
|
158
|
+
column.nativeEnumName = column.type;
|
|
159
|
+
column.enumItems = nativeEnums[column.type];
|
|
160
|
+
}
|
|
161
|
+
ret[key].push(column);
|
|
162
|
+
}
|
|
163
|
+
return ret;
|
|
164
|
+
}
|
|
165
|
+
async getAllChecks(connection, tables) {
|
|
166
|
+
const sql = this.getChecksSQL(tables);
|
|
167
|
+
const allChecks = await connection.execute(sql);
|
|
168
|
+
const ret = {};
|
|
169
|
+
for (const check of allChecks) {
|
|
170
|
+
const key = this.getTableKey(check);
|
|
171
|
+
ret[key] ??= [];
|
|
172
|
+
const m = check.expression.match(/^check \(\((.*)\)\)$/i);
|
|
173
|
+
const def = m?.[1].replace(/\((.*?)\)::\w+/g, "$1");
|
|
174
|
+
ret[key].push({
|
|
175
|
+
name: check.name,
|
|
176
|
+
columnName: check.column_name,
|
|
177
|
+
definition: check.expression,
|
|
178
|
+
expression: def,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return ret;
|
|
182
|
+
}
|
|
183
|
+
async getAllForeignKeys(connection, tables) {
|
|
184
|
+
const sql = `select tco.table_schema as schema_name, kcu.table_name as table_name, rel_kcu.table_name as referenced_table_name,
|
|
185
|
+
rel_kcu.constraint_schema as referenced_schema_name,
|
|
186
|
+
kcu.column_name as column_name,
|
|
187
|
+
rel_kcu.column_name as referenced_column_name, kcu.constraint_name, rco.update_rule, rco.delete_rule
|
|
188
|
+
from information_schema.table_constraints tco
|
|
189
|
+
join information_schema.key_column_usage kcu
|
|
190
|
+
on tco.constraint_schema = kcu.constraint_schema
|
|
191
|
+
and tco.constraint_name = kcu.constraint_name
|
|
192
|
+
join information_schema.referential_constraints rco
|
|
193
|
+
on tco.constraint_schema = rco.constraint_schema
|
|
194
|
+
and tco.constraint_name = rco.constraint_name
|
|
195
|
+
join information_schema.key_column_usage rel_kcu
|
|
196
|
+
on rco.unique_constraint_schema = rel_kcu.constraint_schema
|
|
197
|
+
and rco.unique_constraint_name = rel_kcu.constraint_name
|
|
198
|
+
and kcu.ordinal_position = rel_kcu.ordinal_position
|
|
199
|
+
where (${tables.map((t) => `tco.table_name = '${t.table_name}' and tco.table_schema = '${t.schema_name}' and tco.constraint_schema = '${t.schema_name}'`).join(" or ")})
|
|
200
|
+
and tco.constraint_type = 'FOREIGN KEY'
|
|
201
|
+
order by kcu.table_schema, kcu.table_name, kcu.ordinal_position, kcu.constraint_name`;
|
|
202
|
+
const allFks = await connection.execute(sql);
|
|
203
|
+
const ret = {};
|
|
204
|
+
for (const fk of allFks) {
|
|
205
|
+
const key = this.getTableKey(fk);
|
|
206
|
+
ret[key] ??= [];
|
|
207
|
+
ret[key].push(fk);
|
|
208
|
+
}
|
|
209
|
+
Object.keys(ret).forEach((key) => {
|
|
210
|
+
const [schemaName, tableName] = key.split(".");
|
|
211
|
+
ret[key] = this.mapForeignKeys(ret[key], tableName, schemaName);
|
|
212
|
+
});
|
|
213
|
+
return ret;
|
|
214
|
+
}
|
|
215
|
+
async getNativeEnumDefinitions(connection, schemas) {
|
|
216
|
+
const res = await connection.execute("select t.typname as enum_name, array_agg(e.enumlabel order by e.enumsortorder) as enum_value " +
|
|
217
|
+
"from pg_type t " +
|
|
218
|
+
"join pg_enum e on t.oid = e.enumtypid " +
|
|
219
|
+
"join pg_catalog.pg_namespace n on n.oid = t.typnamespace " +
|
|
220
|
+
"where n.nspname in (?) " +
|
|
221
|
+
"group by t.typname", core_1.Utils.unique(schemas));
|
|
222
|
+
return res.reduce((o, row) => {
|
|
223
|
+
o[row.enum_name] = this.platform.unmarshallArray(row.enum_value);
|
|
224
|
+
return o;
|
|
225
|
+
}, {});
|
|
226
|
+
}
|
|
227
|
+
getDropNativeEnumSQL(name, schema) {
|
|
228
|
+
if (schema && schema !== this.platform.getDefaultSchemaName()) {
|
|
229
|
+
name = schema + "." + name;
|
|
230
|
+
}
|
|
231
|
+
return `drop type ${this.platform.quoteIdentifier(name)}`;
|
|
232
|
+
}
|
|
233
|
+
getAlterNativeEnumSQL(name, schema, value) {
|
|
234
|
+
if (schema && schema !== this.platform.getDefaultSchemaName()) {
|
|
235
|
+
name = schema + "." + name;
|
|
236
|
+
}
|
|
237
|
+
return `alter type ${this.platform.quoteIdentifier(name)} add value if not exists ${this.platform.quoteValue(value)}`;
|
|
238
|
+
}
|
|
239
|
+
async getEnumDefinitions(connection, checks, tableName, schemaName) {
|
|
240
|
+
const found = [];
|
|
241
|
+
const enums = checks.reduce((o, item, index) => {
|
|
242
|
+
// check constraints are defined as one of:
|
|
243
|
+
// `CHECK ((type = ANY (ARRAY['local'::text, 'global'::text])))`
|
|
244
|
+
// `CHECK (("columnName" = ANY (ARRAY['local'::text, 'global'::text])))`
|
|
245
|
+
// `CHECK (((enum_test)::text = ANY ((ARRAY['a'::character varying, 'b'::character varying, 'c'::character varying])::text[])))`
|
|
246
|
+
// `CHECK ((("enumTest")::text = ANY ((ARRAY['a'::character varying, 'b'::character varying, 'c'::character varying])::text[])))`
|
|
247
|
+
// `CHECK ((type = 'a'::text))`
|
|
248
|
+
const m1 = item.definition?.match(/check \(\(\("?(\w+)"?\)::/i) ||
|
|
249
|
+
item.definition?.match(/check \(\("?(\w+)"? = /i);
|
|
250
|
+
const m2 = item.definition?.match(/\(array\[(.*)]\)/i) ||
|
|
251
|
+
item.definition?.match(/ = (.*)\)/i);
|
|
252
|
+
if (item.columnName && m1 && m2) {
|
|
253
|
+
const m3 = m2[1].match(/('[^']+'::text)/g);
|
|
254
|
+
let items;
|
|
255
|
+
/* istanbul ignore else */
|
|
256
|
+
if (m3) {
|
|
257
|
+
items = m3.map((item) => item.trim().match(/^\(?'(.*)'/)?.[1]);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
items = m2[1]
|
|
261
|
+
.split(",")
|
|
262
|
+
.map((item) => item.trim().match(/^\(?'(.*)'/)?.[1]);
|
|
263
|
+
}
|
|
264
|
+
items = items.filter(Boolean);
|
|
265
|
+
if (items.length > 0) {
|
|
266
|
+
o[item.columnName] = items;
|
|
267
|
+
found.push(index);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return o;
|
|
271
|
+
}, {});
|
|
272
|
+
found.reverse().forEach((index) => checks.splice(index, 1));
|
|
273
|
+
return enums;
|
|
274
|
+
}
|
|
275
|
+
createTableColumn(table, column, fromTable, changedProperties, alter) {
|
|
276
|
+
const pk = fromTable.getPrimaryKey();
|
|
277
|
+
const primaryKey = column.primary &&
|
|
278
|
+
!changedProperties &&
|
|
279
|
+
!this.hasNonDefaultPrimaryKeyName(fromTable);
|
|
280
|
+
if (column.autoincrement &&
|
|
281
|
+
!column.generated &&
|
|
282
|
+
!pk?.composite &&
|
|
283
|
+
!changedProperties) {
|
|
284
|
+
if (column.mappedType instanceof core_1.BigIntType) {
|
|
285
|
+
return table.bigIncrements(column.name, { primaryKey });
|
|
286
|
+
}
|
|
287
|
+
return table.increments(column.name, { primaryKey });
|
|
288
|
+
}
|
|
289
|
+
if (column.nativeEnumName && column.enumItems) {
|
|
290
|
+
const existingType = alter
|
|
291
|
+
? column.nativeEnumName in fromTable.nativeEnums
|
|
292
|
+
: false;
|
|
293
|
+
if (!existingType) {
|
|
294
|
+
fromTable.nativeEnums[column.nativeEnumName] = [];
|
|
295
|
+
}
|
|
296
|
+
return table.enum(column.name, column.enumItems, {
|
|
297
|
+
useNative: true,
|
|
298
|
+
enumName: column.nativeEnumName,
|
|
299
|
+
schemaName: fromTable.schema &&
|
|
300
|
+
fromTable.schema !== this.platform.getDefaultSchemaName()
|
|
301
|
+
? fromTable.schema
|
|
302
|
+
: undefined,
|
|
303
|
+
existingType,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
if (column.mappedType instanceof core_1.EnumType &&
|
|
307
|
+
column.enumItems?.every((item) => core_1.Utils.isString(item))) {
|
|
308
|
+
return table.enum(column.name, column.enumItems);
|
|
309
|
+
}
|
|
310
|
+
// serial is just a pseudo type, it cannot be used for altering
|
|
311
|
+
/* istanbul ignore next */
|
|
312
|
+
if (changedProperties && column.type.includes("serial")) {
|
|
313
|
+
column.type = column.type.replace("serial", "int");
|
|
314
|
+
}
|
|
315
|
+
let columnType = column.type;
|
|
316
|
+
if (column.generated === "by default as identity") {
|
|
317
|
+
columnType += ` generated ${column.generated}`;
|
|
318
|
+
}
|
|
319
|
+
else if (column.generated) {
|
|
320
|
+
columnType += ` generated always as ${column.generated}`;
|
|
321
|
+
}
|
|
322
|
+
return table.specificType(column.name, columnType);
|
|
323
|
+
}
|
|
324
|
+
configureColumn(column, col, knex, changedProperties) {
|
|
325
|
+
const guard = (key) => !changedProperties || changedProperties.has(key);
|
|
326
|
+
core_1.Utils.runIfNotEmpty(() => col.nullable(), column.nullable && guard("nullable"));
|
|
327
|
+
core_1.Utils.runIfNotEmpty(() => col.notNullable(), !column.nullable && guard("nullable"));
|
|
328
|
+
core_1.Utils.runIfNotEmpty(() => col.unsigned(), column.unsigned && guard("unsigned"));
|
|
329
|
+
core_1.Utils.runIfNotEmpty(() => col.comment(column.comment), column.comment && !changedProperties);
|
|
330
|
+
this.configureColumnDefault(column, col, knex, changedProperties);
|
|
331
|
+
return col;
|
|
332
|
+
}
|
|
333
|
+
getPreAlterTable(tableDiff, safe) {
|
|
334
|
+
const ret = [];
|
|
335
|
+
const parts = tableDiff.name.split(".");
|
|
336
|
+
const tableName = parts.pop();
|
|
337
|
+
const schemaName = parts.pop();
|
|
338
|
+
/* istanbul ignore next */
|
|
339
|
+
const name = (schemaName && schemaName !== this.platform.getDefaultSchemaName()
|
|
340
|
+
? schemaName + "."
|
|
341
|
+
: "") + tableName;
|
|
342
|
+
const quotedName = this.platform.quoteIdentifier(name);
|
|
343
|
+
// detect that the column was an enum before and remove the check constraint in such case here
|
|
344
|
+
const changedEnums = Object.values(tableDiff.changedColumns).filter((col) => col.fromColumn.mappedType instanceof core_1.EnumType);
|
|
345
|
+
for (const col of changedEnums) {
|
|
346
|
+
if (!col.fromColumn.nativeEnumName &&
|
|
347
|
+
col.column.nativeEnumName &&
|
|
348
|
+
col.fromColumn.default) {
|
|
349
|
+
ret.push(`alter table ${quotedName} alter column "${col.column.name}" drop default`);
|
|
350
|
+
}
|
|
351
|
+
if (!col.fromColumn.nativeEnumName) {
|
|
352
|
+
const constraintName = `${tableName}_${col.column.name}_check`;
|
|
353
|
+
ret.push(`alter table ${quotedName} drop constraint if exists "${constraintName}"`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
// changing uuid column type requires to cast it to text first
|
|
357
|
+
const uuids = Object.values(tableDiff.changedColumns).filter((col) => col.changedProperties.has("type") && col.fromColumn.type === "uuid");
|
|
358
|
+
for (const col of uuids) {
|
|
359
|
+
ret.push(`alter table ${quotedName} alter column "${col.column.name}" type text using ("${col.column.name}"::text)`);
|
|
360
|
+
}
|
|
361
|
+
return ret.join(";\n");
|
|
362
|
+
}
|
|
363
|
+
getPostAlterTable(tableDiff, safe) {
|
|
364
|
+
const ret = [];
|
|
365
|
+
const parts = tableDiff.name.split(".");
|
|
366
|
+
const tableName = parts.pop();
|
|
367
|
+
const schemaName = parts.pop();
|
|
368
|
+
/* istanbul ignore next */
|
|
369
|
+
const name = (schemaName && schemaName !== this.platform.getDefaultSchemaName()
|
|
370
|
+
? schemaName + "."
|
|
371
|
+
: "") + tableName;
|
|
372
|
+
const quotedName = this.platform.quoteIdentifier(name);
|
|
373
|
+
// detect that the column was an enum before and remove the check constraint in such case here
|
|
374
|
+
const changedEnums = Object.values(tableDiff.changedColumns).filter((col) => col.fromColumn.mappedType instanceof core_1.EnumType);
|
|
375
|
+
for (const col of changedEnums) {
|
|
376
|
+
if (!col.fromColumn.nativeEnumName &&
|
|
377
|
+
col.column.nativeEnumName &&
|
|
378
|
+
col.column.default) {
|
|
379
|
+
ret.push(`alter table ${quotedName} alter column "${col.column.name}" set default ${col.column.default}`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return ret.join(";\n");
|
|
383
|
+
}
|
|
384
|
+
getAlterColumnAutoincrement(tableName, column, schemaName) {
|
|
385
|
+
const ret = [];
|
|
386
|
+
const quoted = (val) => this.platform.quoteIdentifier(val);
|
|
387
|
+
/* istanbul ignore next */
|
|
388
|
+
const name = (schemaName && schemaName !== this.platform.getDefaultSchemaName()
|
|
389
|
+
? schemaName + "."
|
|
390
|
+
: "") + tableName;
|
|
391
|
+
/* istanbul ignore else */
|
|
392
|
+
if (column.autoincrement) {
|
|
393
|
+
const seqName = this.platform.getIndexName(tableName, [column.name], "sequence");
|
|
394
|
+
ret.push(`create sequence if not exists ${quoted(seqName)}`);
|
|
395
|
+
ret.push(`select setval('${seqName}', (select max(${quoted(column.name)}) from ${quoted(name)}))`);
|
|
396
|
+
ret.push(`alter table ${quoted(name)} alter column ${quoted(column.name)} set default nextval('${seqName}')`);
|
|
397
|
+
}
|
|
398
|
+
else if (column.default == null) {
|
|
399
|
+
ret.push(`alter table ${quoted(name)} alter column ${quoted(column.name)} drop default`);
|
|
400
|
+
}
|
|
401
|
+
return ret.join(";\n");
|
|
402
|
+
}
|
|
403
|
+
getChangeColumnCommentSQL(tableName, to, schemaName) {
|
|
404
|
+
const name = this.platform.quoteIdentifier((schemaName && schemaName !== this.platform.getDefaultSchemaName()
|
|
405
|
+
? schemaName + "."
|
|
406
|
+
: "") + tableName);
|
|
407
|
+
const value = to.comment ? this.platform.quoteValue(to.comment) : "null";
|
|
408
|
+
return `comment on column ${name}."${to.name}" is ${value}`;
|
|
409
|
+
}
|
|
410
|
+
normalizeDefaultValue(defaultValue, length) {
|
|
411
|
+
if (!defaultValue || typeof defaultValue !== "string") {
|
|
412
|
+
return super.normalizeDefaultValue(defaultValue, length, PostgreSqlSchemaHelper.DEFAULT_VALUES);
|
|
413
|
+
}
|
|
414
|
+
const match = defaultValue.match(/^'(.*)'::(.*)$/);
|
|
415
|
+
if (match) {
|
|
416
|
+
if (match[2] === "integer") {
|
|
417
|
+
return +match[1];
|
|
418
|
+
}
|
|
419
|
+
return `'${match[1]}'`;
|
|
420
|
+
}
|
|
421
|
+
return super.normalizeDefaultValue(defaultValue, length, PostgreSqlSchemaHelper.DEFAULT_VALUES);
|
|
422
|
+
}
|
|
423
|
+
getDatabaseExistsSQL(name) {
|
|
424
|
+
return `select 1 from pg_database where datname = '${name}'`;
|
|
425
|
+
}
|
|
426
|
+
getDatabaseNotExistsError(dbName) {
|
|
427
|
+
return `database "${dbName}" does not exist`;
|
|
428
|
+
}
|
|
429
|
+
getManagementDbName() {
|
|
430
|
+
return (this.platform.getConfig().get("schemaGenerator", {})
|
|
431
|
+
.managementDbName ?? "postgres");
|
|
432
|
+
}
|
|
433
|
+
disableForeignKeysSQL() {
|
|
434
|
+
return `set session_replication_role = 'replica';`;
|
|
435
|
+
}
|
|
436
|
+
enableForeignKeysSQL() {
|
|
437
|
+
return `set session_replication_role = 'origin';`;
|
|
438
|
+
}
|
|
439
|
+
getRenameIndexSQL(tableName, index, oldIndexName) {
|
|
440
|
+
oldIndexName = this.platform.quoteIdentifier(oldIndexName);
|
|
441
|
+
const keyName = this.platform.quoteIdentifier(index.keyName);
|
|
442
|
+
return `alter index ${oldIndexName} rename to ${keyName}`;
|
|
443
|
+
}
|
|
444
|
+
getIndexesSQL(tables) {
|
|
445
|
+
return `select indrelid::regclass as table_name, ns.nspname as schema_name, relname as constraint_name, idx.indisunique as unique, idx.indisprimary as primary, contype,
|
|
446
|
+
array(
|
|
447
|
+
select pg_get_indexdef(idx.indexrelid, k + 1, true)
|
|
448
|
+
from generate_subscripts(idx.indkey, 1) as k
|
|
449
|
+
order by k
|
|
450
|
+
) as index_def,
|
|
451
|
+
pg_get_indexdef(idx.indexrelid) as expression
|
|
452
|
+
from pg_index idx
|
|
453
|
+
join pg_class as i on i.oid = idx.indexrelid
|
|
454
|
+
join pg_namespace as ns on i.relnamespace = ns.oid
|
|
455
|
+
left join pg_constraint as c on c.conname = i.relname
|
|
456
|
+
where indrelid in (${tables.map((t) => `'"${t.schema_name}"."${t.table_name}"'::regclass`).join(", ")})
|
|
457
|
+
order by relname`;
|
|
458
|
+
}
|
|
459
|
+
getChecksSQL(tables) {
|
|
460
|
+
return `select ccu.table_name as table_name, ccu.table_schema as schema_name, pgc.conname as name, conrelid::regclass as table_from, ccu.column_name as column_name, pg_get_constraintdef(pgc.oid) as expression
|
|
461
|
+
from pg_constraint pgc
|
|
462
|
+
join pg_namespace nsp on nsp.oid = pgc.connamespace
|
|
463
|
+
join pg_class cls on pgc.conrelid = cls.oid
|
|
464
|
+
join information_schema.constraint_column_usage ccu on pgc.conname = ccu.constraint_name and nsp.nspname = ccu.constraint_schema
|
|
465
|
+
where contype = 'c' and (${tables.map((t) => `ccu.table_name = '${t.table_name}' and ccu.table_schema = '${t.schema_name}'`).join(" or ")})
|
|
466
|
+
order by pgc.conname`;
|
|
467
|
+
}
|
|
468
|
+
/* istanbul ignore next */
|
|
469
|
+
async getChecks(connection, tableName, schemaName, columns) {
|
|
470
|
+
const res = await this.getAllChecks(connection, [
|
|
471
|
+
{ table_name: tableName, schema_name: schemaName },
|
|
472
|
+
]);
|
|
473
|
+
return res[tableName];
|
|
474
|
+
}
|
|
475
|
+
/* istanbul ignore next */
|
|
476
|
+
async getColumns(connection, tableName, schemaName) {
|
|
477
|
+
const res = await this.getAllColumns(connection, [
|
|
478
|
+
{ table_name: tableName, schema_name: schemaName },
|
|
479
|
+
]);
|
|
480
|
+
return res[tableName];
|
|
481
|
+
}
|
|
482
|
+
/* istanbul ignore next */
|
|
483
|
+
async getIndexes(connection, tableName, schemaName) {
|
|
484
|
+
const res = await this.getAllIndexes(connection, [
|
|
485
|
+
{ table_name: tableName, schema_name: schemaName },
|
|
486
|
+
]);
|
|
487
|
+
return res[tableName];
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
exports.PostgreSqlSchemaHelper = PostgreSqlSchemaHelper;
|