@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.
- package/dist/common/CIMap.d.ts +16 -0
- package/dist/common/CIMap.d.ts.map +1 -0
- package/dist/common/CIMap.js +43 -0
- package/dist/common/CIMap.js.map +1 -0
- package/dist/common/IColumnSchema.d.ts +9 -0
- package/dist/common/IColumnSchema.d.ts.map +1 -1
- package/dist/drivers/base/BaseDriver.d.ts +0 -2
- package/dist/drivers/base/BaseDriver.d.ts.map +1 -1
- package/dist/drivers/base/BaseDriver.js.map +1 -1
- package/dist/drivers/base/ExistingSchema.d.ts +14 -0
- package/dist/drivers/base/ExistingSchema.d.ts.map +1 -0
- package/dist/drivers/base/ExistingSchema.js +34 -0
- package/dist/drivers/base/ExistingSchema.js.map +1 -0
- package/dist/drivers/postgres/PostgreSqlDriver.d.ts.map +1 -1
- package/dist/drivers/postgres/PostgreSqlDriver.js +0 -31
- package/dist/drivers/postgres/PostgreSqlDriver.js.map +1 -1
- package/dist/drivers/sql-server/SqlServerDriver.d.ts +0 -2
- package/dist/drivers/sql-server/SqlServerDriver.d.ts.map +1 -1
- package/dist/drivers/sql-server/SqlServerDriver.js +0 -41
- package/dist/drivers/sql-server/SqlServerDriver.js.map +1 -1
- package/dist/migrations/Migrations.d.ts +9 -2
- package/dist/migrations/Migrations.d.ts.map +1 -1
- package/dist/migrations/Migrations.js +49 -1
- package/dist/migrations/Migrations.js.map +1 -1
- package/dist/migrations/postgres/PostgresAutomaticMigrations.d.ts +2 -4
- package/dist/migrations/postgres/PostgresAutomaticMigrations.d.ts.map +1 -1
- package/dist/migrations/postgres/PostgresAutomaticMigrations.js +15 -39
- package/dist/migrations/postgres/PostgresAutomaticMigrations.js.map +1 -1
- package/dist/migrations/postgres/PostgresMigrations.d.ts +3 -0
- package/dist/migrations/postgres/PostgresMigrations.d.ts.map +1 -1
- package/dist/migrations/postgres/PostgresMigrations.js +68 -0
- package/dist/migrations/postgres/PostgresMigrations.js.map +1 -1
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.d.ts +2 -4
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.d.ts.map +1 -1
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js +22 -45
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js.map +1 -1
- package/dist/migrations/sql-server/SqlServerMigrations.d.ts +5 -0
- package/dist/migrations/sql-server/SqlServerMigrations.d.ts.map +1 -1
- package/dist/migrations/sql-server/SqlServerMigrations.js +77 -0
- package/dist/migrations/sql-server/SqlServerMigrations.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/common/CIMap.ts +50 -0
- package/src/common/IColumnSchema.ts +12 -0
- package/src/drivers/base/BaseDriver.ts +1 -3
- package/src/drivers/base/ExistingSchema.ts +60 -0
- package/src/drivers/postgres/PostgreSqlDriver.ts +1 -32
- package/src/drivers/sql-server/SqlServerDriver.ts +1 -42
- package/src/migrations/Migrations.ts +76 -5
- package/src/migrations/postgres/PostgresAutomaticMigrations.ts +22 -54
- package/src/migrations/postgres/PostgresMigrations.ts +78 -0
- package/src/migrations/sql-server/SqlServerAutomaticMigrations.ts +27 -58
- package/src/migrations/sql-server/SqlServerMigrations.ts +86 -0
- package/dist/migrations/ExistingSchema.d.ts +0 -9
- package/dist/migrations/ExistingSchema.d.ts.map +0 -1
- package/dist/migrations/ExistingSchema.js +0 -31
- package/dist/migrations/ExistingSchema.js.map +0 -1
- 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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
33
|
+
await this.migrateIndexInternal(context, indexDef, type);
|
|
49
34
|
}
|
|
50
35
|
}
|
|
51
36
|
|
|
52
|
-
async
|
|
37
|
+
async createColumn(type: EntityType, iterator: IColumn) {
|
|
53
38
|
|
|
54
39
|
const name = type.schema
|
|
55
|
-
|
|
56
|
-
|
|
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
|
|
43
|
+
const { quotedColumnName } = iterator;
|
|
63
44
|
|
|
64
|
-
const columnSet = new Set(columns.map((x) => x.name));
|
|
65
45
|
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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
|
-
|
|
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
|
-
|
|
61
|
+
await this.executeQuery(def + ";");
|
|
92
62
|
|
|
93
|
-
|
|
63
|
+
}
|
|
94
64
|
|
|
95
|
-
|
|
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
|
-
|
|
103
|
+
|
|
136
104
|
const name = type.schema
|
|
137
|
-
|
|
138
|
-
|
|
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.
|
|
37
|
+
await this.migrateIndexInternal(context, indexDef, type);
|
|
52
38
|
}
|
|
53
39
|
}
|
|
54
40
|
|
|
55
|
-
async
|
|
41
|
+
async createColumn(type: EntityType, iterator: IColumn) {
|
|
56
42
|
|
|
57
|
-
const
|
|
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
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
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
|
-
|
|
83
|
-
|
|
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
|
-
|
|
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
|
-
|
|
71
|
+
}
|
|
102
72
|
|
|
103
|
-
|
|
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
|