@entity-access/entity-access 1.0.491 → 1.0.492

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.
Files changed (58) hide show
  1. package/dist/common/CIMap.d.ts +16 -0
  2. package/dist/common/CIMap.d.ts.map +1 -0
  3. package/dist/common/CIMap.js +43 -0
  4. package/dist/common/CIMap.js.map +1 -0
  5. package/dist/common/IColumnSchema.d.ts +9 -0
  6. package/dist/common/IColumnSchema.d.ts.map +1 -1
  7. package/dist/drivers/base/BaseDriver.d.ts +0 -2
  8. package/dist/drivers/base/BaseDriver.d.ts.map +1 -1
  9. package/dist/drivers/base/BaseDriver.js.map +1 -1
  10. package/dist/drivers/base/ExistingSchema.d.ts +14 -0
  11. package/dist/drivers/base/ExistingSchema.d.ts.map +1 -0
  12. package/dist/drivers/base/ExistingSchema.js +34 -0
  13. package/dist/drivers/base/ExistingSchema.js.map +1 -0
  14. package/dist/drivers/postgres/PostgreSqlDriver.d.ts.map +1 -1
  15. package/dist/drivers/postgres/PostgreSqlDriver.js +0 -31
  16. package/dist/drivers/postgres/PostgreSqlDriver.js.map +1 -1
  17. package/dist/drivers/sql-server/SqlServerDriver.d.ts +0 -2
  18. package/dist/drivers/sql-server/SqlServerDriver.d.ts.map +1 -1
  19. package/dist/drivers/sql-server/SqlServerDriver.js +0 -41
  20. package/dist/drivers/sql-server/SqlServerDriver.js.map +1 -1
  21. package/dist/migrations/Migrations.d.ts +9 -2
  22. package/dist/migrations/Migrations.d.ts.map +1 -1
  23. package/dist/migrations/Migrations.js +49 -1
  24. package/dist/migrations/Migrations.js.map +1 -1
  25. package/dist/migrations/postgres/PostgresAutomaticMigrations.d.ts +2 -4
  26. package/dist/migrations/postgres/PostgresAutomaticMigrations.d.ts.map +1 -1
  27. package/dist/migrations/postgres/PostgresAutomaticMigrations.js +15 -39
  28. package/dist/migrations/postgres/PostgresAutomaticMigrations.js.map +1 -1
  29. package/dist/migrations/postgres/PostgresMigrations.d.ts +3 -0
  30. package/dist/migrations/postgres/PostgresMigrations.d.ts.map +1 -1
  31. package/dist/migrations/postgres/PostgresMigrations.js +68 -0
  32. package/dist/migrations/postgres/PostgresMigrations.js.map +1 -1
  33. package/dist/migrations/sql-server/SqlServerAutomaticMigrations.d.ts +2 -4
  34. package/dist/migrations/sql-server/SqlServerAutomaticMigrations.d.ts.map +1 -1
  35. package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js +22 -45
  36. package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js.map +1 -1
  37. package/dist/migrations/sql-server/SqlServerMigrations.d.ts +5 -0
  38. package/dist/migrations/sql-server/SqlServerMigrations.d.ts.map +1 -1
  39. package/dist/migrations/sql-server/SqlServerMigrations.js +77 -0
  40. package/dist/migrations/sql-server/SqlServerMigrations.js.map +1 -1
  41. package/dist/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +1 -1
  43. package/src/common/CIMap.ts +50 -0
  44. package/src/common/IColumnSchema.ts +12 -0
  45. package/src/drivers/base/BaseDriver.ts +1 -3
  46. package/src/drivers/base/ExistingSchema.ts +60 -0
  47. package/src/drivers/postgres/PostgreSqlDriver.ts +1 -32
  48. package/src/drivers/sql-server/SqlServerDriver.ts +1 -42
  49. package/src/migrations/Migrations.ts +76 -5
  50. package/src/migrations/postgres/PostgresAutomaticMigrations.ts +22 -54
  51. package/src/migrations/postgres/PostgresMigrations.ts +78 -0
  52. package/src/migrations/sql-server/SqlServerAutomaticMigrations.ts +27 -58
  53. package/src/migrations/sql-server/SqlServerMigrations.ts +86 -0
  54. package/dist/migrations/ExistingSchema.d.ts +0 -9
  55. package/dist/migrations/ExistingSchema.d.ts.map +0 -1
  56. package/dist/migrations/ExistingSchema.js +0 -31
  57. package/dist/migrations/ExistingSchema.js.map +0 -1
  58. package/src/migrations/ExistingSchema.ts +0 -39
