@mikro-orm/sql 7.0.0-dev.97 → 7.0.0-dev.98
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.d.ts +56 -0
- package/AbstractSqlConnection.js +232 -0
- package/AbstractSqlDriver.d.ts +94 -0
- package/AbstractSqlDriver.js +1387 -0
- package/AbstractSqlPlatform.d.ts +38 -0
- package/AbstractSqlPlatform.js +104 -0
- package/LICENSE +21 -0
- package/PivotCollectionPersister.d.ts +22 -0
- package/PivotCollectionPersister.js +159 -0
- package/README.md +390 -0
- package/SqlEntityManager.d.ts +33 -0
- package/SqlEntityManager.js +44 -0
- package/SqlEntityRepository.d.ts +19 -0
- package/SqlEntityRepository.js +26 -0
- package/dialects/index.d.ts +4 -0
- package/dialects/index.js +4 -0
- package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +14 -0
- package/dialects/mssql/MsSqlNativeQueryBuilder.js +200 -0
- package/dialects/mssql/index.d.ts +1 -0
- package/dialects/mssql/index.js +1 -0
- package/dialects/mysql/MySqlExceptionConverter.d.ts +9 -0
- package/dialects/mysql/MySqlExceptionConverter.js +80 -0
- package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +7 -0
- package/dialects/mysql/MySqlNativeQueryBuilder.js +77 -0
- package/dialects/mysql/MySqlPlatform.d.ts +45 -0
- package/dialects/mysql/MySqlPlatform.js +116 -0
- package/dialects/mysql/MySqlSchemaHelper.d.ts +36 -0
- package/dialects/mysql/MySqlSchemaHelper.js +269 -0
- package/dialects/mysql/index.d.ts +4 -0
- package/dialects/mysql/index.js +4 -0
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +5 -0
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +8 -0
- package/dialects/postgresql/PostgreSqlTableCompiler.d.ts +1 -0
- package/dialects/postgresql/PostgreSqlTableCompiler.js +1 -0
- package/dialects/postgresql/index.d.ts +1 -0
- package/dialects/postgresql/index.js +1 -0
- package/dialects/sqlite/BaseSqliteConnection.d.ts +6 -0
- package/dialects/sqlite/BaseSqliteConnection.js +8 -0
- package/dialects/sqlite/BaseSqlitePlatform.d.ts +70 -0
- package/dialects/sqlite/BaseSqlitePlatform.js +104 -0
- package/dialects/sqlite/SqliteExceptionConverter.d.ts +9 -0
- package/dialects/sqlite/SqliteExceptionConverter.js +54 -0
- package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +6 -0
- package/dialects/sqlite/SqliteNativeQueryBuilder.js +11 -0
- package/dialects/sqlite/SqliteSchemaHelper.d.ts +38 -0
- package/dialects/sqlite/SqliteSchemaHelper.js +379 -0
- package/dialects/sqlite/index.d.ts +5 -0
- package/dialects/sqlite/index.js +5 -0
- package/index.d.ts +19 -0
- package/index.js +19 -0
- package/package.json +3 -3
- package/plugin/index.d.ts +53 -0
- package/plugin/index.js +42 -0
- package/plugin/transformer.d.ts +115 -0
- package/plugin/transformer.js +883 -0
- package/query/ArrayCriteriaNode.d.ts +11 -0
- package/query/ArrayCriteriaNode.js +24 -0
- package/query/CriteriaNode.d.ts +29 -0
- package/query/CriteriaNode.js +121 -0
- package/query/CriteriaNodeFactory.d.ts +12 -0
- package/query/CriteriaNodeFactory.js +90 -0
- package/query/NativeQueryBuilder.d.ts +108 -0
- package/query/NativeQueryBuilder.js +425 -0
- package/query/ObjectCriteriaNode.d.ts +19 -0
- package/query/ObjectCriteriaNode.js +249 -0
- package/query/QueryBuilder.d.ts +389 -0
- package/query/QueryBuilder.js +1558 -0
- package/query/QueryBuilderHelper.d.ts +73 -0
- package/query/QueryBuilderHelper.js +756 -0
- package/query/ScalarCriteriaNode.d.ts +10 -0
- package/query/ScalarCriteriaNode.js +49 -0
- package/query/enums.d.ts +18 -0
- package/query/enums.js +20 -0
- package/query/index.d.ts +10 -0
- package/query/index.js +10 -0
- package/query/raw.d.ts +59 -0
- package/query/raw.js +68 -0
- package/schema/DatabaseSchema.d.ts +45 -0
- package/schema/DatabaseSchema.js +185 -0
- package/schema/DatabaseTable.d.ts +68 -0
- package/schema/DatabaseTable.js +793 -0
- package/schema/SchemaComparator.d.ts +58 -0
- package/schema/SchemaComparator.js +577 -0
- package/schema/SchemaHelper.d.ts +76 -0
- package/schema/SchemaHelper.js +545 -0
- package/schema/SqlSchemaGenerator.d.ts +65 -0
- package/schema/SqlSchemaGenerator.js +375 -0
- package/schema/index.d.ts +5 -0
- package/schema/index.js +5 -0
- package/typings.d.ts +272 -0
- package/typings.js +1 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CriteriaNode } from './CriteriaNode.js';
|
|
2
|
+
import type { ICriteriaNodeProcessOptions, IQueryBuilder } from '../typings.js';
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export declare class ScalarCriteriaNode<T extends object> extends CriteriaNode<T> {
|
|
7
|
+
process(qb: IQueryBuilder<T>, options?: ICriteriaNodeProcessOptions): any;
|
|
8
|
+
willAutoJoin(qb: IQueryBuilder<T>, alias?: string, options?: ICriteriaNodeProcessOptions): boolean;
|
|
9
|
+
private shouldJoin;
|
|
10
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ARRAY_OPERATORS, ReferenceKind } from '@mikro-orm/core';
|
|
2
|
+
import { CriteriaNode } from './CriteriaNode.js';
|
|
3
|
+
import { JoinType, QueryType } from './enums.js';
|
|
4
|
+
import { QueryBuilder } from './QueryBuilder.js';
|
|
5
|
+
/**
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export class ScalarCriteriaNode extends CriteriaNode {
|
|
9
|
+
process(qb, options) {
|
|
10
|
+
const matchPopulateJoins = options?.matchPopulateJoins || (this.prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(this.prop.kind));
|
|
11
|
+
const nestedAlias = qb.getAliasForJoinPath(this.getPath(), { ...options, matchPopulateJoins });
|
|
12
|
+
if (this.shouldJoin(qb, nestedAlias)) {
|
|
13
|
+
const path = this.getPath();
|
|
14
|
+
const parentPath = this.parent.getPath(); // the parent is always there, otherwise `shouldJoin` would return `false`
|
|
15
|
+
const nestedAlias = qb.getAliasForJoinPath(path) || qb.getNextAlias(this.prop?.pivotTable ?? this.entityName);
|
|
16
|
+
const field = this.aliased(this.prop.name, options?.alias);
|
|
17
|
+
const type = this.prop.kind === ReferenceKind.MANY_TO_MANY ? JoinType.pivotJoin : JoinType.leftJoin;
|
|
18
|
+
qb.join(field, nestedAlias, undefined, type, path);
|
|
19
|
+
// select the owner as virtual property when joining from 1:1 inverse side, but only if the parent is root entity
|
|
20
|
+
if (this.prop.kind === ReferenceKind.ONE_TO_ONE && !parentPath.includes('.') && !qb._fields?.includes(field)) {
|
|
21
|
+
qb.addSelect(field);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (this.payload instanceof QueryBuilder) {
|
|
25
|
+
return this.payload.getNativeQuery().toRaw();
|
|
26
|
+
}
|
|
27
|
+
if (this.payload && typeof this.payload === 'object') {
|
|
28
|
+
const keys = Object.keys(this.payload).filter(key => ARRAY_OPERATORS.includes(key) && Array.isArray(this.payload[key]));
|
|
29
|
+
for (const key of keys) {
|
|
30
|
+
this.payload[key] = JSON.stringify(this.payload[key]);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return this.payload;
|
|
34
|
+
}
|
|
35
|
+
willAutoJoin(qb, alias, options) {
|
|
36
|
+
return this.shouldJoin(qb, alias);
|
|
37
|
+
}
|
|
38
|
+
shouldJoin(qb, nestedAlias) {
|
|
39
|
+
if (!this.parent || !this.prop || (nestedAlias && [QueryType.SELECT, QueryType.COUNT].includes(qb.type ?? QueryType.SELECT))) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
switch (this.prop.kind) {
|
|
43
|
+
case ReferenceKind.ONE_TO_MANY: return true;
|
|
44
|
+
case ReferenceKind.MANY_TO_MANY: return true;
|
|
45
|
+
case ReferenceKind.ONE_TO_ONE: return !this.prop.owner;
|
|
46
|
+
default: return false; // SCALAR, MANY_TO_ONE
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
package/query/enums.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare enum QueryType {
|
|
2
|
+
TRUNCATE = "TRUNCATE",
|
|
3
|
+
SELECT = "SELECT",
|
|
4
|
+
COUNT = "COUNT",
|
|
5
|
+
INSERT = "INSERT",
|
|
6
|
+
UPDATE = "UPDATE",
|
|
7
|
+
DELETE = "DELETE",
|
|
8
|
+
UPSERT = "UPSERT"
|
|
9
|
+
}
|
|
10
|
+
export declare enum JoinType {
|
|
11
|
+
leftJoin = "left join",
|
|
12
|
+
innerJoin = "inner join",
|
|
13
|
+
nestedLeftJoin = "nested left join",
|
|
14
|
+
nestedInnerJoin = "nested inner join",
|
|
15
|
+
pivotJoin = "pivot join",
|
|
16
|
+
innerJoinLateral = "inner join lateral",
|
|
17
|
+
leftJoinLateral = "left join lateral"
|
|
18
|
+
}
|
package/query/enums.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export var QueryType;
|
|
2
|
+
(function (QueryType) {
|
|
3
|
+
QueryType["TRUNCATE"] = "TRUNCATE";
|
|
4
|
+
QueryType["SELECT"] = "SELECT";
|
|
5
|
+
QueryType["COUNT"] = "COUNT";
|
|
6
|
+
QueryType["INSERT"] = "INSERT";
|
|
7
|
+
QueryType["UPDATE"] = "UPDATE";
|
|
8
|
+
QueryType["DELETE"] = "DELETE";
|
|
9
|
+
QueryType["UPSERT"] = "UPSERT";
|
|
10
|
+
})(QueryType || (QueryType = {}));
|
|
11
|
+
export var JoinType;
|
|
12
|
+
(function (JoinType) {
|
|
13
|
+
JoinType["leftJoin"] = "left join";
|
|
14
|
+
JoinType["innerJoin"] = "inner join";
|
|
15
|
+
JoinType["nestedLeftJoin"] = "nested left join";
|
|
16
|
+
JoinType["nestedInnerJoin"] = "nested inner join";
|
|
17
|
+
JoinType["pivotJoin"] = "pivot join";
|
|
18
|
+
JoinType["innerJoinLateral"] = "inner join lateral";
|
|
19
|
+
JoinType["leftJoinLateral"] = "left join lateral";
|
|
20
|
+
})(JoinType || (JoinType = {}));
|
package/query/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './enums.js';
|
|
2
|
+
export * from './QueryBuilderHelper.js';
|
|
3
|
+
export * from './QueryBuilder.js';
|
|
4
|
+
export * from './CriteriaNode.js';
|
|
5
|
+
export * from './ArrayCriteriaNode.js';
|
|
6
|
+
export * from './ObjectCriteriaNode.js';
|
|
7
|
+
export * from './ScalarCriteriaNode.js';
|
|
8
|
+
export * from './CriteriaNodeFactory.js';
|
|
9
|
+
export * from './NativeQueryBuilder.js';
|
|
10
|
+
export * from './raw.js';
|
package/query/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './enums.js';
|
|
2
|
+
export * from './QueryBuilderHelper.js';
|
|
3
|
+
export * from './QueryBuilder.js';
|
|
4
|
+
export * from './CriteriaNode.js';
|
|
5
|
+
export * from './ArrayCriteriaNode.js';
|
|
6
|
+
export * from './ObjectCriteriaNode.js';
|
|
7
|
+
export * from './ScalarCriteriaNode.js';
|
|
8
|
+
export * from './CriteriaNodeFactory.js';
|
|
9
|
+
export * from './NativeQueryBuilder.js';
|
|
10
|
+
export * from './raw.js';
|
package/query/raw.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type AnyString, type Dictionary, type EntityKey, type RawQueryFragment } from '@mikro-orm/core';
|
|
2
|
+
import type { SelectQueryBuilder } from 'kysely';
|
|
3
|
+
import { QueryBuilder } from './QueryBuilder.js';
|
|
4
|
+
/**
|
|
5
|
+
* Creates raw SQL query fragment that can be assigned to a property or part of a filter. This fragment is represented
|
|
6
|
+
* by `RawQueryFragment` class instance that can be serialized to a string, so it can be used both as an object value
|
|
7
|
+
* and key. When serialized, the fragment key gets cached and only such cached key will be recognized by the ORM.
|
|
8
|
+
* This adds a runtime safety to the raw query fragments.
|
|
9
|
+
*
|
|
10
|
+
* > **`raw()` helper is required since v6 to use a raw fragment in your query, both through EntityManager and QueryBuilder.**
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* // as a value
|
|
14
|
+
* await em.find(User, { time: raw('now()') });
|
|
15
|
+
*
|
|
16
|
+
* // as a key
|
|
17
|
+
* await em.find(User, { [raw('lower(name)')]: name.toLowerCase() });
|
|
18
|
+
*
|
|
19
|
+
* // value can be empty array
|
|
20
|
+
* await em.find(User, { [raw('(select 1 = 1)')]: [] });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* The `raw` helper supports several signatures, you can pass in a callback that receives the current property alias:
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* await em.find(User, { [raw(alias => `lower(${alias}.name)`)]: name.toLowerCase() });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* You can also use the `sql` tagged template function, which works the same, but supports only the simple string signature:
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* await em.find(User, { [sql`lower(name)`]: name.toLowerCase() });
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* When using inside filters, you might have to use a callback signature to create new raw instance for every filter usage.
|
|
36
|
+
*
|
|
37
|
+
* ```ts
|
|
38
|
+
* @Filter({ name: 'long', cond: () => ({ [raw('length(perex)')]: { $gt: 10000 } }) })
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* The `raw` helper can be used within indexes and uniques to write database-agnostic SQL expressions. In that case, you can use `'??'` to tag your database identifiers (table name, column names, index name, ...) inside your expression, and pass those identifiers as a second parameter to the `raw` helper. Internally, those will automatically be quoted according to the database in use:
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* // On postgres, will produce: create index "index custom_idx_on_name" on "library.author" ("country")
|
|
45
|
+
* // On mysql, will produce: create index `index custom_idx_on_name` on `library.author` (`country`)
|
|
46
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => raw(`create index ?? on ?? (??)`, ['custom_idx_on_name', table, columns.name]) })
|
|
47
|
+
* @Entity({ schema: 'library' })
|
|
48
|
+
* export class Author { ... }
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* You can also use the `quote` tag function to write database-agnostic SQL expressions. The end-result is the same as using the `raw` function regarding database identifiers quoting, only to have a more elegant expression syntax:
|
|
52
|
+
*
|
|
53
|
+
* ```ts
|
|
54
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => quote`create index ${'custom_idx_on_name'} on ${table} (${columns.name})` })
|
|
55
|
+
* @Entity({ schema: 'library' })
|
|
56
|
+
* export class Author { ... }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function raw<T extends object = any, R = any>(sql: SelectQueryBuilder<any, any, any> | QueryBuilder<T> | EntityKey<T> | EntityKey<T>[] | AnyString | ((alias: string) => string) | RawQueryFragment, params?: readonly unknown[] | Dictionary<unknown>): NoInfer<R>;
|
package/query/raw.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { raw as raw_, Utils } from '@mikro-orm/core';
|
|
2
|
+
import { QueryBuilder } from './QueryBuilder.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates raw SQL query fragment that can be assigned to a property or part of a filter. This fragment is represented
|
|
5
|
+
* by `RawQueryFragment` class instance that can be serialized to a string, so it can be used both as an object value
|
|
6
|
+
* and key. When serialized, the fragment key gets cached and only such cached key will be recognized by the ORM.
|
|
7
|
+
* This adds a runtime safety to the raw query fragments.
|
|
8
|
+
*
|
|
9
|
+
* > **`raw()` helper is required since v6 to use a raw fragment in your query, both through EntityManager and QueryBuilder.**
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* // as a value
|
|
13
|
+
* await em.find(User, { time: raw('now()') });
|
|
14
|
+
*
|
|
15
|
+
* // as a key
|
|
16
|
+
* await em.find(User, { [raw('lower(name)')]: name.toLowerCase() });
|
|
17
|
+
*
|
|
18
|
+
* // value can be empty array
|
|
19
|
+
* await em.find(User, { [raw('(select 1 = 1)')]: [] });
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* The `raw` helper supports several signatures, you can pass in a callback that receives the current property alias:
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* await em.find(User, { [raw(alias => `lower(${alias}.name)`)]: name.toLowerCase() });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* You can also use the `sql` tagged template function, which works the same, but supports only the simple string signature:
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* await em.find(User, { [sql`lower(name)`]: name.toLowerCase() });
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* When using inside filters, you might have to use a callback signature to create new raw instance for every filter usage.
|
|
35
|
+
*
|
|
36
|
+
* ```ts
|
|
37
|
+
* @Filter({ name: 'long', cond: () => ({ [raw('length(perex)')]: { $gt: 10000 } }) })
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* The `raw` helper can be used within indexes and uniques to write database-agnostic SQL expressions. In that case, you can use `'??'` to tag your database identifiers (table name, column names, index name, ...) inside your expression, and pass those identifiers as a second parameter to the `raw` helper. Internally, those will automatically be quoted according to the database in use:
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* // On postgres, will produce: create index "index custom_idx_on_name" on "library.author" ("country")
|
|
44
|
+
* // On mysql, will produce: create index `index custom_idx_on_name` on `library.author` (`country`)
|
|
45
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => raw(`create index ?? on ?? (??)`, ['custom_idx_on_name', table, columns.name]) })
|
|
46
|
+
* @Entity({ schema: 'library' })
|
|
47
|
+
* export class Author { ... }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* You can also use the `quote` tag function to write database-agnostic SQL expressions. The end-result is the same as using the `raw` function regarding database identifiers quoting, only to have a more elegant expression syntax:
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* @Index({ name: 'custom_idx_on_name', expression: (table, columns) => quote`create index ${'custom_idx_on_name'} on ${table} (${columns.name})` })
|
|
54
|
+
* @Entity({ schema: 'library' })
|
|
55
|
+
* export class Author { ... }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function raw(sql, params) {
|
|
59
|
+
if (Utils.isObject(sql) && 'compile' in sql) {
|
|
60
|
+
const query = sql.compile();
|
|
61
|
+
return raw_(query.sql, query.parameters);
|
|
62
|
+
}
|
|
63
|
+
if (sql instanceof QueryBuilder) {
|
|
64
|
+
const query = sql.toQuery();
|
|
65
|
+
return raw_(query.sql, query.params);
|
|
66
|
+
}
|
|
67
|
+
return raw_(sql, params);
|
|
68
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type Configuration, type Dictionary, type EntityMetadata } from '@mikro-orm/core';
|
|
2
|
+
import { DatabaseTable } from './DatabaseTable.js';
|
|
3
|
+
import type { AbstractSqlConnection } from '../AbstractSqlConnection.js';
|
|
4
|
+
import type { AbstractSqlPlatform } from '../AbstractSqlPlatform.js';
|
|
5
|
+
/**
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export declare class DatabaseSchema {
|
|
9
|
+
private readonly platform;
|
|
10
|
+
readonly name: string;
|
|
11
|
+
private tables;
|
|
12
|
+
private namespaces;
|
|
13
|
+
private nativeEnums;
|
|
14
|
+
constructor(platform: AbstractSqlPlatform, name: string);
|
|
15
|
+
addTable(name: string, schema: string | undefined | null, comment?: string): DatabaseTable;
|
|
16
|
+
getTables(): DatabaseTable[];
|
|
17
|
+
getTable(name: string): DatabaseTable | undefined;
|
|
18
|
+
hasTable(name: string): boolean;
|
|
19
|
+
setNativeEnums(nativeEnums: Dictionary<{
|
|
20
|
+
name: string;
|
|
21
|
+
schema?: string;
|
|
22
|
+
items: string[];
|
|
23
|
+
}>): void;
|
|
24
|
+
getNativeEnums(): Dictionary<{
|
|
25
|
+
name: string;
|
|
26
|
+
schema?: string;
|
|
27
|
+
items: string[];
|
|
28
|
+
}>;
|
|
29
|
+
getNativeEnum(name: string): {
|
|
30
|
+
name: string;
|
|
31
|
+
schema?: string;
|
|
32
|
+
items: string[];
|
|
33
|
+
};
|
|
34
|
+
hasNamespace(namespace: string): boolean;
|
|
35
|
+
hasNativeEnum(name: string): boolean;
|
|
36
|
+
getNamespaces(): string[];
|
|
37
|
+
static create(connection: AbstractSqlConnection, platform: AbstractSqlPlatform, config: Configuration, schemaName?: string, schemas?: string[], takeTables?: (string | RegExp)[], skipTables?: (string | RegExp)[]): Promise<DatabaseSchema>;
|
|
38
|
+
static fromMetadata(metadata: EntityMetadata[], platform: AbstractSqlPlatform, config: Configuration, schemaName?: string): DatabaseSchema;
|
|
39
|
+
private static getSchemaName;
|
|
40
|
+
private static matchName;
|
|
41
|
+
private static isTableNameAllowed;
|
|
42
|
+
private static shouldHaveColumn;
|
|
43
|
+
toJSON(): Dictionary;
|
|
44
|
+
prune(schema: string | undefined, wildcardSchemaTables: string[]): void;
|
|
45
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { ReferenceKind, RawQueryFragment, } from '@mikro-orm/core';
|
|
2
|
+
import { DatabaseTable } from './DatabaseTable.js';
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export class DatabaseSchema {
|
|
7
|
+
platform;
|
|
8
|
+
name;
|
|
9
|
+
tables = [];
|
|
10
|
+
namespaces = new Set();
|
|
11
|
+
nativeEnums = {}; // for postgres
|
|
12
|
+
constructor(platform, name) {
|
|
13
|
+
this.platform = platform;
|
|
14
|
+
this.name = name;
|
|
15
|
+
}
|
|
16
|
+
addTable(name, schema, comment) {
|
|
17
|
+
const namespaceName = schema ?? this.name;
|
|
18
|
+
const table = new DatabaseTable(this.platform, name, namespaceName);
|
|
19
|
+
table.nativeEnums = this.nativeEnums;
|
|
20
|
+
table.comment = comment;
|
|
21
|
+
this.tables.push(table);
|
|
22
|
+
if (namespaceName != null) {
|
|
23
|
+
this.namespaces.add(namespaceName);
|
|
24
|
+
}
|
|
25
|
+
return table;
|
|
26
|
+
}
|
|
27
|
+
getTables() {
|
|
28
|
+
return this.tables;
|
|
29
|
+
}
|
|
30
|
+
getTable(name) {
|
|
31
|
+
return this.tables.find(t => t.name === name || `${t.schema}.${t.name}` === name);
|
|
32
|
+
}
|
|
33
|
+
hasTable(name) {
|
|
34
|
+
return !!this.getTable(name);
|
|
35
|
+
}
|
|
36
|
+
setNativeEnums(nativeEnums) {
|
|
37
|
+
this.nativeEnums = nativeEnums;
|
|
38
|
+
for (const nativeEnum of Object.values(nativeEnums)) {
|
|
39
|
+
if (nativeEnum.schema && nativeEnum.schema !== '*') {
|
|
40
|
+
this.namespaces.add(nativeEnum.schema);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
getNativeEnums() {
|
|
45
|
+
return this.nativeEnums;
|
|
46
|
+
}
|
|
47
|
+
getNativeEnum(name) {
|
|
48
|
+
return this.nativeEnums[name];
|
|
49
|
+
}
|
|
50
|
+
hasNamespace(namespace) {
|
|
51
|
+
return this.namespaces.has(namespace);
|
|
52
|
+
}
|
|
53
|
+
hasNativeEnum(name) {
|
|
54
|
+
return name in this.nativeEnums;
|
|
55
|
+
}
|
|
56
|
+
getNamespaces() {
|
|
57
|
+
return [...this.namespaces];
|
|
58
|
+
}
|
|
59
|
+
static async create(connection, platform, config, schemaName, schemas, takeTables, skipTables) {
|
|
60
|
+
const schema = new DatabaseSchema(platform, schemaName ?? config.get('schema') ?? platform.getDefaultSchemaName());
|
|
61
|
+
const allTables = await connection.execute(platform.getSchemaHelper().getListTablesSQL());
|
|
62
|
+
const parts = config.get('migrations').tableName.split('.');
|
|
63
|
+
const migrationsTableName = parts[1] ?? parts[0];
|
|
64
|
+
const migrationsSchemaName = parts.length > 1 ? parts[0] : config.get('schema', platform.getDefaultSchemaName());
|
|
65
|
+
const tables = allTables.filter(t => this.isTableNameAllowed(t.table_name, takeTables, skipTables) && (t.table_name !== migrationsTableName || (t.schema_name && t.schema_name !== migrationsSchemaName)));
|
|
66
|
+
await platform.getSchemaHelper().loadInformationSchema(schema, connection, tables, schemas && schemas.length > 0 ? schemas : undefined);
|
|
67
|
+
return schema;
|
|
68
|
+
}
|
|
69
|
+
static fromMetadata(metadata, platform, config, schemaName) {
|
|
70
|
+
const schema = new DatabaseSchema(platform, schemaName ?? config.get('schema'));
|
|
71
|
+
const nativeEnums = {};
|
|
72
|
+
const skipColumns = config.get('schemaGenerator').skipColumns || {};
|
|
73
|
+
for (const meta of metadata) {
|
|
74
|
+
for (const prop of meta.props) {
|
|
75
|
+
if (prop.nativeEnumName) {
|
|
76
|
+
let key = prop.nativeEnumName;
|
|
77
|
+
let enumName = prop.nativeEnumName;
|
|
78
|
+
let enumSchema = meta.schema ?? schema.name;
|
|
79
|
+
if (key.includes('.')) {
|
|
80
|
+
const [explicitSchema, ...parts] = prop.nativeEnumName.split('.');
|
|
81
|
+
enumName = parts.join('.');
|
|
82
|
+
key = enumName;
|
|
83
|
+
enumSchema = explicitSchema;
|
|
84
|
+
}
|
|
85
|
+
if (enumSchema && enumSchema !== '*' && enumSchema !== platform.getDefaultSchemaName()) {
|
|
86
|
+
key = enumSchema + '.' + key;
|
|
87
|
+
}
|
|
88
|
+
nativeEnums[key] = {
|
|
89
|
+
name: enumName,
|
|
90
|
+
schema: enumSchema,
|
|
91
|
+
items: prop.items?.map(val => '' + val) ?? [],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
schema.setNativeEnums(nativeEnums);
|
|
97
|
+
for (const meta of metadata) {
|
|
98
|
+
const table = schema.addTable(meta.collection, this.getSchemaName(meta, config, schemaName));
|
|
99
|
+
table.comment = meta.comment;
|
|
100
|
+
for (const prop of meta.props) {
|
|
101
|
+
if (!this.shouldHaveColumn(meta, prop, skipColumns)) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
table.addColumnFromProperty(prop, meta, config);
|
|
105
|
+
}
|
|
106
|
+
meta.indexes.forEach(index => table.addIndex(meta, index, 'index'));
|
|
107
|
+
meta.uniques.forEach(index => table.addIndex(meta, index, 'unique'));
|
|
108
|
+
table.addIndex(meta, { properties: meta.props.filter(prop => prop.primary).map(prop => prop.name) }, 'primary');
|
|
109
|
+
for (const check of meta.checks) {
|
|
110
|
+
const columnName = check.property ? meta.properties[check.property].fieldNames[0] : undefined;
|
|
111
|
+
let expression = check.expression;
|
|
112
|
+
const raw = RawQueryFragment.getKnownFragment(expression);
|
|
113
|
+
if (raw) {
|
|
114
|
+
expression = platform.formatQuery(raw.sql, raw.params);
|
|
115
|
+
}
|
|
116
|
+
table.addCheck({
|
|
117
|
+
name: check.name,
|
|
118
|
+
expression,
|
|
119
|
+
definition: `check (${check.expression})`,
|
|
120
|
+
columnName,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return schema;
|
|
125
|
+
}
|
|
126
|
+
static getSchemaName(meta, config, schema) {
|
|
127
|
+
return (meta.schema === '*' ? schema : meta.schema) ?? config.get('schema');
|
|
128
|
+
}
|
|
129
|
+
static matchName(name, nameToMatch) {
|
|
130
|
+
return typeof nameToMatch === 'string'
|
|
131
|
+
? name.toLocaleLowerCase() === nameToMatch.toLocaleLowerCase()
|
|
132
|
+
: nameToMatch.test(name);
|
|
133
|
+
}
|
|
134
|
+
static isTableNameAllowed(tableName, takeTables, skipTables) {
|
|
135
|
+
return ((takeTables?.some(tableNameToMatch => this.matchName(tableName, tableNameToMatch)) ?? true) &&
|
|
136
|
+
!(skipTables?.some(tableNameToMatch => this.matchName(tableName, tableNameToMatch)) ?? false));
|
|
137
|
+
}
|
|
138
|
+
static shouldHaveColumn(meta, prop, skipColumns) {
|
|
139
|
+
if (prop.persist === false || (prop.columnTypes?.length ?? 0) === 0) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
// Check if column should be skipped
|
|
143
|
+
if (skipColumns) {
|
|
144
|
+
const tableName = meta.tableName;
|
|
145
|
+
const tableSchema = meta.schema;
|
|
146
|
+
const fullTableName = tableSchema ? `${tableSchema}.${tableName}` : tableName;
|
|
147
|
+
// Check for skipColumns by table name or fully qualified table name
|
|
148
|
+
const columnsToSkip = skipColumns[tableName] || skipColumns[fullTableName];
|
|
149
|
+
if (columnsToSkip) {
|
|
150
|
+
for (const fieldName of prop.fieldNames) {
|
|
151
|
+
if (columnsToSkip.some(pattern => this.matchName(fieldName, pattern))) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
const getRootProperty = (prop) => prop.embedded ? getRootProperty(meta.properties[prop.embedded[0]]) : prop;
|
|
161
|
+
const rootProp = getRootProperty(prop);
|
|
162
|
+
if (rootProp.kind === ReferenceKind.EMBEDDED) {
|
|
163
|
+
return prop === rootProp || !rootProp.object;
|
|
164
|
+
}
|
|
165
|
+
return [ReferenceKind.SCALAR, ReferenceKind.MANY_TO_ONE].includes(prop.kind) || (prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner);
|
|
166
|
+
}
|
|
167
|
+
toJSON() {
|
|
168
|
+
const { platform, namespaces, ...rest } = this;
|
|
169
|
+
return { namespaces: [...namespaces], ...rest };
|
|
170
|
+
}
|
|
171
|
+
prune(schema, wildcardSchemaTables) {
|
|
172
|
+
const hasWildcardSchema = wildcardSchemaTables.length > 0;
|
|
173
|
+
this.tables = this.tables.filter(table => {
|
|
174
|
+
return (!schema && !hasWildcardSchema) // no schema specified and we don't have any multi-schema entity
|
|
175
|
+
|| table.schema === schema // specified schema matches the table's one
|
|
176
|
+
|| (!schema && !wildcardSchemaTables.includes(table.name)); // no schema specified and the table has fixed one provided
|
|
177
|
+
});
|
|
178
|
+
// remove namespaces of ignored tables
|
|
179
|
+
for (const ns of this.namespaces) {
|
|
180
|
+
if (!this.tables.some(t => t.schema === ns) && !Object.values(this.nativeEnums).some(e => e.schema === ns)) {
|
|
181
|
+
this.namespaces.delete(ns);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type Configuration, type DeferMode, type Dictionary, type EntityMetadata, type EntityProperty, type IndexCallback, type NamingStrategy } from '@mikro-orm/core';
|
|
2
|
+
import type { SchemaHelper } from './SchemaHelper.js';
|
|
3
|
+
import type { CheckDef, Column, ForeignKey, IndexDef } from '../typings.js';
|
|
4
|
+
import type { AbstractSqlPlatform } from '../AbstractSqlPlatform.js';
|
|
5
|
+
/**
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export declare class DatabaseTable {
|
|
9
|
+
private readonly platform;
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly schema?: string | undefined;
|
|
12
|
+
private columns;
|
|
13
|
+
private indexes;
|
|
14
|
+
private checks;
|
|
15
|
+
private foreignKeys;
|
|
16
|
+
nativeEnums: Dictionary<{
|
|
17
|
+
name: string;
|
|
18
|
+
schema?: string;
|
|
19
|
+
items: string[];
|
|
20
|
+
}>;
|
|
21
|
+
comment?: string;
|
|
22
|
+
constructor(platform: AbstractSqlPlatform, name: string, schema?: string | undefined);
|
|
23
|
+
getQuotedName(): string;
|
|
24
|
+
getColumns(): Column[];
|
|
25
|
+
getColumn(name: string): Column | undefined;
|
|
26
|
+
removeColumn(name: string): void;
|
|
27
|
+
getIndexes(): IndexDef[];
|
|
28
|
+
getChecks(): CheckDef[];
|
|
29
|
+
init(cols: Column[], indexes: IndexDef[] | undefined, checks: CheckDef[] | undefined, pks: string[], fks?: Dictionary<ForeignKey>, enums?: Dictionary<string[]>): void;
|
|
30
|
+
addColumn(column: Column): void;
|
|
31
|
+
addColumnFromProperty(prop: EntityProperty, meta: EntityMetadata, config: Configuration): void;
|
|
32
|
+
private getIndexName;
|
|
33
|
+
getEntityDeclaration(namingStrategy: NamingStrategy, schemaHelper: SchemaHelper, scalarPropertiesForRelations: 'always' | 'never' | 'smart'): EntityMetadata;
|
|
34
|
+
private foreignKeysToProps;
|
|
35
|
+
private findFkIndex;
|
|
36
|
+
private getIndexProperties;
|
|
37
|
+
private getSafeBaseNameForFkProp;
|
|
38
|
+
/**
|
|
39
|
+
* The shortest name is stripped of the default namespace. All other namespaced elements are returned as full-qualified names.
|
|
40
|
+
*/
|
|
41
|
+
getShortestName(skipDefaultSchema?: boolean): string;
|
|
42
|
+
getForeignKeys(): Dictionary<ForeignKey>;
|
|
43
|
+
hasColumn(columnName: string): boolean;
|
|
44
|
+
getIndex(indexName: string): IndexDef | undefined;
|
|
45
|
+
hasIndex(indexName: string): boolean;
|
|
46
|
+
getCheck(checkName: string): CheckDef<unknown> | undefined;
|
|
47
|
+
hasCheck(checkName: string): boolean;
|
|
48
|
+
getPrimaryKey(): IndexDef | undefined;
|
|
49
|
+
hasPrimaryKey(): boolean;
|
|
50
|
+
private getForeignKeyDeclaration;
|
|
51
|
+
private getPropertyDeclaration;
|
|
52
|
+
private getReferenceKind;
|
|
53
|
+
private getPropertyName;
|
|
54
|
+
private getPropertyTypeForForeignKey;
|
|
55
|
+
private getPropertyTypeForColumn;
|
|
56
|
+
private getPropertyDefaultValue;
|
|
57
|
+
private processIndexExpression;
|
|
58
|
+
addIndex(meta: EntityMetadata, index: {
|
|
59
|
+
properties?: string | string[];
|
|
60
|
+
name?: string;
|
|
61
|
+
type?: string;
|
|
62
|
+
expression?: string | IndexCallback<any>;
|
|
63
|
+
deferMode?: DeferMode | `${DeferMode}`;
|
|
64
|
+
options?: Dictionary;
|
|
65
|
+
}, type: 'index' | 'unique' | 'primary'): void;
|
|
66
|
+
addCheck(check: CheckDef): void;
|
|
67
|
+
toJSON(): Dictionary;
|
|
68
|
+
}
|