@mikro-orm/sql 7.0.0-rc.2 → 7.0.0-rc.3
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/AbstractSqlConnection.js +2 -1
- package/AbstractSqlDriver.d.ts +18 -12
- package/AbstractSqlDriver.js +187 -38
- package/AbstractSqlPlatform.d.ts +1 -0
- package/AbstractSqlPlatform.js +5 -3
- package/PivotCollectionPersister.js +2 -2
- package/SqlEntityManager.d.ts +2 -2
- package/SqlEntityManager.js +5 -5
- package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +2 -0
- package/dialects/mssql/MsSqlNativeQueryBuilder.js +8 -4
- package/dialects/mysql/BaseMySqlPlatform.js +1 -2
- package/dialects/mysql/MySqlSchemaHelper.js +21 -10
- package/dialects/postgresql/BasePostgreSqlPlatform.js +38 -30
- package/dialects/postgresql/PostgreSqlSchemaHelper.js +63 -47
- package/dialects/sqlite/BaseSqliteConnection.js +2 -2
- package/dialects/sqlite/NodeSqliteDialect.js +3 -1
- package/dialects/sqlite/SqlitePlatform.js +4 -1
- package/dialects/sqlite/SqliteSchemaHelper.js +11 -9
- package/package.json +30 -30
- package/plugin/transformer.js +17 -16
- package/query/CriteriaNode.js +28 -10
- package/query/CriteriaNodeFactory.js +5 -1
- package/query/NativeQueryBuilder.d.ts +25 -0
- package/query/NativeQueryBuilder.js +61 -1
- package/query/ObjectCriteriaNode.js +71 -27
- package/query/QueryBuilder.d.ts +151 -48
- package/query/QueryBuilder.js +233 -54
- package/query/QueryBuilderHelper.d.ts +4 -3
- package/query/QueryBuilderHelper.js +47 -17
- package/query/ScalarCriteriaNode.js +14 -7
- package/query/raw.js +1 -1
- package/schema/DatabaseSchema.js +21 -15
- package/schema/DatabaseTable.js +114 -54
- package/schema/SchemaComparator.js +56 -32
- package/schema/SchemaHelper.js +28 -8
- package/schema/SqlSchemaGenerator.js +13 -7
- package/tsconfig.build.tsbuildinfo +1 -1
- package/typings.d.ts +6 -4
|
@@ -12,7 +12,7 @@ class InsertStatement {
|
|
|
12
12
|
}
|
|
13
13
|
getData() {
|
|
14
14
|
const data = {};
|
|
15
|
-
this.keys.forEach((key, idx) => data[key] = this.data[idx]);
|
|
15
|
+
this.keys.forEach((key, idx) => (data[key] = this.data[idx]));
|
|
16
16
|
return data;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -28,7 +28,7 @@ class DeleteStatement {
|
|
|
28
28
|
}
|
|
29
29
|
getCondition() {
|
|
30
30
|
const cond = {};
|
|
31
|
-
this.keys.forEach((key, idx) => cond[key] = this.cond[idx]);
|
|
31
|
+
this.keys.forEach((key, idx) => (cond[key] = this.cond[idx]));
|
|
32
32
|
return cond;
|
|
33
33
|
}
|
|
34
34
|
}
|
package/SqlEntityManager.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export declare class SqlEntityManager<Driver extends AbstractSqlDriver = Abstrac
|
|
|
20
20
|
/**
|
|
21
21
|
* Shortcut for `createQueryBuilder()`
|
|
22
22
|
*/
|
|
23
|
-
qb<Entity extends object, RootAlias extends string = never>(entityName: EntityName<Entity>, alias?: RootAlias, type?: ConnectionType, loggerContext?: LoggingOptions): QueryBuilder<Entity, RootAlias, never, never, never, "*">;
|
|
23
|
+
qb<Entity extends object, RootAlias extends string = never>(entityName: EntityName<Entity>, alias?: RootAlias, type?: ConnectionType, loggerContext?: LoggingOptions): QueryBuilder<Entity, RootAlias, never, never, never, "*", {}>;
|
|
24
24
|
/**
|
|
25
25
|
* Returns configured Kysely instance.
|
|
26
26
|
*/
|
|
@@ -29,6 +29,6 @@ export declare class SqlEntityManager<Driver extends AbstractSqlDriver = Abstrac
|
|
|
29
29
|
getRepository<T extends object, U extends EntityRepository<T> = SqlEntityRepository<T>>(entityName: EntityName<T>): GetRepository<T, U>;
|
|
30
30
|
protected applyDiscriminatorCondition<Entity extends object>(entityName: EntityName<Entity>, where: FilterQuery<Entity>): FilterQuery<Entity>;
|
|
31
31
|
}
|
|
32
|
-
type EntitiesFromManager<TEntityManager extends EntityManager<any>> = NonNullable<TEntityManager['~entities']> extends any[] ?
|
|
32
|
+
type EntitiesFromManager<TEntityManager extends EntityManager<any>> = NonNullable<TEntityManager['~entities']> extends any[] ? Extract<NonNullable<TEntityManager['~entities']>[number], EntitySchemaWithMeta> : never;
|
|
33
33
|
type AllEntitiesFromManager<TEntityManager extends EntityManager<any>> = NonNullable<TEntityManager['~entities']> extends any[] ? NonNullable<TEntityManager['~entities']>[number] : never;
|
|
34
34
|
export {};
|
package/SqlEntityManager.js
CHANGED
|
@@ -22,11 +22,11 @@ export class SqlEntityManager extends EntityManager {
|
|
|
22
22
|
*/
|
|
23
23
|
getKysely(options = {}) {
|
|
24
24
|
let kysely = this.getConnection(options.type).getClient();
|
|
25
|
-
if (options.columnNamingStrategy != null
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
if (options.columnNamingStrategy != null ||
|
|
26
|
+
options.tableNamingStrategy != null ||
|
|
27
|
+
options.processOnCreateHooks != null ||
|
|
28
|
+
options.processOnUpdateHooks != null ||
|
|
29
|
+
options.convertValues != null) {
|
|
30
30
|
kysely = kysely.withPlugin(new MikroKyselyPlugin(this, options));
|
|
31
31
|
}
|
|
32
32
|
return kysely;
|
|
@@ -11,4 +11,6 @@ export declare class MsSqlNativeQueryBuilder extends NativeQueryBuilder {
|
|
|
11
11
|
protected compileSelect(): void;
|
|
12
12
|
protected addLockClause(): void;
|
|
13
13
|
protected compileTruncate(): void;
|
|
14
|
+
/** MSSQL has no RECURSIVE keyword — CTEs are implicitly recursive. */
|
|
15
|
+
protected getCteKeyword(_hasRecursive: boolean): string;
|
|
14
16
|
}
|
|
@@ -19,6 +19,7 @@ export class MsSqlNativeQueryBuilder extends NativeQueryBuilder {
|
|
|
19
19
|
if (this.options.comment) {
|
|
20
20
|
this.parts.push(...this.options.comment.map(comment => `/* ${comment} */`));
|
|
21
21
|
}
|
|
22
|
+
this.compileCtes();
|
|
22
23
|
if (this.options.onConflict && !Utils.isEmpty(Utils.asArray(this.options.data)[0])) {
|
|
23
24
|
this.compileUpsert();
|
|
24
25
|
}
|
|
@@ -77,9 +78,7 @@ export class MsSqlNativeQueryBuilder extends NativeQueryBuilder {
|
|
|
77
78
|
return { prefix: '', suffix: '' };
|
|
78
79
|
}
|
|
79
80
|
const returningFields = this.options.returning;
|
|
80
|
-
const selections = returningFields
|
|
81
|
-
.map(field => `[t].${this.platform.quoteIdentifier(field)}`)
|
|
82
|
-
.join(',');
|
|
81
|
+
const selections = returningFields.map(field => `[t].${this.platform.quoteIdentifier(field)}`).join(',');
|
|
83
82
|
return {
|
|
84
83
|
prefix: `select top(0) ${selections} into #out from ${this.getTableName()} as t left join ${this.getTableName()} on 0 = 1;`,
|
|
85
84
|
suffix: `select ${selections} from #out as t; drop table #out`,
|
|
@@ -181,7 +180,8 @@ export class MsSqlNativeQueryBuilder extends NativeQueryBuilder {
|
|
|
181
180
|
}
|
|
182
181
|
}
|
|
183
182
|
addLockClause() {
|
|
184
|
-
if (!this.options.lockMode ||
|
|
183
|
+
if (!this.options.lockMode ||
|
|
184
|
+
![LockMode.PESSIMISTIC_READ, LockMode.PESSIMISTIC_WRITE].includes(this.options.lockMode)) {
|
|
185
185
|
return;
|
|
186
186
|
}
|
|
187
187
|
const map = {
|
|
@@ -197,4 +197,8 @@ export class MsSqlNativeQueryBuilder extends NativeQueryBuilder {
|
|
|
197
197
|
const sql = `delete from ${tableName}; declare @count int = case @@rowcount when 0 then 1 else 0 end; dbcc checkident ('${tableName.replace(/[[\]]/g, '')}', reseed, @count)`;
|
|
198
198
|
this.parts.push(sql);
|
|
199
199
|
}
|
|
200
|
+
/** MSSQL has no RECURSIVE keyword — CTEs are implicitly recursive. */
|
|
201
|
+
getCteKeyword(_hasRecursive) {
|
|
202
|
+
return 'with';
|
|
203
|
+
}
|
|
200
204
|
}
|
|
@@ -44,8 +44,7 @@ export class BaseMySqlPlatform extends AbstractSqlPlatform {
|
|
|
44
44
|
return JSON.stringify(value);
|
|
45
45
|
}
|
|
46
46
|
getJsonIndexDefinition(index) {
|
|
47
|
-
return index.columnNames
|
|
48
|
-
.map(column => {
|
|
47
|
+
return index.columnNames.map(column => {
|
|
49
48
|
if (!column.includes('.')) {
|
|
50
49
|
return column;
|
|
51
50
|
}
|
|
@@ -89,11 +89,13 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
89
89
|
};
|
|
90
90
|
// Capture column options (prefix length, sort order)
|
|
91
91
|
if (index.sub_part != null || index.sort_order === 'D') {
|
|
92
|
-
indexDef.columns = [
|
|
92
|
+
indexDef.columns = [
|
|
93
|
+
{
|
|
93
94
|
name: index.column_name,
|
|
94
95
|
...(index.sub_part != null && { length: index.sub_part }),
|
|
95
96
|
...(index.sort_order === 'D' && { sort: 'DESC' }),
|
|
96
|
-
}
|
|
97
|
+
},
|
|
98
|
+
];
|
|
97
99
|
}
|
|
98
100
|
// Capture index type for fulltext and spatial indexes
|
|
99
101
|
if (index.index_type === 'FULLTEXT') {
|
|
@@ -149,7 +151,8 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
149
151
|
*/
|
|
150
152
|
getIndexColumns(index) {
|
|
151
153
|
if (index.columns?.length) {
|
|
152
|
-
return index.columns
|
|
154
|
+
return index.columns
|
|
155
|
+
.map(col => {
|
|
153
156
|
const quotedName = this.quote(col.name);
|
|
154
157
|
// MySQL supports collation via expression: (column_name COLLATE collation_name)
|
|
155
158
|
// When collation is specified, wrap in parentheses as an expression
|
|
@@ -173,7 +176,8 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
173
176
|
colDef += ` ${col.sort}`;
|
|
174
177
|
}
|
|
175
178
|
return colDef;
|
|
176
|
-
})
|
|
179
|
+
})
|
|
180
|
+
.join(', ');
|
|
177
181
|
}
|
|
178
182
|
return index.columnNames.map(c => this.quote(c)).join(', ');
|
|
179
183
|
}
|
|
@@ -205,20 +209,24 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
205
209
|
from information_schema.columns where table_schema = database() and table_name in (${tables.map(t => this.platform.quoteValue(t.table_name))})
|
|
206
210
|
order by ordinal_position`;
|
|
207
211
|
const allColumns = await connection.execute(sql);
|
|
208
|
-
const str = (val) => val != null ? '' + val : val;
|
|
212
|
+
const str = (val) => (val != null ? '' + val : val);
|
|
209
213
|
const extra = (val) => val.replace(/auto_increment|default_generated|(stored|virtual) generated/i, '').trim() || undefined;
|
|
210
214
|
const ret = {};
|
|
211
215
|
for (const col of allColumns) {
|
|
212
216
|
const mappedType = this.platform.getMappedType(col.column_type);
|
|
213
|
-
const defaultValue = str(this.normalizeDefaultValue(
|
|
217
|
+
const defaultValue = str(this.normalizeDefaultValue(mappedType.compareAsType() === 'boolean' && ['0', '1'].includes(col.column_default)
|
|
214
218
|
? ['false', 'true'][+col.column_default]
|
|
215
219
|
: col.column_default, col.length));
|
|
216
220
|
const key = this.getTableKey(col);
|
|
217
|
-
const generated = col.generation_expression
|
|
221
|
+
const generated = col.generation_expression
|
|
222
|
+
? `(${col.generation_expression.replaceAll(`\\'`, `'`)}) ${col.extra.match(/stored generated/i) ? 'stored' : 'virtual'}`
|
|
223
|
+
: undefined;
|
|
218
224
|
ret[key] ??= [];
|
|
219
225
|
ret[key].push({
|
|
220
226
|
name: col.column_name,
|
|
221
|
-
type: this.platform.isNumericColumn(mappedType)
|
|
227
|
+
type: this.platform.isNumericColumn(mappedType)
|
|
228
|
+
? col.column_type.replace(/ unsigned$/, '').replace(/\(\d+\)$/, '')
|
|
229
|
+
: col.column_type,
|
|
222
230
|
mappedType,
|
|
223
231
|
unsigned: col.column_type.endsWith(' unsigned'),
|
|
224
232
|
length: col.length,
|
|
@@ -328,7 +336,10 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
328
336
|
const enums = await connection.execute(sql);
|
|
329
337
|
return enums.reduce((o, item) => {
|
|
330
338
|
o[item.table_name] ??= {};
|
|
331
|
-
o[item.table_name][item.column_name] = item.column_type
|
|
339
|
+
o[item.table_name][item.column_name] = item.column_type
|
|
340
|
+
.match(/enum\((.*)\)/)[1]
|
|
341
|
+
.split(',')
|
|
342
|
+
.map((item) => item.match(/'(.*)'/)[1]);
|
|
332
343
|
return o;
|
|
333
344
|
}, {});
|
|
334
345
|
}
|
|
@@ -338,7 +349,7 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
338
349
|
}
|
|
339
350
|
const sql = `select 1 from information_schema.tables where table_name = 'CHECK_CONSTRAINTS' and table_schema = 'information_schema'`;
|
|
340
351
|
const res = await connection.execute(sql);
|
|
341
|
-
return this._cache.supportsCheckConstraints = res.length > 0;
|
|
352
|
+
return (this._cache.supportsCheckConstraints = res.length > 0);
|
|
342
353
|
}
|
|
343
354
|
getChecksSQL(tables) {
|
|
344
355
|
return `select cc.constraint_schema as table_schema, tc.table_name as table_name, cc.constraint_name as name, cc.check_clause as expression
|
|
@@ -113,8 +113,10 @@ export class BasePostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
113
113
|
}
|
|
114
114
|
getMappedType(type) {
|
|
115
115
|
switch (this.extractSimpleType(type)) {
|
|
116
|
-
case 'tsvector':
|
|
117
|
-
|
|
116
|
+
case 'tsvector':
|
|
117
|
+
return Type.getType(FullTextType);
|
|
118
|
+
default:
|
|
119
|
+
return super.getMappedType(type);
|
|
118
120
|
}
|
|
119
121
|
}
|
|
120
122
|
getRegExpOperator(val, flags) {
|
|
@@ -132,7 +134,7 @@ export class BasePostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
132
134
|
return { $re: val.source };
|
|
133
135
|
}
|
|
134
136
|
isBigIntProperty(prop) {
|
|
135
|
-
return super.isBigIntProperty(prop) ||
|
|
137
|
+
return super.isBigIntProperty(prop) || ['bigserial', 'int8'].includes(prop.columnTypes?.[0]);
|
|
136
138
|
}
|
|
137
139
|
getArrayDeclarationSQL() {
|
|
138
140
|
return 'text[]';
|
|
@@ -166,7 +168,7 @@ export class BasePostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
166
168
|
return ['begin'];
|
|
167
169
|
}
|
|
168
170
|
marshallArray(values) {
|
|
169
|
-
const quote = (v) => v === '' || v.match(/["{},\\]/) ? JSON.stringify(v) : v;
|
|
171
|
+
const quote = (v) => (v === '' || v.match(/["{},\\]/) ? JSON.stringify(v) : v);
|
|
170
172
|
return `{${values.map(v => quote('' + v)).join(',')}}`;
|
|
171
173
|
}
|
|
172
174
|
/* v8 ignore next */
|
|
@@ -174,7 +176,10 @@ export class BasePostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
174
176
|
if (value === '{}') {
|
|
175
177
|
return [];
|
|
176
178
|
}
|
|
177
|
-
return value
|
|
179
|
+
return value
|
|
180
|
+
.substring(1, value.length - 1)
|
|
181
|
+
.split(',')
|
|
182
|
+
.map(v => {
|
|
178
183
|
if (v === `""`) {
|
|
179
184
|
return '';
|
|
180
185
|
}
|
|
@@ -218,7 +223,8 @@ export class BasePostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
218
223
|
const cast = (key) => raw(type in types ? `(${key})::${types[type]}` : key);
|
|
219
224
|
let lastOperator = '->>';
|
|
220
225
|
// force `->` for operator payloads with array values
|
|
221
|
-
if (Utils.isPlainObject(value) &&
|
|
226
|
+
if (Utils.isPlainObject(value) &&
|
|
227
|
+
Object.keys(value).every(key => ARRAY_OPERATORS.includes(key) && Array.isArray(value[key]))) {
|
|
222
228
|
lastOperator = '->';
|
|
223
229
|
}
|
|
224
230
|
if (path.length === 0) {
|
|
@@ -227,8 +233,7 @@ export class BasePostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
227
233
|
return cast(`${root}->${path.map(a => this.quoteValue(a)).join('->')}${lastOperator}'${last}'`);
|
|
228
234
|
}
|
|
229
235
|
getJsonIndexDefinition(index) {
|
|
230
|
-
return index.columnNames
|
|
231
|
-
.map(column => {
|
|
236
|
+
return index.columnNames.map(column => {
|
|
232
237
|
if (!column.includes('.')) {
|
|
233
238
|
return column;
|
|
234
239
|
}
|
|
@@ -286,26 +291,26 @@ export class BasePostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
286
291
|
getDefaultMappedType(type) {
|
|
287
292
|
const normalizedType = this.extractSimpleType(type);
|
|
288
293
|
const map = {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
294
|
+
int2: 'smallint',
|
|
295
|
+
smallserial: 'smallint',
|
|
296
|
+
int: 'integer',
|
|
297
|
+
int4: 'integer',
|
|
298
|
+
serial: 'integer',
|
|
299
|
+
serial4: 'integer',
|
|
300
|
+
int8: 'bigint',
|
|
301
|
+
bigserial: 'bigint',
|
|
302
|
+
serial8: 'bigint',
|
|
303
|
+
numeric: 'decimal',
|
|
304
|
+
bool: 'boolean',
|
|
305
|
+
real: 'float',
|
|
306
|
+
float4: 'float',
|
|
307
|
+
float8: 'double',
|
|
308
|
+
timestamp: 'datetime',
|
|
309
|
+
timestamptz: 'datetime',
|
|
310
|
+
bytea: 'blob',
|
|
311
|
+
jsonb: 'json',
|
|
307
312
|
'character varying': 'varchar',
|
|
308
|
-
|
|
313
|
+
bpchar: 'character',
|
|
309
314
|
};
|
|
310
315
|
return super.getDefaultMappedType(map[normalizedType] ?? type);
|
|
311
316
|
}
|
|
@@ -339,9 +344,12 @@ export class BasePostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
339
344
|
*/
|
|
340
345
|
castColumn(prop) {
|
|
341
346
|
switch (prop?.columnTypes?.[0]) {
|
|
342
|
-
case this.getUuidTypeDeclarationSQL({}):
|
|
343
|
-
|
|
344
|
-
|
|
347
|
+
case this.getUuidTypeDeclarationSQL({}):
|
|
348
|
+
return '::text';
|
|
349
|
+
case this.getBooleanTypeDeclarationSQL():
|
|
350
|
+
return '::int';
|
|
351
|
+
default:
|
|
352
|
+
return '';
|
|
345
353
|
}
|
|
346
354
|
}
|
|
347
355
|
getDefaultClientUrl() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DeferMode, EnumType, Type, Utils } from '@mikro-orm/core';
|
|
1
|
+
import { DeferMode, EnumType, Type, Utils, } from '@mikro-orm/core';
|
|
2
2
|
import { SchemaHelper } from '../../schema/SchemaHelper.js';
|
|
3
3
|
/** PostGIS system views that should be automatically ignored */
|
|
4
4
|
const POSTGIS_VIEWS = ['geography_columns', 'geometry_columns'];
|
|
@@ -22,24 +22,24 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
22
22
|
return `create database ${name}`;
|
|
23
23
|
}
|
|
24
24
|
getListTablesSQL() {
|
|
25
|
-
return `select table_name, table_schema as schema_name, `
|
|
26
|
-
|
|
27
|
-
where c.oid = (select ('"' || table_schema || '"."' || table_name || '"')::regclass::oid) and c.relname = table_name) as table_comment `
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
return (`select table_name, table_schema as schema_name, ` +
|
|
26
|
+
`(select pg_catalog.obj_description(c.oid) from pg_catalog.pg_class c
|
|
27
|
+
where c.oid = (select ('"' || table_schema || '"."' || table_name || '"')::regclass::oid) and c.relname = table_name) as table_comment ` +
|
|
28
|
+
`from information_schema.tables ` +
|
|
29
|
+
`where ${this.getIgnoredNamespacesConditionSQL('table_schema')} ` +
|
|
30
|
+
`and table_name != 'geometry_columns' and table_name != 'spatial_ref_sys' and table_type != 'VIEW' ` +
|
|
31
|
+
`and table_name not in (select inhrelid::regclass::text from pg_inherits) ` +
|
|
32
|
+
`order by table_name`);
|
|
33
33
|
}
|
|
34
34
|
getIgnoredViewsCondition() {
|
|
35
35
|
return POSTGIS_VIEWS.map(v => `table_name != '${v}'`).join(' and ');
|
|
36
36
|
}
|
|
37
37
|
getListViewsSQL() {
|
|
38
|
-
return `select table_name as view_name, table_schema as schema_name, view_definition `
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
return (`select table_name as view_name, table_schema as schema_name, view_definition ` +
|
|
39
|
+
`from information_schema.views ` +
|
|
40
|
+
`where ${this.getIgnoredNamespacesConditionSQL('table_schema')} ` +
|
|
41
|
+
`and ${this.getIgnoredViewsCondition()} ` +
|
|
42
|
+
`order by table_name`);
|
|
43
43
|
}
|
|
44
44
|
async loadViews(schema, connection) {
|
|
45
45
|
const views = await connection.execute(this.getListViewsSQL());
|
|
@@ -51,10 +51,10 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
getListMaterializedViewsSQL() {
|
|
54
|
-
return `select matviewname as view_name, schemaname as schema_name, definition as view_definition `
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
return (`select matviewname as view_name, schemaname as schema_name, definition as view_definition ` +
|
|
55
|
+
`from pg_matviews ` +
|
|
56
|
+
`where ${this.getIgnoredNamespacesConditionSQL('schemaname')} ` +
|
|
57
|
+
`order by matviewname`);
|
|
58
58
|
}
|
|
59
59
|
async loadMaterializedViews(schema, connection, schemaName) {
|
|
60
60
|
const views = await connection.execute(this.getListMaterializedViewsSQL());
|
|
@@ -78,9 +78,9 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
78
78
|
return `refresh materialized view${concurrent} ${this.quote(this.getTableName(name, schema))}`;
|
|
79
79
|
}
|
|
80
80
|
async getNamespaces(connection) {
|
|
81
|
-
const sql = `select schema_name from information_schema.schemata `
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
const sql = `select schema_name from information_schema.schemata ` +
|
|
82
|
+
`where ${this.getIgnoredNamespacesConditionSQL()} ` +
|
|
83
|
+
`order by schema_name`;
|
|
84
84
|
const res = await connection.execute(sql);
|
|
85
85
|
return res.map(row => row.schema_name);
|
|
86
86
|
}
|
|
@@ -90,13 +90,11 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
90
90
|
'tiger',
|
|
91
91
|
'topology',
|
|
92
92
|
/* v8 ignore next */
|
|
93
|
-
...this.platform.getConfig().get('schemaGenerator').ignoreSchema ?? [],
|
|
94
|
-
]
|
|
95
|
-
|
|
96
|
-
'
|
|
97
|
-
|
|
98
|
-
'_timescaledb_',
|
|
99
|
-
].map(p => `"${column}" not like '${p}%'`).join(' and ');
|
|
93
|
+
...(this.platform.getConfig().get('schemaGenerator').ignoreSchema ?? []),
|
|
94
|
+
]
|
|
95
|
+
.map(s => this.platform.quoteValue(s))
|
|
96
|
+
.join(', ');
|
|
97
|
+
const ignoredPrefixes = ['pg_', 'crdb_', '_timescaledb_'].map(p => `"${column}" not like '${p}%'`).join(' and ');
|
|
100
98
|
return `${ignoredPrefixes} and "${column}" not in (${ignored})`;
|
|
101
99
|
}
|
|
102
100
|
async loadInformationSchema(schema, connection, tables, schemas) {
|
|
@@ -130,9 +128,7 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
130
128
|
const key = this.getTableKey(index);
|
|
131
129
|
// Extract INCLUDE columns from expression first, to filter them from key columns
|
|
132
130
|
const includeMatch = index.expression?.match(/include\s*\(([^)]+)\)/i);
|
|
133
|
-
const includeColumns = includeMatch
|
|
134
|
-
? includeMatch[1].split(',').map((col) => unquote(col.trim()))
|
|
135
|
-
: [];
|
|
131
|
+
const includeColumns = includeMatch ? includeMatch[1].split(',').map((col) => unquote(col.trim())) : [];
|
|
136
132
|
// Filter out INCLUDE columns from the column definitions to get only key columns
|
|
137
133
|
const keyColumnDefs = index.index_def.filter((col) => !includeColumns.includes(unquote(col)));
|
|
138
134
|
// Parse sort order and NULLS ordering from the full expression
|
|
@@ -268,17 +264,18 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
268
264
|
where (${[...tablesBySchemas.entries()].map(([schema, tables]) => `(table_schema = ${this.platform.quoteValue(schema)} and table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(',')}))`).join(' or ')})
|
|
269
265
|
order by ordinal_position`;
|
|
270
266
|
const allColumns = await connection.execute(sql);
|
|
271
|
-
const str = (val) => val != null ? '' + val : val;
|
|
267
|
+
const str = (val) => (val != null ? '' + val : val);
|
|
272
268
|
const ret = {};
|
|
273
269
|
for (const col of allColumns) {
|
|
274
270
|
const mappedType = connection.getPlatform().getMappedType(col.data_type);
|
|
275
|
-
const increments = (col.column_default?.includes('nextval') || col.is_identity === 'YES') &&
|
|
271
|
+
const increments = (col.column_default?.includes('nextval') || col.is_identity === 'YES') &&
|
|
272
|
+
connection.getPlatform().isNumericColumn(mappedType);
|
|
276
273
|
const key = this.getTableKey(col);
|
|
277
274
|
ret[key] ??= [];
|
|
278
|
-
let type = col.data_type.toLowerCase() === 'array'
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
275
|
+
let type = col.data_type.toLowerCase() === 'array' ? col.udt_name.replace(/^_(.*)$/, '$1[]') : col.udt_name;
|
|
276
|
+
if (col.data_type === 'USER-DEFINED' &&
|
|
277
|
+
col.udt_schema &&
|
|
278
|
+
col.udt_schema !== this.platform.getDefaultSchemaName()) {
|
|
282
279
|
type = `${col.udt_schema}.${type}`;
|
|
283
280
|
}
|
|
284
281
|
if (type === 'bpchar') {
|
|
@@ -305,7 +302,13 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
305
302
|
default: str(this.normalizeDefaultValue(col.column_default, col.length)),
|
|
306
303
|
unsigned: increments,
|
|
307
304
|
autoincrement: increments,
|
|
308
|
-
generated: col.is_identity === 'YES'
|
|
305
|
+
generated: col.is_identity === 'YES'
|
|
306
|
+
? col.identity_generation === 'BY DEFAULT'
|
|
307
|
+
? 'by default as identity'
|
|
308
|
+
: 'identity'
|
|
309
|
+
: col.generation_expression
|
|
310
|
+
? col.generation_expression + ' stored'
|
|
311
|
+
: undefined,
|
|
309
312
|
comment: col.column_comment,
|
|
310
313
|
};
|
|
311
314
|
if (nativeEnums?.[column.type]) {
|
|
@@ -321,10 +324,16 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
321
324
|
const sql = this.getChecksSQL(tablesBySchemas);
|
|
322
325
|
const allChecks = await connection.execute(sql);
|
|
323
326
|
const ret = {};
|
|
327
|
+
const seen = new Set();
|
|
324
328
|
for (const check of allChecks) {
|
|
325
329
|
const key = this.getTableKey(check);
|
|
330
|
+
const dedupeKey = `${key}:${check.name}`;
|
|
331
|
+
if (seen.has(dedupeKey)) {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
seen.add(dedupeKey);
|
|
326
335
|
ret[key] ??= [];
|
|
327
|
-
const m = check.expression.match(/^check \(\((.*)\)\)$/
|
|
336
|
+
const m = check.expression.match(/^check \(\((.*)\)\)$/is);
|
|
328
337
|
const def = m?.[1].replace(/\((.*?)\)::\w+/g, '$1');
|
|
329
338
|
ret[key].push({
|
|
330
339
|
name: check.name,
|
|
@@ -359,12 +368,17 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
359
368
|
}
|
|
360
369
|
/* v8 ignore next */
|
|
361
370
|
switch (value) {
|
|
362
|
-
case 'r':
|
|
363
|
-
|
|
364
|
-
case '
|
|
365
|
-
|
|
371
|
+
case 'r':
|
|
372
|
+
return 'RESTRICT';
|
|
373
|
+
case 'c':
|
|
374
|
+
return 'CASCADE';
|
|
375
|
+
case 'n':
|
|
376
|
+
return 'SET NULL';
|
|
377
|
+
case 'd':
|
|
378
|
+
return 'SET DEFAULT';
|
|
366
379
|
case 'a':
|
|
367
|
-
default:
|
|
380
|
+
default:
|
|
381
|
+
return 'NO ACTION';
|
|
368
382
|
}
|
|
369
383
|
}
|
|
370
384
|
for (const fk of allFks) {
|
|
@@ -645,7 +659,8 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
645
659
|
*/
|
|
646
660
|
getIndexColumns(index) {
|
|
647
661
|
if (index.columns?.length) {
|
|
648
|
-
return index.columns
|
|
662
|
+
return index.columns
|
|
663
|
+
.map(col => {
|
|
649
664
|
let colDef = this.quote(col.name);
|
|
650
665
|
// PostgreSQL supports collation with double quotes
|
|
651
666
|
if (col.collation) {
|
|
@@ -660,7 +675,8 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
660
675
|
colDef += ` nulls ${col.nulls}`;
|
|
661
676
|
}
|
|
662
677
|
return colDef;
|
|
663
|
-
})
|
|
678
|
+
})
|
|
679
|
+
.join(', ');
|
|
664
680
|
}
|
|
665
681
|
return index.columnNames.map(c => this.quote(c)).join(', ');
|
|
666
682
|
}
|
|
@@ -702,7 +718,7 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
702
718
|
from pg_constraint pgc
|
|
703
719
|
join pg_namespace nsp on nsp.oid = pgc.connamespace
|
|
704
720
|
join pg_class cls on pgc.conrelid = cls.oid
|
|
705
|
-
join information_schema.constraint_column_usage ccu on pgc.conname = ccu.constraint_name and nsp.nspname = ccu.constraint_schema
|
|
721
|
+
join information_schema.constraint_column_usage ccu on pgc.conname = ccu.constraint_name and nsp.nspname = ccu.constraint_schema and cls.relname = ccu.table_name
|
|
706
722
|
where contype = 'c' and (${[...tablesBySchemas.entries()].map(([schema, tables]) => `ccu.table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(',')}) and ccu.table_schema = ${this.platform.quoteValue(schema)}`).join(' or ')})
|
|
707
723
|
order by pgc.conname`;
|
|
708
724
|
}
|
|
@@ -2,8 +2,8 @@ import { CompiledQuery } from 'kysely';
|
|
|
2
2
|
import { AbstractSqlConnection } from '../../AbstractSqlConnection.js';
|
|
3
3
|
export class BaseSqliteConnection extends AbstractSqlConnection {
|
|
4
4
|
createKyselyDialect(options) {
|
|
5
|
-
throw new Error('No SQLite dialect configured. Pass a Kysely dialect via the `driverOptions` config option, '
|
|
6
|
-
|
|
5
|
+
throw new Error('No SQLite dialect configured. Pass a Kysely dialect via the `driverOptions` config option, ' +
|
|
6
|
+
'e.g. `new NodeSqliteDialect(...)` for node:sqlite or a custom dialect for other libraries.');
|
|
7
7
|
}
|
|
8
8
|
async connect(options) {
|
|
9
9
|
await super.connect(options);
|
|
@@ -125,7 +125,10 @@ export class SqlitePlatform extends AbstractSqlPlatform {
|
|
|
125
125
|
convertVersionValue(value, prop) {
|
|
126
126
|
if (prop.runtimeType === 'Date') {
|
|
127
127
|
const ts = +value;
|
|
128
|
-
const str = new Date(ts)
|
|
128
|
+
const str = new Date(ts)
|
|
129
|
+
.toISOString()
|
|
130
|
+
.replace('T', ' ')
|
|
131
|
+
.replace(/\.\d{3}Z$/, '');
|
|
129
132
|
return { $in: [ts, str] };
|
|
130
133
|
}
|
|
131
134
|
return value;
|
|
@@ -31,8 +31,8 @@ export class SqliteSchemaHelper extends SchemaHelper {
|
|
|
31
31
|
return '';
|
|
32
32
|
}
|
|
33
33
|
getListTablesSQL() {
|
|
34
|
-
return `select name as table_name from sqlite_master where type = 'table' and name != 'sqlite_sequence' and name != 'geometry_columns' and name != 'spatial_ref_sys' `
|
|
35
|
-
|
|
34
|
+
return (`select name as table_name from sqlite_master where type = 'table' and name != 'sqlite_sequence' and name != 'geometry_columns' and name != 'spatial_ref_sys' ` +
|
|
35
|
+
`union all select name as table_name from sqlite_temp_master where type = 'table' order by name`);
|
|
36
36
|
}
|
|
37
37
|
async getAllTables(connection, schemas) {
|
|
38
38
|
const databases = await this.getDatabaseList(connection);
|
|
@@ -183,9 +183,11 @@ export class SqliteSchemaHelper extends SchemaHelper {
|
|
|
183
183
|
getDropColumnsSQL(tableName, columns, schemaName) {
|
|
184
184
|
/* v8 ignore next */
|
|
185
185
|
const name = this.quote((schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName);
|
|
186
|
-
return columns
|
|
186
|
+
return columns
|
|
187
|
+
.map(column => {
|
|
187
188
|
return `alter table ${name} drop column ${this.quote(column.name)}`;
|
|
188
|
-
})
|
|
189
|
+
})
|
|
190
|
+
.join(';\n');
|
|
189
191
|
}
|
|
190
192
|
getCreateIndexSQL(tableName, index) {
|
|
191
193
|
/* v8 ignore next */
|
|
@@ -453,10 +455,10 @@ export class SqliteSchemaHelper extends SchemaHelper {
|
|
|
453
455
|
alterTable(diff, safe) {
|
|
454
456
|
const ret = [];
|
|
455
457
|
const [schemaName, tableName] = this.splitTableName(diff.name);
|
|
456
|
-
if (Utils.hasObjectKeys(diff.removedChecks)
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
458
|
+
if (Utils.hasObjectKeys(diff.removedChecks) ||
|
|
459
|
+
Utils.hasObjectKeys(diff.changedChecks) ||
|
|
460
|
+
Utils.hasObjectKeys(diff.changedForeignKeys) ||
|
|
461
|
+
Utils.hasObjectKeys(diff.changedColumns)) {
|
|
460
462
|
return this.getAlterTempTableSQL(diff);
|
|
461
463
|
}
|
|
462
464
|
for (const index of Object.values(diff.removedIndexes)) {
|
|
@@ -496,7 +498,7 @@ export class SqliteSchemaHelper extends SchemaHelper {
|
|
|
496
498
|
return ret;
|
|
497
499
|
}
|
|
498
500
|
getAlterTempTableSQL(changedTable) {
|
|
499
|
-
const tempName = `${
|
|
501
|
+
const tempName = `${changedTable.toTable.name}__temp_alter`;
|
|
500
502
|
const quotedName = this.quote(changedTable.toTable.name);
|
|
501
503
|
const quotedTempName = this.quote(tempName);
|
|
502
504
|
const [first, ...rest] = this.createTable(changedTable.toTable);
|