@mikro-orm/mssql 7.1.0-dev.20 → 7.1.0-dev.22

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.
@@ -30,6 +30,7 @@ export declare class MsSqlSchemaHelper extends SchemaHelper {
30
30
  /** Generates SQL to drop an MSSQL trigger. */
31
31
  dropTrigger(table: DatabaseTable, trigger: SqlTriggerDef): string;
32
32
  private getSchemaQualifiedName;
33
+ getDatabaseCollation(connection: AbstractSqlConnection, ctx?: Transaction): Promise<string | undefined>;
33
34
  getAllTriggers(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]>): Promise<Dictionary<SqlTriggerDef[]>>;
34
35
  loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[], ctx?: Transaction): Promise<void>;
35
36
  getPreAlterTable(tableDiff: TableDifference, safe: boolean): string[];
@@ -21,8 +21,29 @@ export class MsSqlSchemaHelper extends SchemaHelper {
21
21
  return 'master';
22
22
  }
23
23
  getDropDatabaseSQL(name) {
24
+ // `set offline` rejects all connections including the issuing session, so there is no
25
+ // single-user race window where a torn-down pool connection can reconnect between the
26
+ // mode switch and the drop (SQL Server error 3702 "currently in use"). Dropping an
27
+ // offline database leaves the underlying `.mdf`/`.ldf` files behind though, which
28
+ // makes a subsequent `create database` with the same name fail with error 5170
29
+ // ("file already exists"). Capture the physical paths up front and call
30
+ // `master.sys.xp_delete_files` after the drop to clean them up.
24
31
  const quoted = this.quote(name);
25
- return `if db_id(${this.platform.quoteValue(name)}) is not null begin alter database ${quoted} set single_user with rollback immediate; drop database ${quoted}; end`;
32
+ const literal = this.platform.quoteValue(name);
33
+ return (`if db_id(${literal}) is not null begin ` +
34
+ `declare @drop_files table (path nvarchar(260)); ` +
35
+ `insert into @drop_files (path) select physical_name from sys.master_files where database_id = db_id(${literal}); ` +
36
+ `alter database ${quoted} set offline with rollback immediate; ` +
37
+ `drop database ${quoted}; ` +
38
+ `declare @drop_path nvarchar(260); ` +
39
+ `declare drop_files_cursor cursor local fast_forward for select path from @drop_files; ` +
40
+ `open drop_files_cursor; fetch next from drop_files_cursor into @drop_path; ` +
41
+ `while @@fetch_status = 0 begin ` +
42
+ `begin try exec master.sys.xp_delete_files @drop_path; end try begin catch end catch; ` +
43
+ `fetch next from drop_files_cursor into @drop_path; ` +
44
+ `end ` +
45
+ `close drop_files_cursor; deallocate drop_files_cursor; ` +
46
+ `end`);
26
47
  }
27
48
  disableForeignKeysSQL() {
28
49
  return `exec sp_MSforeachtable 'alter table ? nocheck constraint all';`;
@@ -93,7 +114,8 @@ export class MsSqlSchemaHelper extends SchemaHelper {
93
114
  numeric_scale as numeric_scale,
94
115
  datetime_precision as datetime_precision,
95
116
  character_maximum_length as character_maximum_length,
96
- columnproperty(sc.object_id, column_name, 'IsIdentity') is_identity
117
+ columnproperty(sc.object_id, column_name, 'IsIdentity') is_identity,
118
+ nullif(ic.collation_name, convert(nvarchar(128), databasepropertyex(db_name(), 'Collation'))) as collation_name
97
119
  from information_schema.columns ic
98
120
  inner join sys.columns sc on sc.name = ic.column_name and sc.object_id = object_id(ic.table_schema + '.' + ic.table_name)
99
121
  left join sys.computed_columns cmp on cmp.name = ic.column_name and cmp.object_id = object_id(ic.table_schema + '.' + ic.table_name)
@@ -145,6 +167,7 @@ export class MsSqlSchemaHelper extends SchemaHelper {
145
167
  precision: col.numeric_precision,
146
168
  scale: col.numeric_scale,
147
169
  comment: col.column_comment,
170
+ collation: col.collation_name ?? undefined,
148
171
  generated,
149
172
  });
150
173
  }