@@ -0,0 +1,60 @@
1
+ import CIMap from "../../common/CIMap.js";
2
+ import IColumnSchema, { IConstraintSchema, IForeignKeyConstraintSchema, IIndexSchema } from "../../common/IColumnSchema.js";
3
+ import { BaseConnection } from "./BaseDriver.js";
4
+
5
+ export default class ExistingSchema {
6
+
7
+ public readonly tables: Map<string, Map<string, IColumnSchema>>;
8
+ public readonly indexes: Map<string, IIndexSchema>;
9
+ public readonly constraints: Map<string, IConstraintSchema>;
10
+ public readonly foreignKeys: Map<string, IForeignKeyConstraintSchema>;
11
+
12
+ constructor(
13
+ caseInsensitive = false,
14
+ {
15
+ columns,
16
+ indexes,
17
+ constraints,
18
+ foreignKeys
19
+ }: {
20
+ columns: IColumnSchema[],
21
+ indexes?: IIndexSchema[],
22
+ constraints?: IConstraintSchema[],
23
+ foreignKeys?: IForeignKeyConstraintSchema[]
24
+ }
25
+ ) {
26
+
27
+ this.tables = caseInsensitive
28
+ ? new CIMap<CIMap<IColumnSchema>>()
29
+ : new Map<string,Map<string, IColumnSchema>>();
30
+
31
+ for (const c of columns) {
32
+ const table = c.ownerName;
33
+ let list = this.tables.get(table);
34
+ if (!list) {
35
+ list = caseInsensitive ? new CIMap<IColumnSchema>() : new Map<string, IColumnSchema>();
36
+ this.tables.set(table, list);
37
+ }
38
+ list.set(c.name, c);
39
+ }
40
+
41
+ this.indexes = new CIMap<IIndexSchema>();
42
+
43
+ for (const index of indexes) {
44
+ this.indexes.set(index.name, index);
45
+ }
46
+
47
+ this.constraints = new CIMap<IConstraintSchema>();
48
+
49
+ for (const constraint of constraints) {
50
+ this.constraints.set(constraint.name, constraint);
51
+ }
52
+
53
+ this.foreignKeys = new CIMap<IForeignKeyConstraintSchema>();
54
+
55
+ for (const fk of foreignKeys) {
56
+ this.foreignKeys.set(fk.name, fk);
57
+ }
58
+ }
59
+
60
+ }
@@ -11,6 +11,7 @@ import DateTime from "../../types/DateTime.js";
11
11
  import { BaseConnection, BaseDriver, EntityTransaction, IDbConnectionString, IDbReader, IQuery, toQuery } from "../base/BaseDriver.js";
12
12
  import pg from "pg";
13
13
  import Cursor from "pg-cursor";
