@mikro-orm/oracledb 7.0.8 → 7.0.9-dev.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.
@@ -1,111 +1,111 @@
1
- import { DateTimeType, EnumType, SchemaHelper, StringType, TextType, Utils } from '@mikro-orm/sql';
1
+ import { DateTimeType, EnumType, SchemaHelper, StringType, TextType, Utils, } from '@mikro-orm/sql';
2
2
  /** Schema introspection helper for Oracle Database. */
3
3
  export class OracleSchemaHelper extends SchemaHelper {
4
- static DEFAULT_VALUES = {
5
- true: ['1'],
6
- false: ['0'],
7
- systimestamp: ['current_timestamp'],
8
- sysdate: ['current_timestamp'],
9
- };
10
- getDatabaseExistsSQL(name) {
11
- return `select 1 from all_users where username = ${this.platform.quoteValue(name)}`;
12
- }
13
- async getAllTables(connection, schemas, ctx) {
14
- if (!schemas || schemas.length === 0) {
15
- return connection.execute(this.getListTablesSQL(), [], 'all', ctx);
16
- }
17
- const conditions = schemas.map(s => `at.owner = ${this.platform.quoteValue(s)}`).join(' or ');
18
- const sql = `select at.table_name, at.owner as schema_name, atc.comments as table_comment
4
+ static DEFAULT_VALUES = {
5
+ true: ['1'],
6
+ false: ['0'],
7
+ systimestamp: ['current_timestamp'],
8
+ sysdate: ['current_timestamp'],
9
+ };
10
+ getDatabaseExistsSQL(name) {
11
+ return `select 1 from all_users where username = ${this.platform.quoteValue(name)}`;
12
+ }
13
+ async getAllTables(connection, schemas, ctx) {
14
+ if (!schemas || schemas.length === 0) {
15
+ return connection.execute(this.getListTablesSQL(), [], 'all', ctx);
16
+ }
17
+ const conditions = schemas.map(s => `at.owner = ${this.platform.quoteValue(s)}`).join(' or ');
18
+ const sql = `select at.table_name, at.owner as schema_name, atc.comments as table_comment
19
19
  from all_tables at
20
20
  left join all_tab_comments atc on at.owner = atc.owner and at.table_name = atc.table_name
21
21
  where (${conditions})
22
22
  order by schema_name, at.table_name`;
23
- return connection.execute(sql, [], 'all', ctx);
24
- }
25
- getListTablesSQL(schemaName) {
26
- /* v8 ignore next: nullish coalescing chain */
27
- const schema = schemaName ?? this.platform.getDefaultSchemaName() ?? '';
28
- /* v8 ignore next 7: Oracle always has a default schema from dbName */
29
- if (!schema) {
30
- return `select at.table_name, at.owner as schema_name, atc.comments as table_comment
23
+ return connection.execute(sql, [], 'all', ctx);
24
+ }
25
+ getListTablesSQL(schemaName) {
26
+ /* v8 ignore next: nullish coalescing chain */
27
+ const schema = schemaName ?? this.platform.getDefaultSchemaName() ?? '';
28
+ /* v8 ignore next 7: Oracle always has a default schema from dbName */
29
+ if (!schema) {
30
+ return `select at.table_name, at.owner as schema_name, atc.comments as table_comment
31
31
  from all_tables at
32
32
  left join all_tab_comments atc on at.owner = atc.owner and at.table_name = atc.table_name
33
33
  where ${this.getIgnoredNamespacesConditionSQL('at.owner')}
34
34
  order by schema_name, at.table_name`;
35
- }
36
- return `select at.table_name, at.owner as schema_name, atc.comments as table_comment
35
+ }
36
+ return `select at.table_name, at.owner as schema_name, atc.comments as table_comment
37
37
  from all_tables at
38
38
  left join all_tab_comments atc on at.owner = atc.owner and at.table_name = atc.table_name
39
39
  where at.owner = ${this.platform.quoteValue(schema)}
40
40
  order by schema_name, at.table_name`;
41
- }
42
- getListViewsSQL() {
43
- /* v8 ignore next: schema fallback */
44
- const schema = this.platform.getDefaultSchemaName() ?? '';
45
- return `select view_name, owner as schema_name, text as view_definition
41
+ }
42
+ getListViewsSQL() {
43
+ /* v8 ignore next: schema fallback */
44
+ const schema = this.platform.getDefaultSchemaName() ?? '';
45
+ return `select view_name, owner as schema_name, text as view_definition
46
46
  from all_views
47
47
  where owner = ${this.platform.quoteValue(schema)}
48
48
  order by view_name`;
49
- }
50
- async loadViews(schema, connection, schemaName, ctx) {
51
- const views = await connection.execute(this.getListViewsSQL(), [], 'all', ctx);
52
- for (const view of views) {
53
- const definition = view.view_definition?.trim();
54
- /* v8 ignore next 4: empty view definition edge case */
55
- if (definition) {
56
- const schemaName = view.schema_name === this.platform.getDefaultSchemaName() ? undefined : view.schema_name;
57
- schema.addView(view.view_name, schemaName, definition);
58
- }
59
- }
60
- }
61
- async getNamespaces(connection, ctx) {
62
- const sql = `select username as schema_name from all_users where ${this.getIgnoredNamespacesConditionSQL()} order by username`;
63
- const res = await connection.execute(sql, [], 'all', ctx);
64
- return res.map(row => row.schema_name);
65
- }
66
- getIgnoredNamespacesConditionSQL(column = 'username') {
67
- const ignored = [
68
- 'PDBADMIN',
69
- 'ORDS_METADATA',
70
- 'ORDS_PUBLIC_USER',
71
- /* v8 ignore next */
72
- ...(this.platform.getConfig().get('schemaGenerator').ignoreSchema ?? []),
73
- ]
74
- .map(s => this.platform.quoteValue(s))
75
- .join(', ');
76
- return `${column} not in (${ignored}) and oracle_maintained = 'N'`;
77
- }
78
- getDefaultEmptyString() {
79
- return 'null';
80
- }
81
- normalizeDefaultValue(defaultValue, length, defaultValues = {}, stripQuotes = false) {
82
- if (defaultValue == null) {
83
- return defaultValue;
84
- }
85
- // Trim whitespace that Oracle sometimes adds
86
- defaultValue = defaultValue.trim();
87
- let match = /^\((.*)\)$/.exec(defaultValue);
88
- if (match) {
89
- defaultValue = match[1];
90
- }
91
- match = /^\((.*)\)$/.exec(defaultValue);
92
- if (match) {
93
- defaultValue = match[1];
94
- }
95
- match = /^'(.*)'$/.exec(defaultValue);
96
- if (stripQuotes && match) {
97
- defaultValue = match[1];
98
- }
99
- // Normalize current_timestamp variants (Oracle uses CURRENT_TIMESTAMP, SYSTIMESTAMP, etc.)
100
- const lowerDefault = defaultValue.toLowerCase();
101
- if (lowerDefault === 'current_timestamp' || lowerDefault.startsWith('current_timestamp(')) {
102
- // Keep the precision if present
103
- return defaultValue.toLowerCase();
104
- }
105
- return super.normalizeDefaultValue(defaultValue, length, OracleSchemaHelper.DEFAULT_VALUES);
106
- }
107
- async getAllColumns(connection, tablesBySchemas, ctx) {
108
- const sql = `select
49
+ }
50
+ async loadViews(schema, connection, schemaName, ctx) {
51
+ const views = await connection.execute(this.getListViewsSQL(), [], 'all', ctx);
52
+ for (const view of views) {
53
+ const definition = view.view_definition?.trim();
54
+ /* v8 ignore next 4: empty view definition edge case */
55
+ if (definition) {
56
+ const schemaName = view.schema_name === this.platform.getDefaultSchemaName() ? undefined : view.schema_name;
57
+ schema.addView(view.view_name, schemaName, definition);
58
+ }
59
+ }
60
+ }
61
+ async getNamespaces(connection, ctx) {
62
+ const sql = `select username as schema_name from all_users where ${this.getIgnoredNamespacesConditionSQL()} order by username`;
63
+ const res = await connection.execute(sql, [], 'all', ctx);
64
+ return res.map(row => row.schema_name);
65
+ }
66
+ getIgnoredNamespacesConditionSQL(column = 'username') {
67
+ const ignored = [
68
+ 'PDBADMIN',
69
+ 'ORDS_METADATA',
70
+ 'ORDS_PUBLIC_USER',
71
+ /* v8 ignore next */
72
+ ...(this.platform.getConfig().get('schemaGenerator').ignoreSchema ?? []),
73
+ ]
74
+ .map(s => this.platform.quoteValue(s))
75
+ .join(', ');
76
+ return `${column} not in (${ignored}) and oracle_maintained = 'N'`;
77
+ }
78
+ getDefaultEmptyString() {
79
+ return 'null';
80
+ }
81
+ normalizeDefaultValue(defaultValue, length, defaultValues = {}, stripQuotes = false) {
82
+ if (defaultValue == null) {
83
+ return defaultValue;
84
+ }
85
+ // Trim whitespace that Oracle sometimes adds
86
+ defaultValue = defaultValue.trim();
87
+ let match = /^\((.*)\)$/.exec(defaultValue);
88
+ if (match) {
89
+ defaultValue = match[1];
90
+ }
91
+ match = /^\((.*)\)$/.exec(defaultValue);
92
+ if (match) {
93
+ defaultValue = match[1];
94
+ }
95
+ match = /^'(.*)'$/.exec(defaultValue);
96
+ if (stripQuotes && match) {
97
+ defaultValue = match[1];
98
+ }
99
+ // Normalize current_timestamp variants (Oracle uses CURRENT_TIMESTAMP, SYSTIMESTAMP, etc.)
100
+ const lowerDefault = defaultValue.toLowerCase();
101
+ if (lowerDefault === 'current_timestamp' || lowerDefault.startsWith('current_timestamp(')) {
102
+ // Keep the precision if present
103
+ return defaultValue.toLowerCase();
104
+ }
105
+ return super.normalizeDefaultValue(defaultValue, length, OracleSchemaHelper.DEFAULT_VALUES);
106
+ }
107
+ async getAllColumns(connection, tablesBySchemas, ctx) {
108
+ const sql = `select
109
109
  atc.owner as schema_name,
110
110
  atc.table_name as table_name,
111
111
  atc.column_name as column_name,
@@ -127,64 +127,65 @@ export class OracleSchemaHelper extends SchemaHelper {
127
127
  where atc.hidden_column = 'NO'
128
128
  and (${[...tablesBySchemas.entries()].map(([schema, tables]) => `(atc.table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(', ')}) and atc.owner = ${this.platform.quoteValue(schema)})`).join(' or ')})
129
129
  order by atc.owner, atc.table_name, atc.column_id`;
130
- const allColumns = await connection.execute(sql, [], 'all', ctx);
131
- const str = val => (val != null ? '' + val : val);
132
- const ret = {};
133
- for (const col of allColumns) {
134
- const mappedType = this.platform.getMappedType(col.data_type);
135
- const defaultValue = str(this.normalizeDefaultValue(col.column_default, col.length, {}));
136
- const increments = col.is_identity === 'YES' && connection.getPlatform().isNumericColumn(mappedType);
137
- const key = this.getTableKey(col);
138
- /* v8 ignore next */
139
- const generated = col.generation_expression
140
- ? `${col.generation_expression}${col.is_persisted ? ' persisted' : ''}`
141
- : undefined;
142
- let type = col.data_type;
143
- // Set length based on column type
144
- if (['varchar', 'varchar2', 'char'].includes(col.data_type)) {
145
- col.length = col.character_maximum_length;
146
- } else if (col.data_type === 'raw') {
147
- // RAW columns use data_length for their size (e.g., raw(16) for UUIDs)
148
- col.length = col.data_length;
149
- }
150
- if (mappedType instanceof DateTimeType) {
151
- col.length = col.datetime_precision;
152
- }
153
- /* v8 ignore next 2: length formatting branch */
154
- if (col.length != null && !type.endsWith(`(${col.length})`) && !['text', 'date'].includes(type)) {
155
- type += `(${col.length === -1 ? 'max' : col.length})`;
156
- }
157
- // Oracle uses 'number' for numeric types (not 'numeric')
158
- if (type === 'number' && col.numeric_precision != null && col.numeric_scale != null) {
159
- type += `(${col.numeric_precision}, ${col.numeric_scale})`;
160
- }
161
- if (type === 'float' && col.numeric_precision != null) {
162
- type += `(${col.numeric_precision})`;
163
- }
164
- ret[key] ??= [];
165
- ret[key].push({
166
- name: col.column_name,
167
- type: this.platform.isNumericColumn(mappedType)
168
- ? col.data_type.replace(/ unsigned$/, '').replace(/\(\d+\)$/, '')
169
- : type,
170
- mappedType,
171
- unsigned: col.data_type.endsWith(' unsigned'),
172
- length: col.length,
173
- default: increments ? undefined : this.wrap(defaultValue, mappedType),
174
- nullable: col.is_nullable === 'Y',
175
- autoincrement: increments,
176
- precision: col.numeric_precision,
177
- scale: col.numeric_scale,
178
- comment: col.column_comment,
179
- generated,
180
- });
181
- }
182
- return ret;
183
- }
184
- async getAllIndexes(connection, tablesBySchemas, ctx) {
185
- // Query indexes and join with constraints to identify which indexes back PRIMARY KEY or UNIQUE constraints
186
- // Also join with all_ind_expressions to get function-based index expressions
187
- const sql = `select ind.table_owner as schema_name, ind.table_name, ind.index_name, aic.column_name,
130
+ const allColumns = await connection.execute(sql, [], 'all', ctx);
131
+ const str = (val) => (val != null ? '' + val : val);
132
+ const ret = {};
133
+ for (const col of allColumns) {
134
+ const mappedType = this.platform.getMappedType(col.data_type);
135
+ const defaultValue = str(this.normalizeDefaultValue(col.column_default, col.length, {}));
136
+ const increments = col.is_identity === 'YES' && connection.getPlatform().isNumericColumn(mappedType);
137
+ const key = this.getTableKey(col);
138
+ /* v8 ignore next */
139
+ const generated = col.generation_expression
140
+ ? `${col.generation_expression}${col.is_persisted ? ' persisted' : ''}`
141
+ : undefined;
142
+ let type = col.data_type;
143
+ // Set length based on column type
144
+ if (['varchar', 'varchar2', 'char'].includes(col.data_type)) {
145
+ col.length = col.character_maximum_length;
146
+ }
147
+ else if (col.data_type === 'raw') {
148
+ // RAW columns use data_length for their size (e.g., raw(16) for UUIDs)
149
+ col.length = col.data_length;
150
+ }
151
+ if (mappedType instanceof DateTimeType) {
152
+ col.length = col.datetime_precision;
153
+ }
154
+ /* v8 ignore next 2: length formatting branch */
155
+ if (col.length != null && !type.endsWith(`(${col.length})`) && !['text', 'date'].includes(type)) {
156
+ type += `(${col.length === -1 ? 'max' : col.length})`;
157
+ }
158
+ // Oracle uses 'number' for numeric types (not 'numeric')
159
+ if (type === 'number' && col.numeric_precision != null && col.numeric_scale != null) {
160
+ type += `(${col.numeric_precision}, ${col.numeric_scale})`;
161
+ }
162
+ if (type === 'float' && col.numeric_precision != null) {
163
+ type += `(${col.numeric_precision})`;
164
+ }
165
+ ret[key] ??= [];
166
+ ret[key].push({
167
+ name: col.column_name,
168
+ type: this.platform.isNumericColumn(mappedType)
169
+ ? col.data_type.replace(/ unsigned$/, '').replace(/\(\d+\)$/, '')
170
+ : type,
171
+ mappedType,
172
+ unsigned: col.data_type.endsWith(' unsigned'),
173
+ length: col.length,
174
+ default: increments ? undefined : this.wrap(defaultValue, mappedType),
175
+ nullable: col.is_nullable === 'Y',
176
+ autoincrement: increments,
177
+ precision: col.numeric_precision,
178
+ scale: col.numeric_scale,
179
+ comment: col.column_comment,
180
+ generated,
181
+ });
182
+ }
183
+ return ret;
184
+ }
185
+ async getAllIndexes(connection, tablesBySchemas, ctx) {
186
+ // Query indexes and join with constraints to identify which indexes back PRIMARY KEY or UNIQUE constraints
187
+ // Also join with all_ind_expressions to get function-based index expressions
188
+ const sql = `select ind.table_owner as schema_name, ind.table_name, ind.index_name, aic.column_name,
188
189
  case ind.uniqueness when 'UNIQUE' then 'YES' else 'NO' end as is_unique,
189
190
  case when con.constraint_type = 'P' then 'YES' else 'NO' end as is_primary_key,
190
191
  con.constraint_type,
@@ -196,66 +197,62 @@ export class OracleSchemaHelper extends SchemaHelper {
196
197
  left join all_ind_expressions aie on ind.owner = aie.index_owner and ind.index_name = aie.index_name and aic.column_position = aie.column_position
197
198
  where (${[...tablesBySchemas.entries()].map(([schema, tables]) => `(ind.table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(', ')}) and ind.table_owner = ${this.platform.quoteValue(schema)})`).join(' or ')})
198
199
  order by ind.table_name, ind.index_name, aic.column_position`;
199
- const allIndexes = await connection.execute(sql, [], 'all', ctx);
200
- const ret = {};
201
- for (const index of allIndexes) {
202
- const key = this.getTableKey(index);
203
- // If this index backs a PRIMARY KEY or UNIQUE constraint, mark it appropriately
204
- const isPrimary = index.constraint_type === 'P';
205
- const isUniqueConstraint = index.constraint_type === 'U';
206
- const isConstraintIndex = isPrimary || isUniqueConstraint;
207
- // Skip indexes that back PRIMARY KEY constraints - they're handled as part of the table definition
208
- // and should not be managed as separate indexes
209
- if (isPrimary) {
210
- continue;
211
- }
212
- const indexDef = {
213
- columnNames: [index.column_name],
214
- keyName: index.index_name,
215
- unique: index.is_unique === 'YES',
216
- primary: false, // We skip PK indexes above, so this is always false
217
- constraint: isConstraintIndex || index.is_unique === 'YES',
218
- };
219
- // Handle function-based indexes (expression indexes)
220
- /* v8 ignore start: expression index branches */
221
- if (index.expression) {
222
- indexDef.expression = index.expression;
223
- } else if (index.column_name?.match(/[(): ,"'`]/)) {
224
- indexDef.expression = this.getCreateIndexSQL(index.table_name, indexDef, true);
225
- }
226
- /* v8 ignore stop */
227
- ret[key] ??= [];
228
- ret[key].push(indexDef);
229
- }
230
- for (const key of Object.keys(ret)) {
231
- ret[key] = await this.mapIndexes(ret[key]);
232
- }
233
- return ret;
234
- }
235
- mapForeignKeys(fks, tableName, schemaName) {
236
- const ret = super.mapForeignKeys(fks, tableName, schemaName);
237
- for (const fk of Utils.values(ret)) {
238
- fk.columnNames = Utils.unique(fk.columnNames);
239
- fk.referencedColumnNames = Utils.unique(fk.referencedColumnNames);
240
- }
241
- return ret;
242
- }
243
- createForeignKey(table, foreignKey, alterTable = true, inline = false) {
244
- // Oracle supports ON DELETE CASCADE and ON DELETE SET NULL, but not ON UPDATE
245
- const supportedDeleteRules = ['cascade', 'set null'];
246
- return super.createForeignKey(
247
- table,
248
- {
249
- ...foreignKey,
250
- updateRule: undefined,
251
- deleteRule: supportedDeleteRules.includes(foreignKey.deleteRule ?? '') ? foreignKey.deleteRule : undefined,
252
- },
253
- alterTable,
254
- inline,
255
- );
256
- }
257
- async getAllForeignKeys(connection, tablesBySchemas, ctx) {
258
- const sql = `select fk_cons.constraint_name, fk_cons.table_name, fk_cons.owner as schema_name, fk_cols.column_name,
200
+ const allIndexes = await connection.execute(sql, [], 'all', ctx);
201
+ const ret = {};
202
+ for (const index of allIndexes) {
203
+ const key = this.getTableKey(index);
204
+ // If this index backs a PRIMARY KEY or UNIQUE constraint, mark it appropriately
205
+ const isPrimary = index.constraint_type === 'P';
206
+ const isUniqueConstraint = index.constraint_type === 'U';
207
+ const isConstraintIndex = isPrimary || isUniqueConstraint;
208
+ // Skip indexes that back PRIMARY KEY constraints - they're handled as part of the table definition
209
+ // and should not be managed as separate indexes
210
+ if (isPrimary) {
211
+ continue;
212
+ }
213
+ const indexDef = {
214
+ columnNames: [index.column_name],
215
+ keyName: index.index_name,
216
+ unique: index.is_unique === 'YES',
217
+ primary: false, // We skip PK indexes above, so this is always false
218
+ constraint: isConstraintIndex || index.is_unique === 'YES',
219
+ };
220
+ // Handle function-based indexes (expression indexes)
221
+ /* v8 ignore start: expression index branches */
222
+ if (index.expression) {
223
+ indexDef.expression = index.expression;
224
+ }
225
+ else if (index.column_name?.match(/[(): ,"'`]/)) {
226
+ indexDef.expression = this.getCreateIndexSQL(index.table_name, indexDef, true);
227
+ }
228
+ /* v8 ignore stop */
229
+ ret[key] ??= [];
230
+ ret[key].push(indexDef);
231
+ }
232
+ for (const key of Object.keys(ret)) {
233
+ ret[key] = await this.mapIndexes(ret[key]);
234
+ }
235
+ return ret;
236
+ }
237
+ mapForeignKeys(fks, tableName, schemaName) {
238
+ const ret = super.mapForeignKeys(fks, tableName, schemaName);
239
+ for (const fk of Utils.values(ret)) {
240
+ fk.columnNames = Utils.unique(fk.columnNames);
241
+ fk.referencedColumnNames = Utils.unique(fk.referencedColumnNames);
242
+ }
243
+ return ret;
244
+ }
245
+ createForeignKey(table, foreignKey, alterTable = true, inline = false) {
246
+ // Oracle supports ON DELETE CASCADE and ON DELETE SET NULL, but not ON UPDATE
247
+ const supportedDeleteRules = ['cascade', 'set null'];
248
+ return super.createForeignKey(table, {
249
+ ...foreignKey,
250
+ updateRule: undefined,
251
+ deleteRule: supportedDeleteRules.includes(foreignKey.deleteRule ?? '') ? foreignKey.deleteRule : undefined,
252
+ }, alterTable, inline);
253
+ }
254
+ async getAllForeignKeys(connection, tablesBySchemas, ctx) {
255
+ const sql = `select fk_cons.constraint_name, fk_cons.table_name, fk_cons.owner as schema_name, fk_cols.column_name,
259
256
  fk_cons.r_owner as referenced_schema_name,
260
257
  pk_cols.column_name as referenced_column_name,
261
258
  pk_cons.table_name as referenced_table_name,
@@ -268,46 +265,46 @@ export class OracleSchemaHelper extends SchemaHelper {
268
265
  where fk_cons.constraint_type = 'R'
269
266
  and (${[...tablesBySchemas.entries()].map(([schema, tables]) => `(fk_cons.table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(', ')}) and fk_cons.owner = ${this.platform.quoteValue(schema)})`).join(' or ')})
270
267
  order by fk_cons.owner, fk_cons.table_name, fk_cons.constraint_name, pk_cols.position`;
