@mikro-orm/sql 7.3.0-dev.10 → 7.3.0-dev.11
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/dialects/mysql/BaseMySqlPlatform.d.ts +1 -0
- package/dialects/mysql/BaseMySqlPlatform.js +3 -0
- package/dialects/mysql/MySqlSchemaHelper.d.ts +2 -0
- package/dialects/mysql/MySqlSchemaHelper.js +13 -0
- package/dialects/postgresql/PostgreSqlSchemaHelper.d.ts +2 -0
- package/dialects/postgresql/PostgreSqlSchemaHelper.js +75 -21
- package/dialects/sqlite/SqlitePlatform.d.ts +1 -0
- package/dialects/sqlite/SqlitePlatform.js +3 -0
- package/dialects/sqlite/SqliteSchemaHelper.d.ts +1 -0
- package/dialects/sqlite/SqliteSchemaHelper.js +13 -0
- package/package.json +2 -2
- package/schema/DatabaseTable.js +2 -0
- package/schema/SchemaComparator.js +3 -1
- package/schema/SchemaHelper.d.ts +7 -1
- package/schema/SchemaHelper.js +32 -0
- package/schema/SqlSchemaGenerator.js +8 -0
- package/typings.d.ts +3 -1
|
@@ -37,6 +37,7 @@ export declare class BaseMySqlPlatform extends AbstractSqlPlatform {
|
|
|
37
37
|
getDefaultMappedType(type: string): Type<unknown>;
|
|
38
38
|
isNumericColumn(mappedType: Type<unknown>): boolean;
|
|
39
39
|
supportsUnsigned(): boolean;
|
|
40
|
+
supportsAutoincrementIncrement(): boolean;
|
|
40
41
|
/** MySQL/MariaDB identifier limit. */
|
|
41
42
|
getMaxIdentifierLength(): number;
|
|
42
43
|
getIndexName(tableName: string, columns: string[], type: 'index' | 'unique' | 'foreign' | 'primary' | 'sequence' | 'check'): string;
|
|
@@ -20,6 +20,8 @@ export declare class MySqlSchemaHelper extends SchemaHelper {
|
|
|
20
20
|
tableExists(connection: AbstractSqlConnection, tableName: string, schemaName: string | undefined, ctx?: Transaction): Promise<boolean>;
|
|
21
21
|
disableForeignKeysSQL(): string;
|
|
22
22
|
enableForeignKeysSQL(): string;
|
|
23
|
+
getResetSequenceSQL(tableName: string, schemaName: string | undefined, columnName: string, startWith: number): string;
|
|
24
|
+
getAddColumnsSQL(table: DatabaseTable, columns: Column[]): string[];
|
|
23
25
|
finalizeTable(table: DatabaseTable, charset: string, collate?: string): string;
|
|
24
26
|
getListTablesSQL(): string;
|
|
25
27
|
getListViewsSQL(): string;
|
|
@@ -42,12 +42,25 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
42
42
|
enableForeignKeysSQL() {
|
|
43
43
|
return 'set foreign_key_checks = 1;';
|
|
44
44
|
}
|
|
45
|
+
getResetSequenceSQL(tableName, schemaName, columnName, startWith) {
|
|
46
|
+
return `alter table ${this.quote(this.getTableName(tableName, schemaName))} auto_increment = ${startWith}`;
|
|
47
|
+
}
|
|
48
|
+
getAddColumnsSQL(table, columns) {
|
|
49
|
+
const [sql, ...rest] = super.getAddColumnsSQL(table, columns);
|
|
50
|
+
const startWith = columns.find(column => column.autoincrement)?.sequence?.startWith;
|
|
51
|
+
// the table option numbers the existing rows of the added column from the declared start too
|
|
52
|
+
return [startWith != null ? `${sql}, auto_increment = ${startWith}` : sql, ...rest];
|
|
53
|
+
}
|
|
45
54
|
finalizeTable(table, charset, collate) {
|
|
46
55
|
let sql = ` default character set ${charset}`;
|
|
47
56
|
if (collate) {
|
|
48
57
|
sql += ` collate ${collate}`;
|
|
49
58
|
}
|
|
50
59
|
sql += ' engine = InnoDB';
|
|
60
|
+
const startWith = table.getColumns().find(column => column.autoincrement)?.sequence?.startWith;
|
|
61
|
+
if (startWith != null) {
|
|
62
|
+
sql += ` auto_increment = ${startWith}`;
|
|
63
|
+
}
|
|
51
64
|
if (table.comment) {
|
|
52
65
|
sql += ` comment = ${this.platform.quoteValue(table.comment)}`;
|
|
53
66
|
}
|
|
@@ -29,6 +29,7 @@ export declare class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
29
29
|
loadMaterializedViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string, ctx?: Transaction): Promise<void>;
|
|
30
30
|
createMaterializedView(name: string, schema: string | undefined, definition: string, withData?: boolean): string;
|
|
31
31
|
createTable(table: DatabaseTable, alter?: boolean): string[];
|
|
32
|
+
getResetSequenceSQL(tableName: string, schemaName: string | undefined, columnName: string, startWith: number): string;
|
|
32
33
|
dropMaterializedViewIfExists(name: string, schema?: string): string;
|
|
33
34
|
refreshMaterializedView(name: string, schema?: string, concurrently?: boolean): string;
|
|
34
35
|
getNamespaces(connection: AbstractSqlConnection, ctx?: Transaction): Promise<string[]>;
|
|
@@ -134,6 +135,7 @@ export declare class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
134
135
|
castColumn(name: string, type: string): string;
|
|
135
136
|
dropForeignKey(tableName: string, constraintName: string): string;
|
|
136
137
|
getPostAlterTable(tableDiff: TableDifference, safe: boolean): string[];
|
|
138
|
+
getAddColumnsSQL(table: DatabaseTable, columns: Column[]): string[];
|
|
137
139
|
private getAlterColumnAutoincrement;
|
|
138
140
|
getChangeColumnCommentSQL(tableName: string, to: Column, schemaName?: string): string;
|
|
139
141
|
alterTableComment(table: DatabaseTable, comment?: string): string;
|
|
@@ -106,10 +106,23 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
106
106
|
}
|
|
107
107
|
createTable(table, alter) {
|
|
108
108
|
const partitioning = table.getPartitioning();
|
|
109
|
+
const [createTable, ...rest] = super.createTable(table, alter);
|
|
110
|
+
// `serial` columns can't declare sequence options inline, so alter the implicit sequence right after creating the table
|
|
111
|
+
const sequences = table
|
|
112
|
+
.getColumns()
|
|
113
|
+
.filter(column => column.autoincrement && !column.generated && this.getSequenceOptionsSQL(column))
|
|
114
|
+
.map(column => {
|
|
115
|
+
const sequence = `pg_get_serial_sequence(${this.platform.quoteValue(table.getQuotedName())}, ${this.platform.quoteValue(column.name)})`;
|
|
116
|
+
const { startWith = -1, incrementBy = 1 } = column.sequence;
|
|
117
|
+
// `alter sequence` keeps the ascending bounds of the serial, so a descending one gets the bounds and start of a fresh sequence
|
|
118
|
+
const options = incrementBy < 0
|
|
119
|
+
? `no minvalue maxvalue ${Math.max(startWith, -1)} start with ${startWith} increment by ${incrementBy}`
|
|
120
|
+
: this.getSequenceOptionsSQL(column);
|
|
121
|
+
return `do $$ begin execute format('alter sequence %s ${options} restart', ${sequence}); end $$`;
|
|
122
|
+
});
|
|
109
123
|
if (!partitioning) {
|
|
110
|
-
return
|
|
124
|
+
return [createTable, ...sequences, ...rest];
|
|
111
125
|
}
|
|
112
|
-
const [createTable, ...rest] = super.createTable(table, alter);
|
|
113
126
|
const partitions = partitioning.partitions.map(partition => {
|
|
114
127
|
const partitionName = this.quote(this.getTableName(partition.name, partition.schema ?? table.schema));
|
|
115
128
|
return `create table ${partitionName} partition of ${table.getQuotedName()} ${partition.bound}`;
|
|
@@ -119,7 +132,12 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
119
132
|
// regex replacement tokens like `$$`, `$&`, or `$1` inside user-supplied expressions (e.g., a
|
|
120
133
|
// callback that returns a dollar-quoted literal) are not interpreted as back-references.
|
|
121
134
|
const spliced = `${createTable.slice(0, -1)} partition by ${partitioning.definition};`;
|
|
122
|
-
return [spliced, ...rest, ...partitions];
|
|
135
|
+
return [spliced, ...sequences, ...rest, ...partitions];
|
|
136
|
+
}
|
|
137
|
+
getResetSequenceSQL(tableName, schemaName, columnName, startWith) {
|
|
138
|
+
const table = this.platform.quoteValue(this.quote(this.getTableName(tableName, schemaName)));
|
|
139
|
+
// `truncate … restart identity` goes back to the start the sequence was created with, which the metadata may not match
|
|
140
|
+
return `select setval(pg_get_serial_sequence(${table}, ${this.platform.quoteValue(columnName)}), ${startWith}, false)`;
|
|
123
141
|
}
|
|
124
142
|
dropMaterializedViewIfExists(name, schema) {
|
|
125
143
|
return `drop materialized view if exists ${this.quote(this.getTableName(name, schema))} cascade`;
|
|
@@ -387,15 +405,16 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
387
405
|
data_type,
|
|
388
406
|
is_identity,
|
|
389
407
|
identity_generation,
|
|
390
|
-
identity_start,
|
|
391
|
-
identity_increment,
|
|
392
408
|
generation_expression,
|
|
393
409
|
pg_catalog.col_description(pgc.oid, cols.ordinal_position::int) column_comment,
|
|
394
|
-
coll.collname as collation_name
|
|
410
|
+
coll.collname as collation_name,
|
|
411
|
+
seq.seqstart as sequence_start,
|
|
412
|
+
seq.seqincrement as sequence_increment
|
|
395
413
|
from information_schema.columns cols
|
|
396
414
|
join pg_class pgc on cols.table_name = pgc.relname
|
|
397
415
|
join pg_attribute pga on pgc.oid = pga.attrelid and cols.column_name = pga.attname
|
|
398
416
|
left join pg_collation coll on pga.attcollation = coll.oid and coll.collname <> 'default'
|
|
417
|
+
left join pg_sequence seq on seq.seqrelid = pg_get_serial_sequence(quote_ident(cols.table_schema) || '.' || quote_ident(cols.table_name), cols.column_name)::regclass
|
|
399
418
|
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 ')})
|
|
400
419
|
order by ordinal_position`;
|
|
401
420
|
const allColumns = await connection.execute(sql, [], 'all', ctx);
|
|
@@ -435,14 +454,6 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
435
454
|
type += `(${col.numeric_precision},${col.numeric_scale})`;
|
|
436
455
|
}
|
|
437
456
|
const length = this.inferLengthFromColumnType(type) === -1 ? -1 : col.length;
|
|
438
|
-
// a descending sequence starts at -1 by default
|
|
439
|
-
const defaultIdentityStart = col.identity_increment?.startsWith('-') ? '-1' : '1';
|
|
440
|
-
// read back non-default identity options, so `identity (start with 1000)` does not diff against plain `identity`
|
|
441
|
-
const identityOptions = [
|
|
442
|
-
col.identity_start !== defaultIdentityStart && `start with ${col.identity_start}`,
|
|
443
|
-
col.identity_increment !== '1' && `increment by ${col.identity_increment}`,
|
|
444
|
-
].filter(Boolean);
|
|
445
|
-
const identitySuffix = identityOptions.length > 0 ? ` (${identityOptions.join(' ')})` : '';
|
|
446
457
|
const column = {
|
|
447
458
|
name: col.column_name,
|
|
448
459
|
type,
|
|
@@ -454,8 +465,11 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
454
465
|
default: str(this.normalizeDefaultValue(col.column_default, col.length)),
|
|
455
466
|
unsigned: increments,
|
|
456
467
|
autoincrement: increments,
|
|
468
|
+
sequence: increments ? this.getIntrospectedSequence(col.sequence_start, col.sequence_increment) : undefined,
|
|
457
469
|
generated: col.is_identity === 'YES'
|
|
458
|
-
?
|
|
470
|
+
? col.identity_generation === 'BY DEFAULT'
|
|
471
|
+
? 'by default as identity'
|
|
472
|
+
: 'identity'
|
|
459
473
|
: col.generation_expression
|
|
460
474
|
? col.generation_expression + ' stored'
|
|
461
475
|
: undefined,
|
|
@@ -1040,11 +1054,15 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
1040
1054
|
columnType = this.quote(columnType);
|
|
1041
1055
|
}
|
|
1042
1056
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1057
|
+
const sequenceOptions = this.getSequenceOptionsSQL(column);
|
|
1058
|
+
const generated = sequenceOptions && /^(by default as )?identity$/.test(column.generated ?? '')
|
|
1059
|
+
? `${column.generated} (${sequenceOptions})`
|
|
1060
|
+
: column.generated;
|
|
1061
|
+
if (generated?.startsWith('by default as identity')) {
|
|
1062
|
+
columnType += ` generated ${generated}`;
|
|
1045
1063
|
}
|
|
1046
|
-
else if (
|
|
1047
|
-
columnType += ` generated always as ${
|
|
1064
|
+
else if (generated) {
|
|
1065
|
+
columnType += ` generated always as ${generated}`;
|
|
1048
1066
|
}
|
|
1049
1067
|
col.push(columnType);
|
|
1050
1068
|
Utils.runIfNotEmpty(() => col.push(this.getCollateSQL(column.collation)), column.collation);
|
|
@@ -1201,14 +1219,50 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
|
1201
1219
|
}
|
|
1202
1220
|
return ret;
|
|
1203
1221
|
}
|
|
1222
|
+
getAddColumnsSQL(table, columns) {
|
|
1223
|
+
const compositePK = table.getPrimaryKey()?.composite;
|
|
1224
|
+
const before = [];
|
|
1225
|
+
const after = [];
|
|
1226
|
+
const adds = columns.map(column => {
|
|
1227
|
+
const sequenceOptions = this.getSequenceOptionsSQL(column);
|
|
1228
|
+
if (!sequenceOptions || !column.autoincrement || column.generated) {
|
|
1229
|
+
return column;
|
|
1230
|
+
}
|
|
1231
|
+
// a `serial` column numbers the existing rows right away, so expand it to a sequence created with the options upfront
|
|
1232
|
+
const seqName = this.quote(this.getTableName(this.platform.getIndexName(table.name, [column.name], 'sequence'), table.schema));
|
|
1233
|
+
before.push(`create sequence ${seqName} ${sequenceOptions}`);
|
|
1234
|
+
after.push(`alter sequence ${seqName} owned by ${table.getQuotedName()}.${this.quote(column.name)}`);
|
|
1235
|
+
// the expanded column has no inline `primary key`, which `alterTable` expects from an added autoincrement PK
|
|
1236
|
+
if (column.primary && !compositePK && !this.hasNonDefaultPrimaryKeyName(table)) {
|
|
1237
|
+
after.push(`alter table ${table.getQuotedName()} add primary key (${this.quote(column.name)})`);
|
|
1238
|
+
}
|
|
1239
|
+
return {
|
|
1240
|
+
...column,
|
|
1241
|
+
type: column.mappedType.getColumnType({ autoincrement: false }, this.platform),
|
|
1242
|
+
autoincrement: false,
|
|
1243
|
+
nullable: false,
|
|
1244
|
+
default: `nextval('${seqName}')`,
|
|
1245
|
+
};
|
|
1246
|
+
});
|
|
1247
|
+
return [...before, ...super.getAddColumnsSQL(table, adds), ...after];
|
|
1248
|
+
}
|
|
1204
1249
|
getAlterColumnAutoincrement(tableName, column, schemaName) {
|
|
1205
1250
|
const ret = [];
|
|
1206
1251
|
/* v8 ignore next */
|
|
1207
1252
|
const name = (schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName;
|
|
1208
1253
|
if (column.autoincrement) {
|
|
1209
1254
|
const seqName = this.platform.getIndexName(tableName, [column.name], 'sequence');
|
|
1210
|
-
|
|
1211
|
-
|
|
1255
|
+
const sequenceOptions = this.getSequenceOptionsSQL(column);
|
|
1256
|
+
const { incrementBy = 1, startWith = incrementBy < 0 ? -1 : 1 } = column.sequence ?? {};
|
|
1257
|
+
const lastValue = `(select ${incrementBy < 0 ? 'min' : 'max'}(${this.quote(column.name)}) from ${this.quote(name)})`;
|
|
1258
|
+
ret.push(`create sequence if not exists ${this.quote(seqName)}${sequenceOptions ? ` ${sequenceOptions}` : ''}`);
|
|
1259
|
+
if (sequenceOptions) {
|
|
1260
|
+
// continue after the existing values, but never before the declared start
|
|
1261
|
+
ret.push(`select setval('${seqName}', ${incrementBy < 0 ? 'least' : 'greatest'}(${lastValue} + ${incrementBy}, ${startWith}), false)`);
|
|
1262
|
+
}
|
|
1263
|
+
else {
|
|
1264
|
+
ret.push(`select setval('${seqName}', ${lastValue})`);
|
|
1265
|
+
}
|
|
1212
1266
|
ret.push(`alter table ${this.quote(name)} alter column ${this.quote(column.name)} set default nextval('${seqName}')`);
|
|
1213
1267
|
}
|
|
1214
1268
|
return ret;
|
|
@@ -14,6 +14,7 @@ export declare class SqlitePlatform extends AbstractSqlPlatform {
|
|
|
14
14
|
usesReturningStatement(): boolean;
|
|
15
15
|
usesEnumCheckConstraints(): boolean;
|
|
16
16
|
supportsComments(): boolean;
|
|
17
|
+
supportsAutoincrementIncrement(): boolean;
|
|
17
18
|
getCurrentTimestampSQL(length: number): string;
|
|
18
19
|
getDateTimeTypeDeclarationSQL(column: {
|
|
19
20
|
length: number;
|
|
@@ -21,6 +21,7 @@ export declare class SqliteSchemaHelper extends SchemaHelper {
|
|
|
21
21
|
getDropDatabaseSQL(name: string): string;
|
|
22
22
|
loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[], ctx?: Transaction): Promise<void>;
|
|
23
23
|
createTable(table: DatabaseTable, alter?: boolean): string[];
|
|
24
|
+
getResetSequenceSQL(tableName: string, schemaName: string | undefined, columnName: string, startWith: number): string;
|
|
24
25
|
createTableColumn(column: Column, table: DatabaseTable, _changedProperties?: Set<string>): string | undefined;
|
|
25
26
|
getAddColumnsSQL(table: DatabaseTable, columns: Column[], diff?: TableDifference): string[];
|
|
26
27
|
dropForeignKey(tableName: string, constraintName: string): string;
|
|
@@ -144,6 +144,13 @@ export class SqliteSchemaHelper extends SchemaHelper {
|
|
|
144
144
|
}
|
|
145
145
|
const ret = [];
|
|
146
146
|
this.append(ret, sql);
|
|
147
|
+
const startWith = columns.find(column => column.autoincrement)?.sequence?.startWith;
|
|
148
|
+
if (startWith != null) {
|
|
149
|
+
// a table rebuild renames the counter row of the temp table over, so only seed it when missing
|
|
150
|
+
const sequenceTable = this.quote(this.getTableName('sqlite_sequence', table.schema));
|
|
151
|
+
const name = this.platform.quoteValue(table.name);
|
|
152
|
+
this.append(ret, `insert into ${sequenceTable} (name, seq) select ${name}, ${startWith - 1} where not exists (select 1 from ${sequenceTable} where name = ${name})`);
|
|
153
|
+
}
|
|
147
154
|
for (const index of table.getIndexes()) {
|
|
148
155
|
this.append(ret, this.createIndex(index, table));
|
|
149
156
|
}
|
|
@@ -152,6 +159,12 @@ export class SqliteSchemaHelper extends SchemaHelper {
|
|
|
152
159
|
}
|
|
153
160
|
return ret;
|
|
154
161
|
}
|
|
162
|
+
getResetSequenceSQL(tableName, schemaName, columnName, startWith) {
|
|
163
|
+
const sequenceTable = this.quote(this.getTableName('sqlite_sequence', schemaName));
|
|
164
|
+
const name = this.platform.quoteValue(tableName);
|
|
165
|
+
// the counter row does not exist before the first insert when the table was created without `sequence`
|
|
166
|
+
return `delete from ${sequenceTable} where name = ${name};\ninsert into ${sequenceTable} (name, seq) values (${name}, ${startWith - 1})`;
|
|
167
|
+
}
|
|
155
168
|
createTableColumn(column, table, _changedProperties) {
|
|
156
169
|
const col = [this.quote(column.name)];
|
|
157
170
|
const checks = table.getChecks();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/sql",
|
|
3
|
-
"version": "7.3.0-dev.
|
|
3
|
+
"version": "7.3.0-dev.11",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"data-mapper",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@mikro-orm/core": "^7.2.2"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@mikro-orm/core": "7.3.0-dev.
|
|
56
|
+
"@mikro-orm/core": "7.3.0-dev.11"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">= 22.17.0"
|
package/schema/DatabaseTable.js
CHANGED
|
@@ -155,6 +155,7 @@ export class DatabaseTable {
|
|
|
155
155
|
comment: prop.comment,
|
|
156
156
|
collation: prop.collation,
|
|
157
157
|
extra: prop.extra,
|
|
158
|
+
sequence: prop.sequence,
|
|
158
159
|
ignoreSchemaChanges: prop.ignoreSchemaChanges,
|
|
159
160
|
};
|
|
160
161
|
this.#columns[field].unsigned ??= this.#columns[field].autoincrement;
|
|
@@ -796,6 +797,7 @@ export class DatabaseTable {
|
|
|
796
797
|
nullable: column.nullable,
|
|
797
798
|
primary: column.primary && persist,
|
|
798
799
|
autoincrement: column.autoincrement,
|
|
800
|
+
sequence: column.sequence,
|
|
799
801
|
fieldName: column.name,
|
|
800
802
|
unsigned: column.unsigned,
|
|
801
803
|
length: column.length,
|
|
@@ -708,7 +708,9 @@ export class SchemaComparator {
|
|
|
708
708
|
log(`'nullable' changed for column ${fromTable.name}.${fromColumn.name}`, { fromColumn, toColumn });
|
|
709
709
|
changedProperties.add('nullable');
|
|
710
710
|
}
|
|
711
|
-
|
|
711
|
+
// identity options (start/increment) are applied on create only, same as the `sequence` option
|
|
712
|
+
const withoutIdentityOptions = (generated) => generated?.replace(/^((?:by default as )?identity)\s*\(.*\)$/is, '$1');
|
|
713
|
+
if (this.diffExpression(withoutIdentityOptions(fromColumn.generated), withoutIdentityOptions(toColumn.generated))) {
|
|
712
714
|
log(`'generated' changed for column ${fromTable.name}.${fromColumn.name}`, { fromColumn, toColumn });
|
|
713
715
|
changedProperties.add('generated');
|
|
714
716
|
}
|
package/schema/SchemaHelper.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Connection, type Dictionary, type Options, type Transaction, type RawQueryFragment } from '@mikro-orm/core';
|
|
1
|
+
import { type Connection, type Dictionary, type Options, type Transaction, type RawQueryFragment, type SequenceOptions } from '@mikro-orm/core';
|
|
2
2
|
import type { AbstractSqlConnection } from '../AbstractSqlConnection.js';
|
|
3
3
|
import type { AbstractSqlPlatform } from '../AbstractSqlPlatform.js';
|
|
4
4
|
import type { CheckDef, Column, ForeignKey, IndexDef, Table, TableDifference, SqlTriggerDef, SqlRoutineDef } from '../typings.js';
|
|
@@ -45,6 +45,12 @@ export declare abstract class SchemaHelper {
|
|
|
45
45
|
resolveMigrationSchema(schema: string | undefined): string | undefined;
|
|
46
46
|
finalizeTable(table: DatabaseTable, charset: string, collate?: string): string;
|
|
47
47
|
appendComments(table: DatabaseTable): string[];
|
|
48
|
+
/** Returns SQL that moves the autoincrement counter back to `sequence.startWith` after `clear()` truncated the table. */
|
|
49
|
+
getResetSequenceSQL(tableName: string, schemaName: string | undefined, columnName: string, startWith: number): string;
|
|
50
|
+
/** Maps the introspected start and increment of an autoincrement column to its `sequence` option, omitting defaults. */
|
|
51
|
+
protected getIntrospectedSequence(start: unknown, increment: unknown): SequenceOptions | undefined;
|
|
52
|
+
/** Renders the `start with … increment by …` clause for the `sequence` option of an autoincrement column. */
|
|
53
|
+
protected getSequenceOptionsSQL(column: Column): string;
|
|
48
54
|
supportsSchemaConstraints(): boolean;
|
|
49
55
|
getPrimaryKeys(connection: AbstractSqlConnection, indexes: IndexDef[] | undefined, tableName: string, schemaName?: string): Promise<string[]>;
|
|
50
56
|
inferLengthFromColumnType(type: string): number | undefined;
|
package/schema/SchemaHelper.js
CHANGED
|
@@ -91,6 +91,38 @@ export class SchemaHelper {
|
|
|
91
91
|
appendComments(table) {
|
|
92
92
|
return [];
|
|
93
93
|
}
|
|
94
|
+
/** Returns SQL that moves the autoincrement counter back to `sequence.startWith` after `clear()` truncated the table. */
|
|
95
|
+
/* v8 ignore next */
|
|
96
|
+
getResetSequenceSQL(tableName, schemaName, columnName, startWith) {
|
|
97
|
+
return '';
|
|
98
|
+
}
|
|
99
|
+
/** Maps the introspected start and increment of an autoincrement column to its `sequence` option, omitting defaults. */
|
|
100
|
+
getIntrospectedSequence(start, increment) {
|
|
101
|
+
if (start == null) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
const incrementBy = Number(increment ?? 1);
|
|
105
|
+
const startWith = Number(start);
|
|
106
|
+
const sequence = {};
|
|
107
|
+
if (startWith !== (incrementBy < 0 ? -1 : 1)) {
|
|
108
|
+
sequence.startWith = startWith;
|
|
109
|
+
}
|
|
110
|
+
if (incrementBy !== 1) {
|
|
111
|
+
sequence.incrementBy = incrementBy;
|
|
112
|
+
}
|
|
113
|
+
return Utils.hasObjectKeys(sequence) ? sequence : undefined;
|
|
114
|
+
}
|
|
115
|
+
/** Renders the `start with … increment by …` clause for the `sequence` option of an autoincrement column. */
|
|
116
|
+
getSequenceOptionsSQL(column) {
|
|
117
|
+
const { startWith, incrementBy } = column.sequence ?? {};
|
|
118
|
+
const descending = incrementBy != null && incrementBy < 0;
|
|
119
|
+
// a sequence is bounded by 1 (ascending) or -1 (descending) by default, a start beyond that has to move the bound
|
|
120
|
+
const bound = startWith != null &&
|
|
121
|
+
(descending ? startWith > -1 && `maxvalue ${startWith}` : startWith < 1 && `minvalue ${startWith}`);
|
|
122
|
+
return [startWith != null && `start with ${startWith}`, incrementBy != null && `increment by ${incrementBy}`, bound]
|
|
123
|
+
.filter(Boolean)
|
|
124
|
+
.join(' ');
|
|
125
|
+
}
|
|
94
126
|
supportsSchemaConstraints() {
|
|
95
127
|
return true;
|
|
96
128
|
}
|
|
@@ -141,6 +141,14 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
|
|
|
141
141
|
.withSchema(schema)
|
|
142
142
|
.truncate()
|
|
143
143
|
.execute();
|
|
144
|
+
// the counters of a TPT child's inherited columns (PK included) belong to the parent table
|
|
145
|
+
const props = meta.tptParent ? (meta.ownProps ?? []) : meta.props;
|
|
146
|
+
for (const prop of props.filter(prop => prop.autoincrement && prop.sequence?.startWith != null)) {
|
|
147
|
+
const sql = this.helper.getResetSequenceSQL(meta.tableName, this.getSchemaName(meta, { schema }), prop.fieldNames[0], prop.sequence.startWith);
|
|
148
|
+
if (sql) {
|
|
149
|
+
await this.execute(sql, { ctx: this.em?.getTransactionContext() });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
144
152
|
}
|
|
145
153
|
catch (e) {
|
|
146
154
|
if (this.platform.getExceptionConverter().convertException(e) instanceof TableNotFoundException) {
|
package/typings.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Generated, Kysely } from 'kysely';
|
|
2
|
-
import type { CheckCallback, DeferMode, Dictionary, EntityName, EntityMetadata, EntityProperty, EntitySchemaWithMeta, ExtractDefineEntityProperties, FilterQuery, GroupOperator, IndexColumnOptions, InferEntityName, Opt, Primary, PrimaryProperty, QueryFlag, QueryOrderMap, RawQueryFragment, RoutineIgnoreField, Scalar, Type } from '@mikro-orm/core';
|
|
2
|
+
import type { CheckCallback, DeferMode, Dictionary, EntityName, EntityMetadata, EntityProperty, EntitySchemaWithMeta, ExtractDefineEntityProperties, FilterQuery, GroupOperator, IndexColumnOptions, InferEntityName, Opt, Primary, PrimaryProperty, QueryFlag, QueryOrderMap, RawQueryFragment, RoutineIgnoreField, Scalar, SequenceOptions, Type } from '@mikro-orm/core';
|
|
3
3
|
import type { JoinType, QueryType } from './query/enums.js';
|
|
4
4
|
import type { DatabaseSchema } from './schema/DatabaseSchema.js';
|
|
5
5
|
import type { DatabaseTable } from './schema/DatabaseTable.js';
|
|
@@ -37,6 +37,8 @@ export interface Column {
|
|
|
37
37
|
mappedType: Type<unknown>;
|
|
38
38
|
unsigned?: boolean;
|
|
39
39
|
autoincrement?: boolean;
|
|
40
|
+
/** applied only when the column is created, never diffed */
|
|
41
|
+
sequence?: SequenceOptions;
|
|
40
42
|
nullable?: boolean;
|
|
41
43
|
length?: number;
|
|
42
44
|
precision?: number;
|