@@ -337,6 +360,10 @@ export class MsSqlSchemaHelper extends SchemaHelper {
337
360
  }
338
361
  return this.quote(name);
339
362
  }
363
+ async getDatabaseCollation(connection, ctx) {
364
+ const [row] = await connection.execute(`select convert(nvarchar(128), databasepropertyex(db_name(), 'Collation')) as collation`, [], 'all', ctx);
365
+ return row?.collation;
366
+ }
340
367
  async getAllTriggers(connection, tablesBySchemas) {
341
368
  const conditions = [];
342
369
  for (const [schema, tables] of tablesBySchemas) {
@@ -398,9 +425,11 @@ export class MsSqlSchemaHelper extends SchemaHelper {
398
425
  const checks = await this.getAllChecks(connection, tablesBySchema, ctx);
399
426
  const fks = await this.getAllForeignKeys(connection, tablesBySchema, ctx);
400
427
  const triggers = await this.getAllTriggers(connection, tablesBySchema);
428
+ const dbCollation = await this.getDatabaseCollation(connection, ctx);
401
429
  for (const t of tables) {
402
430
  const key = this.getTableKey(t);
403
431
  const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
432
+ table.collation = dbCollation;
404
433
  const pks = await this.getPrimaryKeys(connection, indexes[key], table.name, table.schema);
405
434
  const enums = this.getEnumDefinitions(checks[key] ?? []);
406
435
  table.init(columns[key], indexes[key], checks[key], pks, fks[key], enums);
@@ -522,7 +551,11 @@ export class MsSqlSchemaHelper extends SchemaHelper {
522
551
  else {
523
552
  col.push(columnType);
524
553
  }
525
- Utils.runIfNotEmpty(() => col.push('identity(1,1)'), column.autoincrement);
554
+ Utils.runIfNotEmpty(() => col.push(this.getCollateSQL(column.collation)), column.collation);
555
+ // `IDENTITY(1,1)` is rejected inside `ALTER COLUMN`, so it must only be emitted when the
556
+ // change actually involves the identity attribute or is a fresh column (no `changedProperties`).
557
+ Utils.runIfNotEmpty(() => col.push('identity(1,1)'), column.autoincrement &&
558
+ (!changedProperties || changedProperties.has('autoincrement') || changedProperties.has('type')));
526
559
  Utils.runIfNotEmpty(() => col.push('null'), column.nullable);
527
560
  Utils.runIfNotEmpty(() => col.push('not null'), !column.nullable && !column.generated);
528
561
  if (column.autoincrement &&
@@ -544,7 +577,7 @@ export class MsSqlSchemaHelper extends SchemaHelper {
544
577
  const [constraint] = this.getDropDefaultsSQL(table.name, [column], table.schema);
545
578
  parts.push(constraint);
546
579
  }
547
- if (changedProperties.has('type') || changedProperties.has('nullable')) {
580
+ if (changedProperties.has('type') || changedProperties.has('nullable') || changedProperties.has('collation')) {
548
581
  const col = this.createTableColumn(column, table, changedProperties);
549
582
  parts.push(`alter table ${table.getQuotedName()} alter column ${col}`);
550
583
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/mssql",
3
- "version": "7.1.0-dev.20",
3
+ "version": "7.1.0-dev.22",
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",
@@ -47,7 +47,7 @@
47
47
  "copy": "node ../../scripts/copy.mjs"
48
48
  },
49
49
  "dependencies": {
50
- "@mikro-orm/sql": "7.1.0-dev.20",
50
+ "@mikro-orm/sql": "7.1.0-dev.22",
51
51
  "kysely": "0.28.16",
52
52
  "tarn": "3.0.2",
53
53
  "tedious": "19.2.1",
@@ -57,7 +57,7 @@
57
57
  "@mikro-orm/core": "^7.0.12"
58
58
  },
59
59
  "peerDependencies": {
60
- "@mikro-orm/core": "7.1.0-dev.20"
60
+ "@mikro-orm/core": "7.1.0-dev.22"
61
61
  },
62
62
  "engines": {
63
63
  "node": ">= 22.17.0"