271
- const allFks = await connection.execute(sql, [], 'all', ctx);
272
- const ret = {};
273
- for (const fk of allFks) {
274
- // Oracle returns schema names in uppercase - normalize to lowercase for consistency
275
- fk.schema_name = fk.schema_name?.toLowerCase();
276
- fk.referenced_schema_name = fk.referenced_schema_name?.toLowerCase();
277
- const key = this.getTableKey(fk);
278
- ret[key] ??= [];
279
- ret[key].push(fk);
280
- }
281
- Object.keys(ret).forEach(key => {
282
- const [schemaName, tableName] = key.split('.');
283
- ret[key] = this.mapForeignKeys(ret[key], tableName, schemaName);
284
- });
285
- return ret;
286
- }
287
- getEnumDefinitions(checks) {
288
- return checks.reduce((o, item, index) => {
289
- // check constraints are defined as
290
- // `([type]='owner' OR [type]='manager' OR [type]='employee')`
291
- const m1 = item.definition?.match(/^check \((.*)\)/);
292
- let items = m1?.[1].split(' OR ');
293
- /* v8 ignore next */
294
- const hasItems = (items?.length ?? 0) > 0;
295
- /* v8 ignore next: enum parsing branch */
296
- if (item.columnName && hasItems) {
297
- items = items
298
- .map(val => /^\(?'(.*)'/.exec(val.trim().replace(`"${item.columnName}"=`, ''))?.[1])
299
- .filter(Boolean);
300
- if (items.length > 0) {
301
- o[item.columnName] = items;
302
- }
303
- }
304
- return o;
305
- }, {});
306
- }
307
- getChecksSQL(tablesBySchemas) {
308
- // Filter out NOT NULL constraints using search_condition_vc (Oracle 12c+)
309
- // NOT NULL constraints have expressions like '"column_name" IS NOT NULL'
310
- return `select con.constraint_name as name,
268
+ const allFks = await connection.execute(sql, [], 'all', ctx);
269
+ const ret = {};
270
+ for (const fk of allFks) {
271
+ // Oracle returns schema names in uppercase - normalize to lowercase for consistency
272
+ fk.schema_name = fk.schema_name?.toLowerCase();
273
+ fk.referenced_schema_name = fk.referenced_schema_name?.toLowerCase();
274
+ const key = this.getTableKey(fk);
275
+ ret[key] ??= [];
276
+ ret[key].push(fk);
277
+ }
278
+ Object.keys(ret).forEach(key => {
279
+ const [schemaName, tableName] = key.split('.');
280
+ ret[key] = this.mapForeignKeys(ret[key], tableName, schemaName);
281
+ });
282
+ return ret;
283
+ }
284
+ getEnumDefinitions(checks) {
285
+ return checks.reduce((o, item, index) => {
286
+ // check constraints are defined as
287
+ // `([type]='owner' OR [type]='manager' OR [type]='employee')`
288
+ const m1 = item.definition?.match(/^check \((.*)\)/);
289
+ let items = m1?.[1].split(' OR ');
290
+ /* v8 ignore next */
291
+ const hasItems = (items?.length ?? 0) > 0;
292
+ /* v8 ignore next: enum parsing branch */
293
+ if (item.columnName && hasItems) {
294
+ items = items
295
+ .map(val => /^\(?'(.*)'/.exec(val.trim().replace(`"${item.columnName}"=`, ''))?.[1])
296
+ .filter(Boolean);
297
+ if (items.length > 0) {
298
+ o[item.columnName] = items;
299
+ }
300
+ }
301
+ return o;
302
+ }, {});
303
+ }
304
+ getChecksSQL(tablesBySchemas) {
305
+ // Filter out NOT NULL constraints using search_condition_vc (Oracle 12c+)
306
+ // NOT NULL constraints have expressions like '"column_name" IS NOT NULL'
307
+ return `select con.constraint_name as name,
311
308
  con.owner schema_name,
312
309
  con.table_name table_name,
313
310
  (select case when count(acc.column_name) = 1 then min(acc.column_name) else null end
@@ -323,279 +320,273 @@ export class OracleSchemaHelper extends SchemaHelper {
323
320
  and con.search_condition_vc not like '%IS NOT NULL'
324
321
  and (${[...tablesBySchemas.entries()].map(([schema, tables]) => `(con.table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(', ')}) and con.owner = ${this.platform.quoteValue(schema)})`).join(' or ')})
325
322
  order by con.constraint_name`;
326
- }
327
- async getAllChecks(connection, tablesBySchemas, ctx) {
328
- const sql = this.getChecksSQL(tablesBySchemas);
329
- const allChecks = await connection.execute(sql, [], 'all', ctx);
330
- const ret = {};
331
- for (const check of allChecks) {
332
- const key = this.getTableKey(check);
333
- ret[key] ??= [];
334
- const expression = check.expression.replace(/^\((.*)\)$/, '$1');
335
- ret[key].push({
336
- name: check.name,
337
- columnName: check.column_name,
338
- definition: `check (${expression})`,
339
- expression,
340
- });
341
- }
342
- return ret;
343
- }
344
- async loadInformationSchema(schema, connection, tables, schemas, ctx) {
345
- if (tables.length === 0) {
346
- return;
347
- }
348
- const tablesBySchema = this.getTablesGroupedBySchemas(tables);
349
- const columns = await this.getAllColumns(connection, tablesBySchema, ctx);
350
- const indexes = await this.getAllIndexes(connection, tablesBySchema, ctx);
351
- const checks = await this.getAllChecks(connection, tablesBySchema, ctx);
352
- const fks = await this.getAllForeignKeys(connection, tablesBySchema, ctx);
353
- for (const t of tables) {
354
- const key = this.getTableKey(t);
355
- const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
356
- const pks = await this.getPrimaryKeys(connection, indexes[key], table.name, table.schema);
357
- const enums = this.getEnumDefinitions(checks[key] ?? []);
358
- table.init(columns[key], indexes[key], checks[key], pks, fks[key], enums);
359
- }
360
- }
361
- getPreAlterTable(tableDiff, safe) {
362
- const ret = [];
363
- const indexes = tableDiff.fromTable.getIndexes();
364
- const parts = tableDiff.name.split('.');
365
- const tableName = parts.pop();
366
- const schemaName = parts.pop();
367
- const name =
368
- (schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName;
369
- const quotedName = this.quote(name);
370
- // indexes need to be first dropped to be able to change a column type
371
- const changedTypes = Object.values(tableDiff.changedColumns).filter(col => col.changedProperties.has('type'));
372
- for (const col of changedTypes) {
373
- for (const index of indexes) {
374
- if (index.columnNames.includes(col.column.name)) {
375
- ret.push(this.getDropIndexSQL(name, index));
376
- }
377
- }
378
- }
379
- return ret;
380
- }
381
- getPostAlterTable(tableDiff, safe) {
382
- const ret = [];
383
- const indexes = tableDiff.fromTable.getIndexes();
384
- const parts = tableDiff.name.split('.');
385
- const tableName = parts.pop();
386
- const schemaName = parts.pop();
387
- const name =
388
- (schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName;
389
- // indexes need to be first dropped to be able to change a column type
390
- const changedTypes = Object.values(tableDiff.changedColumns).filter(col => col.changedProperties.has('type'));
391
- for (const col of changedTypes) {
392
- for (const index of indexes) {
393
- if (index.columnNames.includes(col.column.name)) {
394
- this.append(ret, this.getCreateIndexSQL(name, index));
395
- }
396
- }
397
- }
398
- return ret;
399
- }
400
- getCreateNamespaceSQL(name) {
401
- const rawPassword = this.platform.getConfig().get('password');
402
- /* v8 ignore start: password type and tableSpace fallback */
403
- const password = typeof rawPassword === 'string' ? rawPassword : 'Schema_' + Math.random().toString(36).slice(2);
404
- const tableSpace = this.platform.getConfig().get('schemaGenerator').tableSpace ?? 'users';
405
- /* v8 ignore stop */
406
- return [
407
- `create user ${this.quote(name)}`,
408
- `identified by ${this.quote(password)}`,
409
- `default tablespace ${this.quote(tableSpace)}`,
410
- `quota unlimited on ${this.quote(tableSpace)}`,
411
- ].join(' ');
412
- }
413
- getDropNamespaceSQL(name) {
414
- return `drop user ${this.quote(name)} cascade`;
415
- }
416
- getDropIndexSQL(tableName, index) {
417
- return `drop index ${this.quote(index.keyName)}`;
418
- }
419
- dropIndex(table, index, oldIndexName = index.keyName) {
420
- if (index.primary) {
421
- return `alter table ${this.quote(table)} drop constraint ${this.quote(oldIndexName)}`;
422
- }
423
- return `drop index ${this.quote(oldIndexName)}`;
424
- }
425
- getManagementDbName() {
426
- /* v8 ignore next: managementDbName fallback */
427
- return this.platform.getConfig().get('schemaGenerator', {}).managementDbName ?? 'system';
428
- }
429
- getDatabaseNotExistsError(dbName) {
430
- return 'ORA-01918';
431
- }
432
- getCreateDatabaseSQL(name) {
433
- return `create user ${this.quote(name)}`;
434
- }
435
- getDropDatabaseSQL(name) {
436
- return `drop user ${this.quote(name)} cascade`;
437
- }
438
- getDropColumnsSQL(tableName, columns, schemaName) {
439
- /* v8 ignore next 3: schema prefix branch */
440
- const tableNameRaw = this.quote(
441
- (schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName,
442
- );
443
- const drops = [];
444
- for (const column of columns) {
445
- drops.push(this.quote(column.name));
446
- }
447
- return `alter table ${tableNameRaw} drop (${drops.join(', ')})`;
448
- }
449
- getRenameColumnSQL(tableName, oldColumnName, to, schemaName) {
450
- /* v8 ignore next 2: schema prefix branch */
451
- const tableNameRaw =
452
- (schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName;
453
- return `alter table ${this.quote(tableNameRaw)} rename column ${this.quote(oldColumnName)} to ${this.quote(to.name)}`;
454
- }
455
- createTableColumn(column, table, changedProperties) {
456
- const compositePK = table.getPrimaryKey()?.composite;
457
- const primaryKey = !changedProperties && !this.hasNonDefaultPrimaryKeyName(table);
458
- /* v8 ignore next: generated column branch */
459
- const columnType = column.generated ? `as ${column.generated}` : column.type;
460
- const col = [this.quote(column.name), columnType];
461
- Utils.runIfNotEmpty(() => col.push('generated by default as identity'), column.autoincrement);
462
- /* v8 ignore next 3: default value branch */
463
- const useDefault = changedProperties
464
- ? false
465
- : column.default != null && column.default !== 'null' && !column.autoincrement;
466
- // const defaultName = this.platform.getConfig().getNamingStrategy().indexName(table.name, [column.name], 'default');
467
- Utils.runIfNotEmpty(() => col.push(`default ${column.default}`), useDefault);
468
- /* v8 ignore next 2: nullable/not-null branches */
469
- Utils.runIfNotEmpty(() => col.push('null'), column.nullable);
470
- Utils.runIfNotEmpty(() => col.push('not null'), !column.nullable && !column.generated);
471
- /* v8 ignore next 6: autoincrement PK branch depends on column diff state */
472
- if (
473
- column.autoincrement &&
474
- !column.generated &&
475
- !compositePK &&
476
- (!changedProperties || changedProperties.has('autoincrement') || changedProperties.has('type'))
477
- ) {
478
- Utils.runIfNotEmpty(() => col.push('primary key'), primaryKey && column.primary);
479
- }
480
- return col.join(' ');
481
- }
482
- alterTableColumn(column, table, changedProperties) {
483
- const parts = [];
484
- const quotedTableName = table.getQuotedName();
485
- // Oracle uses MODIFY for column changes, and always requires the column type
486
- if (changedProperties.has('type') || changedProperties.has('nullable') || changedProperties.has('default')) {
487
- const colParts = [this.quote(column.name), column.type];
488
- if (changedProperties.has('default')) {
489
- if (column.default != null && column.default !== 'null') {
490
- colParts.push(`default ${column.default}`);
491
- } else {
492
- colParts.push('default null');
493
- }
494
- }
495
- if (changedProperties.has('nullable')) {
496
- colParts.push(column.nullable ? 'null' : 'not null');
497
- }
498
- parts.push(`alter table ${quotedTableName} modify ${colParts.join(' ')}`);
499
- }
500
- return parts;
501
- }
502
- getCreateIndexSQL(tableName, index, partialExpression = false) {
503
- if (index.expression && !partialExpression) {
504
- return index.expression;
505
- }
506
- const keyName = this.quote(index.keyName);
507
- /* v8 ignore next: deferred index branch */
508
- const defer = index.deferMode ? ` deferrable initially ${index.deferMode}` : '';
509
- const sql = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${this.quote(tableName)} `;
510
- if (index.expression && partialExpression) {
511
- return `${sql}(${index.expression})${defer}`;
512
- }
513
- return super.getCreateIndexSQL(tableName, index);
514
- }
515
- createIndex(index, table, createPrimary = false) {
516
- if (index.primary) {
517
- return '';
518
- }
519
- if (index.expression) {
520
- return index.expression;
521
- }
522
- // oracle creates an implicit index for unique constraints, so skip creating
523
- // a non-unique index when a unique index on the same columns already exists
524
- if (!index.unique) {
525
- const cols = index.columnNames.join(',');
526
- const hasUniqueIndex = table
527
- .getIndexes()
528
- .some(i => i.unique && i.keyName !== index.keyName && i.columnNames.join(',') === cols);
529
- if (hasUniqueIndex) {
530
- return '';
531
- }
532
- }
533
- const quotedTableName = table.getQuotedName();
534
- if (index.unique) {
535
- const nullableCols = index.columnNames.filter(column => table.getColumn(column)?.nullable);
536
- return `create unique index ${this.quote(index.keyName)} on ${quotedTableName} (${index.columnNames
537
- .map(c => {
538
- if (table.getColumn(c)?.nullable) {
539
- return `case when ${nullableCols.map(c => `${this.quote(c)} is not null`).join(' and ')} then ${this.quote(c)} end`;
540
- }
541
- return this.quote(c);
323
+ }
324
+ async getAllChecks(connection, tablesBySchemas, ctx) {
325
+ const sql = this.getChecksSQL(tablesBySchemas);
326
+ const allChecks = await connection.execute(sql, [], 'all', ctx);
327
+ const ret = {};
328
+ for (const check of allChecks) {
329
+ const key = this.getTableKey(check);
330
+ ret[key] ??= [];
331
+ const expression = check.expression.replace(/^\((.*)\)$/, '$1');
332
+ ret[key].push({
333
+ name: check.name,
334
+ columnName: check.column_name,
335
+ definition: `check (${expression})`,
336
+ expression,
337
+ });
338
+ }
339
+ return ret;
340
+ }
341
+ async loadInformationSchema(schema, connection, tables, schemas, ctx) {
342
+ if (tables.length === 0) {
343
+ return;
344
+ }
345
+ const tablesBySchema = this.getTablesGroupedBySchemas(tables);
346
+ const columns = await this.getAllColumns(connection, tablesBySchema, ctx);
347
+ const indexes = await this.getAllIndexes(connection, tablesBySchema, ctx);
348
+ const checks = await this.getAllChecks(connection, tablesBySchema, ctx);
349
+ const fks = await this.getAllForeignKeys(connection, tablesBySchema, ctx);
350
+ for (const t of tables) {
351
+ const key = this.getTableKey(t);
352
+ const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
353
+ const pks = await this.getPrimaryKeys(connection, indexes[key], table.name, table.schema);
354
+ const enums = this.getEnumDefinitions(checks[key] ?? []);
355
+ table.init(columns[key], indexes[key], checks[key], pks, fks[key], enums);
356
+ }
357
+ }
358
+ getPreAlterTable(tableDiff, safe) {
359
+ const ret = [];
360
+ const indexes = tableDiff.fromTable.getIndexes();
361
+ const parts = tableDiff.name.split('.');
362
+ const tableName = parts.pop();
363
+ const schemaName = parts.pop();
364
+ const name = (schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName;
365
+ const quotedName = this.quote(name);
366
+ // indexes need to be first dropped to be able to change a column type
367
+ const changedTypes = Object.values(tableDiff.changedColumns).filter(col => col.changedProperties.has('type'));
368
+ for (const col of changedTypes) {
369
+ for (const index of indexes) {
370
+ if (index.columnNames.includes(col.column.name)) {
371
+ ret.push(this.getDropIndexSQL(name, index));
372
+ }
373
+ }
374
+ }
375
+ return ret;
376
+ }
377
+ getPostAlterTable(tableDiff, safe) {
378
+ const ret = [];
379
+ const indexes = tableDiff.fromTable.getIndexes();
380
+ const parts = tableDiff.name.split('.');
381
+ const tableName = parts.pop();
382
+ const schemaName = parts.pop();
383
+ const name = (schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName;
384
+ // indexes need to be first dropped to be able to change a column type
385
+ const changedTypes = Object.values(tableDiff.changedColumns).filter(col => col.changedProperties.has('type'));
386
+ for (const col of changedTypes) {
387
+ for (const index of indexes) {
388
+ if (index.columnNames.includes(col.column.name)) {
389
+ this.append(ret, this.getCreateIndexSQL(name, index));
390
+ }
391
+ }
392
+ }
393
+ return ret;
394
+ }
395
+ getCreateNamespaceSQL(name) {
396
+ const rawPassword = this.platform.getConfig().get('password');
397
+ /* v8 ignore start: password type and tableSpace fallback */
398
+ const password = typeof rawPassword === 'string' ? rawPassword : 'Schema_' + Math.random().toString(36).slice(2);
399
+ const tableSpace = this.platform.getConfig().get('schemaGenerator').tableSpace ?? 'users';
400
+ /* v8 ignore stop */
401
+ return [
402
+ `create user ${this.quote(name)}`,
403
+ `identified by ${this.quote(password)}`,
404
+ `default tablespace ${this.quote(tableSpace)}`,
405
+ `quota unlimited on ${this.quote(tableSpace)}`,
406
+ ].join(' ');
407
+ }
408
+ getDropNamespaceSQL(name) {
409
+ return `drop user ${this.quote(name)} cascade`;
410
+ }
411
+ getDropIndexSQL(tableName, index) {
412
+ return `drop index ${this.quote(index.keyName)}`;
413
+ }
414
+ dropIndex(table, index, oldIndexName = index.keyName) {
415
+ if (index.primary) {
416
+ return `alter table ${this.quote(table)} drop constraint ${this.quote(oldIndexName)}`;
417
+ }
418
+ return `drop index ${this.quote(oldIndexName)}`;
419
+ }
420
+ getManagementDbName() {
421
+ /* v8 ignore next: managementDbName fallback */
422
+ return this.platform.getConfig().get('schemaGenerator', {}).managementDbName ?? 'system';
423
+ }
424
+ getDatabaseNotExistsError(dbName) {
425
+ return 'ORA-01918';
426
+ }
427
+ getCreateDatabaseSQL(name) {
428
+ return `create user ${this.quote(name)}`;
429
+ }
430
+ getDropDatabaseSQL(name) {
431
+ return `drop user ${this.quote(name)} cascade`;
432
+ }
433
+ getDropColumnsSQL(tableName, columns, schemaName) {
434
+ /* v8 ignore next 3: schema prefix branch */
435
+ const tableNameRaw = this.quote((schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName);
436
+ const drops = [];
437
+ for (const column of columns) {
438
+ drops.push(this.quote(column.name));
439
+ }
440
+ return `alter table ${tableNameRaw} drop (${drops.join(', ')})`;
441
+ }
442
+ getRenameColumnSQL(tableName, oldColumnName, to, schemaName) {
443
+ /* v8 ignore next 2: schema prefix branch */
444
+ const tableNameRaw = (schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName;
445
+ return `alter table ${this.quote(tableNameRaw)} rename column ${this.quote(oldColumnName)} to ${this.quote(to.name)}`;
446
+ }
447
+ createTableColumn(column, table, changedProperties) {
448
+ const compositePK = table.getPrimaryKey()?.composite;
449
+ const primaryKey = !changedProperties && !this.hasNonDefaultPrimaryKeyName(table);
450
+ /* v8 ignore next: generated column branch */
451
+ const columnType = column.generated ? `as ${column.generated}` : column.type;
452
+ const col = [this.quote(column.name), columnType];
453
+ Utils.runIfNotEmpty(() => col.push('generated by default as identity'), column.autoincrement);
454
+ /* v8 ignore next 3: default value branch */
455
+ const useDefault = changedProperties
456
+ ? false
457
+ : column.default != null && column.default !== 'null' && !column.autoincrement;
458
+ // const defaultName = this.platform.getConfig().getNamingStrategy().indexName(table.name, [column.name], 'default');
459
+ Utils.runIfNotEmpty(() => col.push(`default ${column.default}`), useDefault);
460
+ /* v8 ignore next 2: nullable/not-null branches */
461
+ Utils.runIfNotEmpty(() => col.push('null'), column.nullable);
462
+ Utils.runIfNotEmpty(() => col.push('not null'), !column.nullable && !column.generated);
463
+ /* v8 ignore next 6: autoincrement PK branch depends on column diff state */
464
+ if (column.autoincrement &&
465
+ !column.generated &&
466
+ !compositePK &&
467
+ (!changedProperties || changedProperties.has('autoincrement') || changedProperties.has('type'))) {
468
+ Utils.runIfNotEmpty(() => col.push('primary key'), primaryKey && column.primary);
469
+ }
470
+ return col.join(' ');
471
+ }
472
+ alterTableColumn(column, table, changedProperties) {
473
+ const parts = [];
474
+ const quotedTableName = table.getQuotedName();
475
+ // Oracle uses MODIFY for column changes, and always requires the column type
476
+ if (changedProperties.has('type') || changedProperties.has('nullable') || changedProperties.has('default')) {
477
+ const colParts = [this.quote(column.name), column.type];
478
+ if (changedProperties.has('default')) {
479
+ if (column.default != null && column.default !== 'null') {
480
+ colParts.push(`default ${column.default}`);
481
+ }
482
+ else {
483
+ colParts.push('default null');
484
+ }
485
+ }
486
+ if (changedProperties.has('nullable')) {
487
+ colParts.push(column.nullable ? 'null' : 'not null');
488
+ }
489
+ parts.push(`alter table ${quotedTableName} modify ${colParts.join(' ')}`);
490
+ }
491
+ return parts;
492
+ }
493
+ getCreateIndexSQL(tableName, index, partialExpression = false) {
494
+ if (index.expression && !partialExpression) {
495
+ return index.expression;
496
+ }
497
+ const keyName = this.quote(index.keyName);
498
+ /* v8 ignore next: deferred index branch */
499
+ const defer = index.deferMode ? ` deferrable initially ${index.deferMode}` : '';
500
+ const sql = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${this.quote(tableName)} `;
501
+ if (index.expression && partialExpression) {
502
+ return `${sql}(${index.expression})${defer}`;
503
+ }
504
+ return super.getCreateIndexSQL(tableName, index);
505
+ }
506
+ createIndex(index, table, createPrimary = false) {
507
+ if (index.primary) {
508
+ return '';
509
+ }
510
+ if (index.expression) {
511
+ return index.expression;
512
+ }
513
+ // oracle creates an implicit index for unique constraints, so skip creating
514
+ // a non-unique index when a unique index on the same columns already exists
515
+ if (!index.unique) {
516
+ const cols = index.columnNames.join(',');
517
+ const hasUniqueIndex = table
518
+ .getIndexes()
519
+ .some(i => i.unique && i.keyName !== index.keyName && i.columnNames.join(',') === cols);
520
+ if (hasUniqueIndex) {
521
+ return '';
522
+ }
523
+ }
524
+ const quotedTableName = table.getQuotedName();
525
+ if (index.unique) {
526
+ const nullableCols = index.columnNames.filter(column => table.getColumn(column)?.nullable);
527
+ return `create unique index ${this.quote(index.keyName)} on ${quotedTableName} (${index.columnNames
528
+ .map(c => {
529
+ if (table.getColumn(c)?.nullable) {
530
+ return `case when ${nullableCols.map(c => `${this.quote(c)} is not null`).join(' and ')} then ${this.quote(c)} end`;
531
+ }
532
+ return this.quote(c);
533
+ })
534
+ .join(', ')})`;
535
+ }
536
+ return super.createIndex(index, table);
537
+ }
538
+ dropForeignKey(tableName, constraintName) {
539
+ return `alter table ${this.quote(tableName)} drop constraint ${this.quote(constraintName)}`;
540
+ }
541
+ dropViewIfExists(name, schema) {
542
+ if (schema === this.platform.getDefaultSchemaName()) {
543
+ schema = undefined;
544
+ }
545
+ return `drop view if exists ${this.quote(schema, name)} cascade constraints`;
546
+ }
547
+ dropTableIfExists(name, schema) {
548
+ if (schema === this.platform.getDefaultSchemaName()) {
549
+ schema = undefined;
550
+ }
551
+ return `drop table if exists ${this.quote(schema, name)} cascade constraint`;
552
+ }
553
+ getAddColumnsSQL(table, columns) {
554
+ const adds = columns
555
+ .map(column => {
556
+ return this.createTableColumn(column, table);
542
557
  })
543
- .join(', ')})`;
544
- }
545
- return super.createIndex(index, table);
546
- }
547
- dropForeignKey(tableName, constraintName) {
548
- return `alter table ${this.quote(tableName)} drop constraint ${this.quote(constraintName)}`;
549
- }
550
- dropViewIfExists(name, schema) {
551
- if (schema === this.platform.getDefaultSchemaName()) {
552
- schema = undefined;
553
- }
554
- return `drop view if exists ${this.quote(schema, name)} cascade constraints`;
555
- }
556
- dropTableIfExists(name, schema) {
557
- if (schema === this.platform.getDefaultSchemaName()) {
558
- schema = undefined;
559
- }
560
- return `drop table if exists ${this.quote(schema, name)} cascade constraint`;
561
- }
562
- getAddColumnsSQL(table, columns) {
563
- const adds = columns
564
- .map(column => {
565
- return this.createTableColumn(column, table);
566
- })
567
- .join(', ');
568
- // Oracle requires parentheses when adding multiple columns
569
- const wrap = columns.length > 1 ? `(${adds})` : adds;
570
- return [`alter table ${table.getQuotedName()} add ${wrap}`];
571
- }
572
- appendComments(table) {
573
- const sql = [];
574
- if (table.comment) {
575
- const comment = this.platform.quoteValue(this.processComment(table.comment));
576
- sql.push(`comment on table ${table.getQuotedName()} is ${comment}`);
577
- }
578
- for (const column of table.getColumns()) {
579
- if (column.comment) {
580
- const comment = this.platform.quoteValue(this.processComment(column.comment));
581
- sql.push(`comment on column ${table.getQuotedName()}.${this.quote(column.name)} is ${comment}`);
582
- }
583
- }
584
- return sql;
585
- }
586
- inferLengthFromColumnType(type) {
587
- const match = /^(\w+)\s*\(\s*(-?\d+|max)\s*\)/.exec(type);
588
- if (!match) {
589
- return;
590
- }
591
- if (match[2] === 'max') {
592
- return -1;
593
- }
594
- return +match[2];
595
- }
596
- /* v8 ignore next 4: wrap is called by schema comparator internals */
597
- wrap(val, type) {
598
- const stringType = type instanceof StringType || type instanceof TextType || type instanceof EnumType;
599
- return typeof val === 'string' && val.length > 0 && stringType ? this.platform.quoteValue(val) : val;
600
- }
558
+ .join(', ');
559
+ // Oracle requires parentheses when adding multiple columns
560
+ const wrap = columns.length > 1 ? `(${adds})` : adds;
561
+ return [`alter table ${table.getQuotedName()} add ${wrap}`];
562
+ }
563
+ appendComments(table) {
564
+ const sql = [];
565
+ if (table.comment) {
566
+ const comment = this.platform.quoteValue(this.processComment(table.comment));
567
+ sql.push(`comment on table ${table.getQuotedName()} is ${comment}`);
568
+ }
569
+ for (const column of table.getColumns()) {
570
+ if (column.comment) {
571
+ const comment = this.platform.quoteValue(this.processComment(column.comment));
572
+ sql.push(`comment on column ${table.getQuotedName()}.${this.quote(column.name)} is ${comment}`);
573
+ }
574
+ }
575
+ return sql;
576
+ }
577
+ inferLengthFromColumnType(type) {
578
+ const match = /^(\w+)\s*\(\s*(-?\d+|max)\s*\)/.exec(type);
579
+ if (!match) {
580
+ return;
581
+ }
582
+ if (match[2] === 'max') {
583
+ return -1;
584
+ }
585
+ return +match[2];
586
+ }
587
+ /* v8 ignore next 4: wrap is called by schema comparator internals */
588
+ wrap(val, type) {
589
+ const stringType = type instanceof StringType || type instanceof TextType || type instanceof EnumType;
590
+ return typeof val === 'string' && val.length > 0 && stringType ? this.platform.quoteValue(val) : val;
591
+ }
601
592
  }