14
+ import ExistingSchema from "../base/ExistingSchema.js";
14
15
  export interface IPgSqlConnectionString extends IDbConnectionString {
15
16
 
16
17
  user?: string, // default process.env.PGUSER || process.env.USER
@@ -220,38 +221,6 @@ class PostgreSqlConnection extends BaseConnection {
220
221
  return new PostgresAutomaticMigrations(context);
221
222
  }
222
223
 
223
- async getColumnSchema(schema: string): Promise<IColumnSchema[]> {
224
- const text = `
225
- select
226
- column_name as "columnName",
227
- case data_type
228
- when 'bigint' then 'BigInt'
229
- when 'boolean' then 'Boolean'
230
- when 'timestamp' then 'DateTime'
231
- when 'timestamp with time zone' then 'DateTime'
232
- when 'timestamp without time zone' then 'DateTime'
233
- when 'integer' then 'Int'
234
- when 'real' then 'Double'
235
- when 'numeric' then 'Decimal'
236
- else 'Char' end as "dataType",
237
- case
238
- when is_nullable = 'YES' then true
239
- else false end as "nullable",
240
- character_maximum_length as "length",
241
- case
242
- when is_identity = 'YES' then 'identity'
243
- else null end as "identity",
244
- case
245
- when is_generated = 'YES' then '() => 1'
246
- else null end as "computed",
247
- table_name as "ownerName",
248
- 'table' as "ownerType"
249
- from information_schema.columns
250
- where table_schema = $1`;
251
- const r = await this.executeQuery({ text, values: [ schema ]});
252
- return r.rows;
253
- }
254
-
255
224
  public async executeReader(command: IQuery, signal?: AbortSignal): Promise<IDbReader> {
256
225
  return new DbReader(command, this, signal);
257
226
  }
@@ -11,6 +11,7 @@ import EntityType from "../../entity-query/EntityType.js";
11
11
  import DateTime from "../../types/DateTime.js";
12
12
  import IColumnSchema from "../../common/IColumnSchema.js";
13
13
  import type EntityContext from "../../model/EntityContext.js";
14
+ import ExistingSchema from "../base/ExistingSchema.js";
14
15
 
15
16
  export type ISqlServerConnectionString = IDbConnectionString & sql.config;
16
17
 
@@ -129,48 +130,6 @@ export class SqlServerConnection extends BaseConnection {
129
130
  super(driver);
130
131
  }
131
132
 
132
- async getColumnSchema(schema: string): Promise<IColumnSchema[]> {
133
- const text = `
134
- SELECT
135
- COLUMN_NAME as [name],
136
- CASE DATA_TYPE
137
- WHEN 'bit' THEN 'Boolean'
138
- WHEN 'int' Then 'Int'
139
- WHEN 'bigint' THEN 'BigInt'
140
- WHEN 'date' then 'DateTime'
141
- WHEN 'datetime' then 'DateTime'
142
- WHEN 'datetime2' then 'DateTime'
143
- WHEN 'real' then 'Float'
144
- WHEN 'double' then 'Double'
145
- WHEN 'decimal' then 'Decimal'
146
- WHEN 'identity' then 'UUID'
147
- WHEN 'varbinary' then 'ByteArray'
148
- WHEN 'geometry' then 'Geometry'
149
- ELSE 'Char'
150
- END as [dataType],
151
- CASE WHEN IS_NULLABLE = 'YES' THEN 1 ELSE 0 END as [nullable],
152
- CHARACTER_MAXIMUM_LENGTH as [length],
153
- CASE
154
- WHEN COLUMN_DEFAULT = 'getutcdate()' then '() => Sql.date.now()'
155
- WHEN COLUMN_DEFAULT = '(getutcdate())' then '() => Sql.date.now()'
156
- WHEN COLUMN_DEFAULT = '(newid())' then '() => Sql.crypto.randomUUID()'
157
- WHEN (COLUMN_DEFAULT = '(0)' OR COLUMN_DEFAULT = '((0))')
158
- AND DATA_TYPE = 'bit' THEN '() => false'
159
- WHEN (COLUMN_DEFAULT = '(1)' OR COLUMN_DEFAULT = '((1))')
160
- AND DATA_TYPE = 'bit' THEN '() => true'
161
- WHEN COLUMN_DEFAULT is NULL THEN ''
162
- ELSE '() => ' + COLUMN_DEFAULT
163
- END as [default],
164
- ColumnProperty(OBJECT_ID(TABLE_SCHEMA+'.'+TABLE_NAME),COLUMN_NAME,'IsComputed') as [computed],
165
- TABLE_NAME as [ownerName],
166
- 'table' as [ownerType]
167
- FROM INFORMATION_SCHEMA.COLUMNS
168
- WHERE TABLE_SCHEMA = $1
169
- `;
170
- const r = await this.executeQuery({ text, values: [schema] });
171
- return r.rows;
172
- }
173
-
174
133
  public async executeReader(command: IQuery, signal?: AbortSignal): Promise<IDbReader> {
175
134
  command = toQuery(command);
176
135
  let rq = await this.newRequest(signal);
@@ -1,3 +1,4 @@
1
+ import CIMap from "../common/CIMap.js";
1
2
  import Logger, { ConsoleLogger } from "../common/Logger.js";
2
3
  import { modelSymbol } from "../common/symbols/symbols.js";
3
4
  import type QueryCompiler from "../compiler/QueryCompiler.js";
@@ -6,18 +7,20 @@ import { IColumn } from "../decorators/IColumn.js";
6
7
  import type { IForeignKeyConstraint } from "../decorators/IForeignKeyConstraint.js";
7
8
  import type { IIndex } from "../decorators/IIndex.js";
8
9
  import type { BaseConnection, IQuery, IQueryResult } from "../drivers/base/BaseDriver.js";
10
+ import ExistingSchema from "../drivers/base/ExistingSchema.js";
9
11
  import type EntityType from "../entity-query/EntityType.js";
10
12
  import type EntityContext from "../model/EntityContext.js";
11
13
  import type EntityQuery from "../model/EntityQuery.js";
12
- import ExistingSchema from "./ExistingSchema.js";
13
14
 
14
15
  export default abstract class Migrations {
15
16
 
16
17
  logger: Logger;
17
18
 
19
+ protected schemaCache = new Map<string, ExistingSchema>();
20
+
18
21
  constructor(
19
22
  private context: EntityContext,
20
- private connection: BaseConnection = context.connection,
23
+ protected connection: BaseConnection = context.connection,
21
24
  protected compiler: QueryCompiler = context.driver.compiler
22
25
  ) {
23
26
 
@@ -76,12 +79,17 @@ export default abstract class Migrations {
76
79
  }
77
80
  }
78
81
 
82
+ const schema = await this.getSchema(type);
83
+
79
84
  await this.migrateTable(context, type);
80
85
 
81
86
  // create constraints
82
87
  for (const iterator of type.checkConstraints) {
88
+ if (schema.constraints.has(iterator.name)) {
89
+ continue;
90
+ }
83
91
  const source = context.query(type.typeClass) as EntityQuery<any>;
84
- const { target , textQuery } = this.compiler.compileToSql(source, `(p) => ${iterator.filter}` as any);
92
+ const { textQuery } = this.compiler.compileToSql(source, `(p) => ${iterator.filter}` as any);
85
93
  const r = new RegExp(source.selectStatement.sourceParameter.name + "\\.", "ig");
86
94
  iterator.filter = textQuery.join("").replace(r, "") as any;
87
95
  await this.migrateCheckConstraint(context, iterator, type);
@@ -121,6 +129,9 @@ export default abstract class Migrations {
121
129
  // foreignKeyConstraint.refColumns.push(relatedEntity.getProperty(iterator.name).field);
122
130
  // }
123
131
 
132
+ if(schema.foreignKeys.has(foreignKeyConstraint.name)) {
133
+ continue;
134
+ }
124
135
  postMigration.push(() => this.migrateForeignKey(context, foreignKeyConstraint));
125
136
  }
126
137
  }
@@ -174,6 +185,13 @@ export default abstract class Migrations {
174
185
 
175
186
  index = { ... index };
176
187
 
188
+ const schema = await this.getSchema(type);
189
+
190
+ if (schema.indexes.has(index.name)) {
191
+ return;
192
+ }
193
+
194
+
177
195
  for (const column of index.columns) {
178
196
  const c = type.getProperty(column.name);
179
197
  if (c.field) {
@@ -193,14 +211,67 @@ export default abstract class Migrations {
193
211
 
194
212
  }
195
213
 
196
- abstract migrateIndex(context: EntityContext, index: IIndex, type: EntityType);
214
+ async migrateTable(context: EntityContext, type: EntityType) {
215
+
216
+ const schema = await this.getSchema(type);
217
+
218
+ // create table if not exists...
219
+ const nonKeyColumns = type.nonKeys;
220
+ const keys = type.keys;
221
+
222
+ if (!schema.tables.has(type.name)) {
223
+ await this.createTable(type, keys);
224
+ }
225
+
226
+ await this.createColumns(type, nonKeyColumns);
227
+
228
+ }
197
229
 
198
- abstract migrateTable(context: EntityContext, type: EntityType): Promise<any>;
230
+ async createColumns(type: EntityType, nonKeyColumns: IColumn[]) {
231
+ const name = type.schema
232
+ ? type.schema + "." + type.name
233
+ : type.name;
234
+
235
+ if (nonKeyColumns.length > 1) {
236
+ nonKeyColumns.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
237
+ }
238
+
239
+ const schema = await this.getSchema(type);
240
+
241
+ const table = schema.tables.get(type.name);
242
+
243
+ for (const iterator of nonKeyColumns) {
244
+ if (table?.has(iterator.columnName)) {
245
+ continue;
246
+ }
247
+ await this.createColumn(type, iterator);
248
+ }
249
+
250
+ }
251
+
252
+ abstract createTable(type: EntityType, keys: IColumn[]);
253
+
254
+ abstract createColumn(type: EntityType, column: IColumn);
255
+
256
+ abstract migrateIndex(context: EntityContext, index: IIndex, type: EntityType);
199
257
 
200
258
  abstract migrateForeignKey(context: EntityContext, constraint: IForeignKeyConstraint);
201
259
 
202
260
  abstract migrateCheckConstraint(context: EntityContext, checkConstraint: ICheckConstraint, type: EntityType);
203
261
 
262
+ public async getSchema(type: EntityType): Promise<ExistingSchema> {
263
+ const schema = type.schema || "__ default + __ schema ";
264
+ let s = this.schemaCache.get(schema);
265
+ if (s) {
266
+ return s;
267
+ }
268
+ s = await this.getExistingSchema(type);
269
+ this.schemaCache.set(schema, s);
270
+ return s;
271
+ }
272
+
273
+ protected abstract getExistingSchema(type: EntityType): Promise<ExistingSchema>;
274
+
204
275
  protected executeQuery(command: IQuery, signal?: AbortSignal): Promise<IQueryResult> {
205
276
  const text = typeof command === "string" ? command : command.text;
206
277
  this.logger?.log(text);
@@ -4,9 +4,9 @@ import { IColumn } from "../../decorators/IColumn.js";
4
4
  import { IForeignKeyConstraint } from "../../decorators/IForeignKeyConstraint.js";
5
5
  import { IIndex } from "../../decorators/IIndex.js";
6
6
  import { BaseConnection, BaseDriver } from "../../drivers/base/BaseDriver.js";
7
+ import ExistingSchema from "../../drivers/base/ExistingSchema.js";
7
8
  import EntityType from "../../entity-query/EntityType.js";
8
9
  import type EntityContext from "../../model/EntityContext.js";
9
- import ExistingSchema from "../ExistingSchema.js";
10
10
  import PostgresMigrations from "./PostgresMigrations.js";
11
11
 
12
12
  export default class PostgresAutomaticMigrations extends PostgresMigrations {
@@ -20,21 +20,6 @@ export default class PostgresAutomaticMigrations extends PostgresMigrations {
20
20
  )`);
21
21
  }
22
22
 
23
- async migrateTable(context: EntityContext, type: EntityType) {
24
-
25
-
26
- // create table if not exists...
27
- const nonKeyColumns = type.nonKeys;
28
- const keys = type.keys;
29
-
30
- const driver = context.connection;
31
-
32
- await this.createTable(driver, type, keys);
33
-
34
- await this.createColumns(driver, type, nonKeyColumns);
35
-
36
- }
37
-
38
23
  async createIndexForForeignKeys(context: EntityContext, type: EntityType, fkColumns: IColumn[]) {
39
24
  for (const iterator of fkColumns) {
40
25
  const filter = iterator.nullable
@@ -45,56 +30,39 @@ export default class PostgresAutomaticMigrations extends PostgresMigrations {
45
30
  columns: [{ name: iterator.columnName, descending: iterator.indexOrder !== "ascending"}],
46
31
  filter
47
32
  };
48
- await this.migrateIndex(context, indexDef, type);
33
+ await this.migrateIndexInternal(context, indexDef, type);
49
34
  }
50
35
  }
51
36
 
52
- async createColumns(driver: BaseConnection, type: EntityType, nonKeyColumns: IColumn[]) {
37
+ async createColumn(type: EntityType, iterator: IColumn) {
53
38
 
54
39
  const name = type.schema
55
- ? type.schema + "." + type.name
56
- : type.name;
57
-
58
- if (nonKeyColumns.length > 1) {
59
- nonKeyColumns.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
60
- }
40
+ ? type.schema + "." + type.name
41
+ : type.name;
61
42
 
62
- const columns = await ExistingSchema.getSchema(driver, type.schema || "public", type.name, true);
43
+ const { quotedColumnName } = iterator;
63
44
 
64
- const columnSet = new Set(columns.map((x) => x.name));
65
45
 
66
- for (const iterator of nonKeyColumns) {
67
- const { columnName } = iterator;
68
- if (columnSet.has(columnName)) {
69
- continue;
70
- }
71
- let def = `ALTER TABLE ${name} ADD COLUMN IF NOT EXISTS ${columnName} `;
72
- def += this.getColumnDefinition(iterator);
46
+ let def = `ALTER TABLE ${name} ADD COLUMN IF NOT EXISTS ${quotedColumnName} `;
47
+ def += this.getColumnDefinition(iterator);
73
48
 
74
- if (iterator.nullable !== true) {
75
- def += " NOT NULL ";
76
- }
77
-
78
- if (iterator.generated === "computed") {
79
- def += ` GENERATED ALWAYS AS (${iterator.computed}) ${iterator.stored ? "STORED" : ""} \r\n\t`;
80
- }
81
-
82
- if (typeof iterator.default === "string") {
83
- def += " DEFAULT " + iterator.default;
84
- }
49
+ if (iterator.nullable !== true) {
50
+ def += " NOT NULL ";
51
+ }
85
52
 
86
- await this.executeQuery(def + ";");
53
+ if (iterator.generated === "computed") {
54
+ def += ` GENERATED ALWAYS AS (${iterator.computed}) ${iterator.stored ? "STORED" : ""} \r\n\t`;
87
55
  }
88
56
 
89
- }
57
+ if (typeof iterator.default === "string") {
58
+ def += " DEFAULT " + iterator.default;
59
+ }
90
60
 
91
- async createTable(driver: BaseConnection, type: EntityType, keys: IColumn[]) {
61
+ await this.executeQuery(def + ";");
92
62
 
93
- const columns = await ExistingSchema.getSchema(driver, type.schema || "public", type.name, true);
63
+ }
94
64
 
95
- if (columns.length) {
96
- return;
97
- }
65
+ async createTable(type: EntityType, keys: IColumn[]) {
98
66
 
99
67
  const name = type.schema
100
68
  ? type.schema + "." + type.name
@@ -132,10 +100,10 @@ export default class PostgresAutomaticMigrations extends PostgresMigrations {
132
100
  }
133
101
 
134
102
  async migrateIndex(context: EntityContext, index: IIndex, type: EntityType) {
135
- const driver = context.connection;
103
+
136
104
  const name = type.schema
137
- ? type.schema + "." + type.name
138
- : type.name;
105
+ ? type.schema + "." + type.name
106
+ : type.name;
139
107
  const indexName = index.name;
140
108
  const columns = [];
141
109
  for (const column of index.columns) {
@@ -1,8 +1,86 @@
1
1
  import { IColumn } from "../../decorators/IColumn.js";
2
+ import ExistingSchema from "../../drivers/base/ExistingSchema.js";
3
+ import EntityType from "../../entity-query/EntityType.js";
2
4
  import Migrations from "../Migrations.js";
3
5
 
4
6
  export default abstract class PostgresMigrations extends Migrations {
5
7
 
8
+ async getExistingSchema(type: EntityType) {
9
+
10
+ const schema = type.schema || "public";
11
+ const values = [schema];
12
+
13
+ let text = `
14
+ select
15
+ column_name as "name",
16
+ case data_type
17
+ when 'bigint' then 'BigInt'
18
+ when 'boolean' then 'Boolean'
19
+ when 'timestamp' then 'DateTime'
20
+ when 'timestamp with time zone' then 'DateTime'
21
+ when 'timestamp without time zone' then 'DateTime'
22
+ when 'integer' then 'Int'
23
+ when 'real' then 'Double'
24
+ when 'numeric' then 'Decimal'
25
+ else 'Char' end as "dataType",
26
+ case
27
+ when is_nullable = 'YES' then true
28
+ else false end as "nullable",
29
+ character_maximum_length as "length",
30
+ case
31
+ when is_identity = 'YES' then 'identity'
32
+ else null end as "identity",
33
+ case
34
+ when is_generated = 'YES' then '() => 1'
35
+ else null end as "computed",
36
+ table_name as "ownerName",
37
+ 'table' as "ownerType"
38
+ from information_schema.columns
39
+ where table_schema = $1`;
40
+
41
+ let r = await this.executeQuery({ text, values});
42
+ const columns = r.rows;
43
+
44
+ text = `
45
+ SELECT
46
+ tc.constraint_name as "name"
47
+ FROM information_schema.table_constraints AS tc
48
+ JOIN information_schema.key_column_usage AS kcu
49
+ ON tc.constraint_name = kcu.constraint_name
50
+ AND tc.table_schema = kcu.table_schema
51
+ JOIN information_schema.constraint_column_usage AS ccu
52
+ ON ccu.constraint_name = tc.constraint_name
53
+ WHERE
54
+ tc.constraint_type = 'FOREIGN KEY'
55
+ AND tc.table_schema = $1
56
+ `;
57
+ r = await this.executeQuery({ text, values});
58
+ const foreignKeys = r.rows;
59
+
60
+ text = `
61
+ SELECT indexname as "name" FROM pg_indexes where schemaName=$1`;
62
+ r = await this.executeQuery({ text, values });
63
+ const indexes = r.rows;
64
+
65
+ text = `
66
+ SELECT
67
+ tc.constraint_name as "name"
68
+ FROM information_schema.table_constraints AS tc
69
+ JOIN information_schema.key_column_usage AS kcu
70
+ ON tc.constraint_name = kcu.constraint_name
71
+ AND tc.table_schema = kcu.table_schema
72
+ JOIN information_schema.constraint_column_usage AS ccu
73
+ ON ccu.constraint_name = tc.constraint_name
74
+ WHERE
75
+ tc.constraint_type <> 'FOREIGN KEY'
76
+ AND tc.table_schema = $1`;
77
+
78
+ r = await this.executeQuery({ text, values });
79
+ const constraints = r.rows;
80
+
81
+ return new ExistingSchema(false, { columns, foreignKeys, indexes, constraints });
82
+ }
83
+
6
84
  protected getColumnDefinition(iterator: IColumn) {
7
85
  if (iterator.dataType === "Decimal") {
8
86
  if (iterator.precision && iterator.scale) {
@@ -4,10 +4,10 @@ import { IColumn } from "../../decorators/IColumn.js";
4
4
  import { IForeignKeyConstraint } from "../../decorators/IForeignKeyConstraint.js";
5
5
  import { IIndex } from "../../decorators/IIndex.js";
6
6
  import { BaseConnection } from "../../drivers/base/BaseDriver.js";
7
+ import ExistingSchema from "../../drivers/base/ExistingSchema.js";
7
8
  import { SqlServerLiteral } from "../../drivers/sql-server/SqlServerLiteral.js";
8
9
  import EntityType from "../../entity-query/EntityType.js";
9
10
  import type EntityContext from "../../model/EntityContext.js";
10
- import ExistingSchema from "../ExistingSchema.js";
11
11
  import SqlServerMigrations from "./SqlServerMigrations.js";
12
12
 
13
13
  export default class SqlServerAutomaticMigrations extends SqlServerMigrations {
@@ -23,20 +23,6 @@ export default class SqlServerAutomaticMigrations extends SqlServerMigrations {
23
23
  END`);
24
24
  }
25
25
 
26
- async migrateTable(context: EntityContext, type: EntityType) {
27
-
28
-
29
- // create table if not exists...
30
- const nonKeyColumns = type.nonKeys;
31
- const keys = type.keys;
32
-
33
- const driver = context.connection;
34
-
35
- await this.createTable(driver, type, keys);
36
-
37
- await this.createColumns(driver, type, nonKeyColumns);
38
-
39
- }
40
26
 
41
27
  async createIndexForForeignKeys(context: EntityContext, type: EntityType, fkColumns: IColumn[]) {
42
28
  for (const iterator of fkColumns) {
@@ -48,61 +34,43 @@ export default class SqlServerAutomaticMigrations extends SqlServerMigrations {
48
34
  columns: [{ name: iterator.quotedColumnName, descending: iterator.indexOrder !== "ascending"}],
49
35
  filter
50
36
  };
51
- await this.migrateIndex(context, indexDef, type);
37
+ await this.migrateIndexInternal(context, indexDef, type);
52
38
  }
53
39
  }
54
40
 
55
- async createColumns(driver: BaseConnection, type: EntityType, nonKeyColumns: IColumn[]) {
41
+ async createColumn(type: EntityType, iterator: IColumn) {
56
42
 
57
- const name = type.schema
58
- ? type.schema + "." + type.name
59
- : type.name;
60
-
61
- if (nonKeyColumns.length > 1) {
62
- nonKeyColumns.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
63
- }
43
+ const { quotedColumnName } = iterator;
64
44
 
65
- const columns = await ExistingSchema.getSchema(driver, type.schema || "dbo", type.name);
66
-
67
- const columnSet = new Set(columns.map((x) => x.name.toLowerCase()));
68
-
69
- for (const iterator of nonKeyColumns) {
70
- const { quotedColumnName, columnName } = iterator;
71
- if (columnSet.has(columnName.toLowerCase())) {
72
- continue;
73
- }
74
- let def = `ALTER TABLE ${name} ADD ${quotedColumnName} `;
45
+ const name = type.schema
46
+ ? type.schema + "." + type.name
47
+ : type.name;
75
48
 
76
- if (iterator.computed) {
77
- def += ` AS ${iterator.computed} ${iterator.stored ? "PERSISTED" : ""}`;
78
- await this.executeQuery(def + ";");
79
- continue;
80
- }
49
+ let def = `ALTER TABLE ${name} ADD ${quotedColumnName} `;
81
50
 
82
- def += this.getColumnDefinition(iterator);
83
- if (iterator.nullable === true) {
84
- def += " NULL ";
85
- } else {
86
- def += " NOT NULL ";
87
- }
88
- if (iterator.computed) {
89
- def += ` AS ${iterator.computed} ${iterator.stored ? "PERSISTED" : ""}`;
90
- }
91
- if (typeof iterator.default === "string") {
92
- def += " DEFAULT " + iterator.default;
93
- }
51
+ if (iterator.computed) {
52
+ def += ` AS ${iterator.computed} ${iterator.stored ? "PERSISTED" : ""}`;
94
53
  await this.executeQuery(def + ";");
54
+ return;
95
55
  }
96
56
 
97
- }
98
-
99
- async createTable(driver: BaseConnection, type: EntityType, keys: IColumn[]) {
57
+ def += this.getColumnDefinition(iterator);
58
+ if (iterator.nullable === true) {
59
+ def += " NULL ";
60
+ } else {
61
+ def += " NOT NULL ";
62
+ }
63
+ if (iterator.computed) {
64
+ def += ` AS ${iterator.computed} ${iterator.stored ? "PERSISTED" : ""}`;
65
+ }
66
+ if (typeof iterator.default === "string") {
67
+ def += " DEFAULT " + iterator.default;
68
+ }
69
+ await this.executeQuery(def + ";");
100
70
 
101
- const columns = await ExistingSchema.getSchema(driver, type.schema || "public", type.name);
71
+ }
102
72
 
103
- if (columns.length) {
104
- return;
105
- }
73
+ async createTable(type: EntityType, keys: IColumn[]) {
106
74
 
107
75
  const name = type.schema
108
76
  ? type.schema + "." + type.name
@@ -138,6 +106,7 @@ export default class SqlServerAutomaticMigrations extends SqlServerMigrations {
138
106
  }
139
107
 
140
108
  async migrateIndex(context: EntityContext, index: IIndex, type: EntityType) {
109
+
141
110
  const driver = context.connection;
142
111
  const name = type.schema
143
112
  ? type.schema + "." + type.name