@mikro-orm/sql 7.0.0-dev.98 → 7.0.0-rc.0
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 +6 -7
- package/AbstractSqlConnection.js +27 -24
- package/AbstractSqlDriver.d.ts +82 -23
- package/AbstractSqlDriver.js +584 -184
- package/AbstractSqlPlatform.d.ts +3 -4
- package/AbstractSqlPlatform.js +0 -4
- package/PivotCollectionPersister.d.ts +5 -0
- package/PivotCollectionPersister.js +30 -12
- package/SqlEntityManager.d.ts +2 -2
- package/dialects/mysql/{MySqlPlatform.d.ts → BaseMySqlPlatform.d.ts} +3 -2
- package/dialects/mysql/{MySqlPlatform.js → BaseMySqlPlatform.js} +5 -1
- package/dialects/mysql/MySqlSchemaHelper.d.ts +12 -1
- package/dialects/mysql/MySqlSchemaHelper.js +97 -6
- package/dialects/mysql/index.d.ts +1 -2
- package/dialects/mysql/index.js +1 -2
- package/dialects/postgresql/BasePostgreSqlPlatform.d.ts +106 -0
- package/dialects/postgresql/BasePostgreSqlPlatform.js +350 -0
- package/dialects/postgresql/FullTextType.d.ts +14 -0
- package/dialects/postgresql/FullTextType.js +59 -0
- package/dialects/postgresql/PostgreSqlExceptionConverter.d.ts +8 -0
- package/dialects/postgresql/PostgreSqlExceptionConverter.js +47 -0
- package/dialects/postgresql/PostgreSqlSchemaHelper.d.ts +90 -0
- package/dialects/postgresql/PostgreSqlSchemaHelper.js +732 -0
- package/dialects/postgresql/index.d.ts +3 -0
- package/dialects/postgresql/index.js +3 -0
- package/dialects/sqlite/BaseSqliteConnection.d.ts +1 -0
- package/dialects/sqlite/BaseSqliteConnection.js +14 -1
- package/dialects/sqlite/BaseSqlitePlatform.d.ts +6 -0
- package/dialects/sqlite/BaseSqlitePlatform.js +12 -0
- package/dialects/sqlite/SqliteSchemaHelper.d.ts +25 -0
- package/dialects/sqlite/SqliteSchemaHelper.js +145 -19
- package/dialects/sqlite/index.d.ts +0 -1
- package/dialects/sqlite/index.js +0 -1
- package/package.json +5 -6
- package/plugin/transformer.d.ts +1 -1
- package/plugin/transformer.js +1 -1
- package/query/CriteriaNode.d.ts +9 -5
- package/query/CriteriaNode.js +16 -15
- package/query/CriteriaNodeFactory.d.ts +6 -6
- package/query/CriteriaNodeFactory.js +33 -31
- package/query/NativeQueryBuilder.d.ts +3 -2
- package/query/NativeQueryBuilder.js +1 -2
- package/query/ObjectCriteriaNode.js +50 -35
- package/query/QueryBuilder.d.ts +548 -79
- package/query/QueryBuilder.js +537 -159
- package/query/QueryBuilderHelper.d.ts +22 -14
- package/query/QueryBuilderHelper.js +158 -69
- package/query/ScalarCriteriaNode.js +2 -2
- package/query/raw.d.ts +11 -3
- package/query/raw.js +1 -2
- package/schema/DatabaseSchema.d.ts +15 -2
- package/schema/DatabaseSchema.js +143 -15
- package/schema/DatabaseTable.d.ts +12 -0
- package/schema/DatabaseTable.js +91 -31
- package/schema/SchemaComparator.d.ts +8 -0
- package/schema/SchemaComparator.js +126 -3
- package/schema/SchemaHelper.d.ts +26 -3
- package/schema/SchemaHelper.js +98 -11
- package/schema/SqlSchemaGenerator.d.ts +10 -0
- package/schema/SqlSchemaGenerator.js +137 -9
- package/tsconfig.build.tsbuildinfo +1 -0
- package/typings.d.ts +74 -36
- package/dialects/postgresql/PostgreSqlTableCompiler.d.ts +0 -1
- package/dialects/postgresql/PostgreSqlTableCompiler.js +0 -1
package/AbstractSqlPlatform.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Constructor, type EntityManager, type EntityRepository, type IDatabaseDriver, type IsolationLevel, type MikroORM, Platform } from '@mikro-orm/core';
|
|
1
|
+
import { type RawQueryFragment, type Constructor, type EntityManager, type EntityRepository, type IDatabaseDriver, type IsolationLevel, type MikroORM, Platform } from '@mikro-orm/core';
|
|
2
2
|
import { SqlSchemaGenerator } from './schema/SqlSchemaGenerator.js';
|
|
3
3
|
import { type SchemaHelper } from './schema/SchemaHelper.js';
|
|
4
4
|
import type { IndexDef } from './typings.js';
|
|
@@ -24,9 +24,8 @@ export declare abstract class AbstractSqlPlatform extends Platform {
|
|
|
24
24
|
getRollbackToSavepointSQL(savepointName: string): string;
|
|
25
25
|
getReleaseSavepointSQL(savepointName: string): string;
|
|
26
26
|
quoteValue(value: any): string;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
getSearchJsonPropertyKey(path: string[], type: string, aliased: boolean, value?: unknown): string;
|
|
27
|
+
getSearchJsonPropertySQL(path: string, type: string, aliased: boolean): string | RawQueryFragment;
|
|
28
|
+
getSearchJsonPropertyKey(path: string[], type: string, aliased: boolean, value?: unknown): string | RawQueryFragment;
|
|
30
29
|
getJsonIndexDefinition(index: IndexDef): string[];
|
|
31
30
|
supportsSchemas(): boolean;
|
|
32
31
|
/** @inheritDoc */
|
package/AbstractSqlPlatform.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import SqlString from 'sqlstring';
|
|
2
1
|
import { isRaw, JsonProperty, Platform, raw, Utils, } from '@mikro-orm/core';
|
|
3
2
|
import { SqlEntityRepository } from './SqlEntityRepository.js';
|
|
4
3
|
import { SqlSchemaGenerator } from './schema/SqlSchemaGenerator.js';
|
|
@@ -60,9 +59,6 @@ export class AbstractSqlPlatform extends Platform {
|
|
|
60
59
|
}
|
|
61
60
|
return this.escape(value);
|
|
62
61
|
}
|
|
63
|
-
escape(value) {
|
|
64
|
-
return SqlString.escape(value, true, this.timezone);
|
|
65
|
-
}
|
|
66
62
|
getSearchJsonPropertySQL(path, type, aliased) {
|
|
67
63
|
return this.getSearchJsonPropertyKey(path.split('->'), type, aliased);
|
|
68
64
|
}
|
|
@@ -17,6 +17,11 @@ export declare class PivotCollectionPersister<Entity extends object> {
|
|
|
17
17
|
private enqueueUpsert;
|
|
18
18
|
private createInsertStatement;
|
|
19
19
|
private enqueueDelete;
|
|
20
|
+
/**
|
|
21
|
+
* Build the keys and data arrays for pivot table operations.
|
|
22
|
+
* Handles polymorphic M:N by prepending the discriminator column/value.
|
|
23
|
+
*/
|
|
24
|
+
private buildPivotKeysAndData;
|
|
20
25
|
private collectStatements;
|
|
21
26
|
execute(): Promise<void>;
|
|
22
27
|
}
|
|
@@ -83,27 +83,45 @@ export class PivotCollectionPersister {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
createInsertStatement(prop, fks, pks) {
|
|
86
|
-
const data = prop
|
|
87
|
-
const keys = prop.owner
|
|
88
|
-
? [...prop.inverseJoinColumns, ...prop.joinColumns]
|
|
89
|
-
: [...prop.joinColumns, ...prop.inverseJoinColumns];
|
|
86
|
+
const { data, keys } = this.buildPivotKeysAndData(prop, fks, pks);
|
|
90
87
|
return new InsertStatement(keys, data, this.order++);
|
|
91
88
|
}
|
|
92
89
|
enqueueDelete(prop, deleteDiff, pks) {
|
|
93
90
|
if (deleteDiff === true) {
|
|
94
|
-
const
|
|
91
|
+
const { data, keys } = this.buildPivotKeysAndData(prop, [], pks, true);
|
|
92
|
+
const statement = new DeleteStatement(keys, data);
|
|
95
93
|
this.deletes.set(statement.getHash(), statement);
|
|
96
94
|
return;
|
|
97
95
|
}
|
|
98
96
|
for (const fks of deleteDiff) {
|
|
99
|
-
const data = prop
|
|
100
|
-
const keys = prop.owner
|
|
101
|
-
? [...prop.inverseJoinColumns, ...prop.joinColumns]
|
|
102
|
-
: [...prop.joinColumns, ...prop.inverseJoinColumns];
|
|
97
|
+
const { data, keys } = this.buildPivotKeysAndData(prop, fks, pks);
|
|
103
98
|
const statement = new DeleteStatement(keys, data);
|
|
104
99
|
this.deletes.set(statement.getHash(), statement);
|
|
105
100
|
}
|
|
106
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Build the keys and data arrays for pivot table operations.
|
|
104
|
+
* Handles polymorphic M:N by prepending the discriminator column/value.
|
|
105
|
+
*/
|
|
106
|
+
buildPivotKeysAndData(prop, fks, pks, deleteAll = false) {
|
|
107
|
+
let data;
|
|
108
|
+
let keys;
|
|
109
|
+
if (deleteAll) {
|
|
110
|
+
data = pks;
|
|
111
|
+
keys = prop.joinColumns;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
data = prop.owner ? [...fks, ...pks] : [...pks, ...fks];
|
|
115
|
+
keys = prop.owner
|
|
116
|
+
? [...prop.inverseJoinColumns, ...prop.joinColumns]
|
|
117
|
+
: [...prop.joinColumns, ...prop.inverseJoinColumns];
|
|
118
|
+
}
|
|
119
|
+
if (prop.polymorphic && prop.discriminatorColumn && prop.discriminatorValue) {
|
|
120
|
+
data = [prop.discriminatorValue, ...data];
|
|
121
|
+
keys = [prop.discriminatorColumn, ...keys];
|
|
122
|
+
}
|
|
123
|
+
return { data, keys };
|
|
124
|
+
}
|
|
107
125
|
collectStatements(statements) {
|
|
108
126
|
const items = [];
|
|
109
127
|
for (const statement of statements.values()) {
|
|
@@ -120,7 +138,7 @@ export class PivotCollectionPersister {
|
|
|
120
138
|
for (const item of chunk) {
|
|
121
139
|
cond.$or.push(item.getCondition());
|
|
122
140
|
}
|
|
123
|
-
await this.driver.nativeDelete(this.meta.
|
|
141
|
+
await this.driver.nativeDelete(this.meta.class, cond, {
|
|
124
142
|
ctx: this.ctx,
|
|
125
143
|
schema: this.schema,
|
|
126
144
|
loggerContext: this.loggerContext,
|
|
@@ -131,7 +149,7 @@ export class PivotCollectionPersister {
|
|
|
131
149
|
const filtered = this.collectStatements(this.inserts);
|
|
132
150
|
for (let i = 0; i < filtered.length; i += this.batchSize) {
|
|
133
151
|
const chunk = filtered.slice(i, i + this.batchSize);
|
|
134
|
-
await this.driver.nativeInsertMany(this.meta.
|
|
152
|
+
await this.driver.nativeInsertMany(this.meta.class, chunk, {
|
|
135
153
|
ctx: this.ctx,
|
|
136
154
|
schema: this.schema,
|
|
137
155
|
convertCustomTypes: false,
|
|
@@ -144,7 +162,7 @@ export class PivotCollectionPersister {
|
|
|
144
162
|
const filtered = this.collectStatements(this.upserts);
|
|
145
163
|
for (let i = 0; i < filtered.length; i += this.batchSize) {
|
|
146
164
|
const chunk = filtered.slice(i, i + this.batchSize);
|
|
147
|
-
await this.driver.nativeUpdateMany(this.meta.
|
|
165
|
+
await this.driver.nativeUpdateMany(this.meta.class, [], chunk, {
|
|
148
166
|
ctx: this.ctx,
|
|
149
167
|
schema: this.schema,
|
|
150
168
|
convertCustomTypes: false,
|
package/SqlEntityManager.d.ts
CHANGED
|
@@ -20,14 +20,14 @@ export declare class SqlEntityManager<Driver extends AbstractSqlDriver = Abstrac
|
|
|
20
20
|
/**
|
|
21
21
|
* Shortcut for `createQueryBuilder()`
|
|
22
22
|
*/
|
|
23
|
-
qb<Entity extends object, RootAlias extends string = never>(entityName: EntityName<Entity>, alias?: RootAlias, type?: ConnectionType, loggerContext?: LoggingOptions): QueryBuilder<Entity, RootAlias, never, never>;
|
|
23
|
+
qb<Entity extends object, RootAlias extends string = never>(entityName: EntityName<Entity>, alias?: RootAlias, type?: ConnectionType, loggerContext?: LoggingOptions): QueryBuilder<Entity, RootAlias, never, never, never, "*">;
|
|
24
24
|
/**
|
|
25
25
|
* Returns configured Kysely instance.
|
|
26
26
|
*/
|
|
27
27
|
getKysely<TDB = undefined, TOptions extends GetKyselyOptions = GetKyselyOptions>(options?: TOptions): Kysely<TDB extends undefined ? InferKyselyDB<EntitiesFromManager<this>, TOptions> : TDB>;
|
|
28
28
|
execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(query: string | NativeQueryBuilder | RawQueryFragment, params?: any[], method?: 'all' | 'get' | 'run', loggerContext?: LoggingOptions): Promise<T>;
|
|
29
29
|
getRepository<T extends object, U extends EntityRepository<T> = SqlEntityRepository<T>>(entityName: EntityName<T>): GetRepository<T, U>;
|
|
30
|
-
protected applyDiscriminatorCondition<Entity extends object>(entityName:
|
|
30
|
+
protected applyDiscriminatorCondition<Entity extends object>(entityName: EntityName<Entity>, where: FilterQuery<Entity>): FilterQuery<Entity>;
|
|
31
31
|
}
|
|
32
32
|
type EntitiesFromManager<TEntityManager extends EntityManager<any>> = NonNullable<TEntityManager['~entities']> extends any[] ? (Extract<NonNullable<TEntityManager['~entities']>[number], EntitySchemaWithMeta>) : never;
|
|
33
33
|
export {};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { type SimpleColumnMeta, type Type, type TransformContext, type IsolationLevel } from '@mikro-orm/core';
|
|
1
|
+
import { type SimpleColumnMeta, type Type, type TransformContext, type MikroORM, type IsolationLevel } from '@mikro-orm/core';
|
|
2
2
|
import { MySqlSchemaHelper } from './MySqlSchemaHelper.js';
|
|
3
3
|
import { MySqlExceptionConverter } from './MySqlExceptionConverter.js';
|
|
4
4
|
import { AbstractSqlPlatform } from '../../AbstractSqlPlatform.js';
|
|
5
5
|
import type { IndexDef } from '../../typings.js';
|
|
6
6
|
import { MySqlNativeQueryBuilder } from './MySqlNativeQueryBuilder.js';
|
|
7
|
-
export declare class
|
|
7
|
+
export declare class BaseMySqlPlatform extends AbstractSqlPlatform {
|
|
8
8
|
protected readonly schemaHelper: MySqlSchemaHelper;
|
|
9
9
|
protected readonly exceptionConverter: MySqlExceptionConverter;
|
|
10
10
|
protected readonly ORDER_BY_NULLS_TRANSLATE: {
|
|
@@ -16,6 +16,7 @@ export declare class MySqlPlatform extends AbstractSqlPlatform {
|
|
|
16
16
|
/** @internal */
|
|
17
17
|
createNativeQueryBuilder(): MySqlNativeQueryBuilder;
|
|
18
18
|
getDefaultCharset(): string;
|
|
19
|
+
init(orm: MikroORM): void;
|
|
19
20
|
getBeginTransactionSQL(options?: {
|
|
20
21
|
isolationLevel?: IsolationLevel;
|
|
21
22
|
readOnly?: boolean;
|
|
@@ -3,7 +3,7 @@ import { MySqlSchemaHelper } from './MySqlSchemaHelper.js';
|
|
|
3
3
|
import { MySqlExceptionConverter } from './MySqlExceptionConverter.js';
|
|
4
4
|
import { AbstractSqlPlatform } from '../../AbstractSqlPlatform.js';
|
|
5
5
|
import { MySqlNativeQueryBuilder } from './MySqlNativeQueryBuilder.js';
|
|
6
|
-
export class
|
|
6
|
+
export class BaseMySqlPlatform extends AbstractSqlPlatform {
|
|
7
7
|
schemaHelper = new MySqlSchemaHelper(this);
|
|
8
8
|
exceptionConverter = new MySqlExceptionConverter();
|
|
9
9
|
ORDER_BY_NULLS_TRANSLATE = {
|
|
@@ -19,6 +19,10 @@ export class MySqlPlatform extends AbstractSqlPlatform {
|
|
|
19
19
|
getDefaultCharset() {
|
|
20
20
|
return 'utf8mb4';
|
|
21
21
|
}
|
|
22
|
+
init(orm) {
|
|
23
|
+
super.init(orm);
|
|
24
|
+
orm.config.get('schemaGenerator').disableForeignKeysForClear ??= true;
|
|
25
|
+
}
|
|
22
26
|
getBeginTransactionSQL(options) {
|
|
23
27
|
if (options?.isolationLevel || options?.readOnly) {
|
|
24
28
|
const parts = [];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Dictionary, type Type } from '@mikro-orm/core';
|
|
2
|
-
import type { CheckDef, Column,
|
|
2
|
+
import type { CheckDef, Column, ForeignKey, IndexDef, Table, TableDifference } from '../../typings.js';
|
|
3
3
|
import type { AbstractSqlConnection } from '../../AbstractSqlConnection.js';
|
|
4
4
|
import { SchemaHelper } from '../../schema/SchemaHelper.js';
|
|
5
5
|
import type { DatabaseSchema } from '../../schema/DatabaseSchema.js';
|
|
@@ -16,9 +16,20 @@ export declare class MySqlSchemaHelper extends SchemaHelper {
|
|
|
16
16
|
enableForeignKeysSQL(): string;
|
|
17
17
|
finalizeTable(table: DatabaseTable, charset: string, collate?: string): string;
|
|
18
18
|
getListTablesSQL(): string;
|
|
19
|
+
getListViewsSQL(): string;
|
|
20
|
+
loadViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string): Promise<void>;
|
|
19
21
|
loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[]): Promise<void>;
|
|
20
22
|
getAllIndexes(connection: AbstractSqlConnection, tables: Table[]): Promise<Dictionary<IndexDef[]>>;
|
|
21
23
|
getCreateIndexSQL(tableName: string, index: IndexDef, partialExpression?: boolean): string;
|
|
24
|
+
/**
|
|
25
|
+
* Build the column list for a MySQL index, with MySQL-specific handling for collation.
|
|
26
|
+
* MySQL requires collation to be specified as an expression: (column_name COLLATE collation_name)
|
|
27
|
+
*/
|
|
28
|
+
protected getIndexColumns(index: IndexDef): string;
|
|
29
|
+
/**
|
|
30
|
+
* Append MySQL-specific index suffixes like INVISIBLE.
|
|
31
|
+
*/
|
|
32
|
+
protected appendMySqlIndexSuffix(sql: string, index: IndexDef): string;
|
|
22
33
|
getAllColumns(connection: AbstractSqlConnection, tables: Table[]): Promise<Dictionary<Column[]>>;
|
|
23
34
|
getAllChecks(connection: AbstractSqlConnection, tables: Table[]): Promise<Dictionary<CheckDef[]>>;
|
|
24
35
|
getAllForeignKeys(connection: AbstractSqlConnection, tables: Table[]): Promise<Dictionary<Dictionary<ForeignKey>>>;
|
|
@@ -33,6 +33,28 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
33
33
|
getListTablesSQL() {
|
|
34
34
|
return `select table_name as table_name, nullif(table_schema, schema()) as schema_name, table_comment as table_comment from information_schema.tables where table_type = 'BASE TABLE' and table_schema = schema()`;
|
|
35
35
|
}
|
|
36
|
+
getListViewsSQL() {
|
|
37
|
+
return `select table_name as view_name, nullif(table_schema, schema()) as schema_name, view_definition from information_schema.views where table_schema = schema()`;
|
|
38
|
+
}
|
|
39
|
+
async loadViews(schema, connection, schemaName) {
|
|
40
|
+
const views = await connection.execute(this.getListViewsSQL());
|
|
41
|
+
for (const view of views) {
|
|
42
|
+
// MySQL information_schema.views.view_definition requires SHOW VIEW privilege
|
|
43
|
+
// and may return NULL. Use SHOW CREATE VIEW as fallback.
|
|
44
|
+
let definition = view.view_definition?.trim();
|
|
45
|
+
if (!definition) {
|
|
46
|
+
const createView = await connection.execute(`show create view \`${view.view_name}\``);
|
|
47
|
+
if (createView[0]?.['Create View']) {
|
|
48
|
+
// Extract SELECT statement from CREATE VIEW ... AS SELECT ...
|
|
49
|
+
const match = createView[0]['Create View'].match(/\bAS\s+(.+)$/is);
|
|
50
|
+
definition = match?.[1]?.trim();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (definition) {
|
|
54
|
+
schema.addView(view.view_name, view.schema_name ?? undefined, definition);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
36
58
|
async loadInformationSchema(schema, connection, tables) {
|
|
37
59
|
if (tables.length === 0) {
|
|
38
60
|
return;
|
|
@@ -50,7 +72,7 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
50
72
|
}
|
|
51
73
|
}
|
|
52
74
|
async getAllIndexes(connection, tables) {
|
|
53
|
-
const sql = `select table_name as table_name, nullif(table_schema, schema()) as schema_name, index_name as index_name, non_unique as non_unique, column_name as column_name /*!80013 , expression as expression */
|
|
75
|
+
const sql = `select table_name as table_name, nullif(table_schema, schema()) as schema_name, index_name as index_name, non_unique as non_unique, column_name as column_name, index_type as index_type, sub_part as sub_part, collation as sort_order /*!80013 , expression as expression, is_visible as is_visible */
|
|
54
76
|
from information_schema.statistics where table_schema = database()
|
|
55
77
|
and table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(', ')})
|
|
56
78
|
order by schema_name, table_name, index_name, seq_in_index`;
|
|
@@ -65,6 +87,26 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
65
87
|
primary: index.index_name === 'PRIMARY',
|
|
66
88
|
constraint: !index.non_unique,
|
|
67
89
|
};
|
|
90
|
+
// Capture column options (prefix length, sort order)
|
|
91
|
+
if (index.sub_part != null || index.sort_order === 'D') {
|
|
92
|
+
indexDef.columns = [{
|
|
93
|
+
name: index.column_name,
|
|
94
|
+
...(index.sub_part != null && { length: index.sub_part }),
|
|
95
|
+
...(index.sort_order === 'D' && { sort: 'DESC' }),
|
|
96
|
+
}];
|
|
97
|
+
}
|
|
98
|
+
// Capture index type for fulltext and spatial indexes
|
|
99
|
+
if (index.index_type === 'FULLTEXT') {
|
|
100
|
+
indexDef.type = 'fulltext';
|
|
101
|
+
}
|
|
102
|
+
else if (index.index_type === 'SPATIAL') {
|
|
103
|
+
/* v8 ignore next */
|
|
104
|
+
indexDef.type = 'spatial';
|
|
105
|
+
}
|
|
106
|
+
// Capture invisible flag (MySQL 8.0.13+)
|
|
107
|
+
if (index.is_visible === 'NO') {
|
|
108
|
+
indexDef.invisible = true;
|
|
109
|
+
}
|
|
68
110
|
if (!index.column_name || index.expression?.match(/ where /i)) {
|
|
69
111
|
indexDef.expression = index.expression; // required for the `getCreateIndexSQL()` call
|
|
70
112
|
indexDef.expression = this.getCreateIndexSQL(index.table_name, indexDef, !!index.expression);
|
|
@@ -84,17 +126,66 @@ export class MySqlSchemaHelper extends SchemaHelper {
|
|
|
84
126
|
}
|
|
85
127
|
tableName = this.quote(tableName);
|
|
86
128
|
const keyName = this.quote(index.keyName);
|
|
87
|
-
|
|
129
|
+
let sql = `alter table ${tableName} add ${index.unique ? 'unique' : 'index'} ${keyName} `;
|
|
88
130
|
if (index.expression && partialExpression) {
|
|
89
|
-
|
|
131
|
+
sql += `(${index.expression})`;
|
|
132
|
+
return this.appendMySqlIndexSuffix(sql, index);
|
|
90
133
|
}
|
|
91
134
|
// JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
|
|
92
135
|
if (index.columnNames.some(column => column.includes('.'))) {
|
|
93
136
|
const columns = this.platform.getJsonIndexDefinition(index);
|
|
94
|
-
|
|
95
|
-
|
|
137
|
+
sql = `alter table ${tableName} add ${index.unique ? 'unique ' : ''}index ${keyName} `;
|
|
138
|
+
sql += `(${columns.join(', ')})`;
|
|
139
|
+
return this.appendMySqlIndexSuffix(sql, index);
|
|
140
|
+
}
|
|
141
|
+
// Build column list with advanced options
|
|
142
|
+
const columns = this.getIndexColumns(index);
|
|
143
|
+
sql += `(${columns})`;
|
|
144
|
+
return this.appendMySqlIndexSuffix(sql, index);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Build the column list for a MySQL index, with MySQL-specific handling for collation.
|
|
148
|
+
* MySQL requires collation to be specified as an expression: (column_name COLLATE collation_name)
|
|
149
|
+
*/
|
|
150
|
+
getIndexColumns(index) {
|
|
151
|
+
if (index.columns?.length) {
|
|
152
|
+
return index.columns.map(col => {
|
|
153
|
+
const quotedName = this.quote(col.name);
|
|
154
|
+
// MySQL supports collation via expression: (column_name COLLATE collation_name)
|
|
155
|
+
// When collation is specified, wrap in parentheses as an expression
|
|
156
|
+
if (col.collation) {
|
|
157
|
+
let expr = col.length ? `${quotedName}(${col.length})` : quotedName;
|
|
158
|
+
expr = `(${expr} collate ${col.collation})`;
|
|
159
|
+
// Sort order comes after the expression
|
|
160
|
+
if (col.sort) {
|
|
161
|
+
expr += ` ${col.sort}`;
|
|
162
|
+
}
|
|
163
|
+
return expr;
|
|
164
|
+
}
|
|
165
|
+
// Standard column definition without collation
|
|
166
|
+
let colDef = quotedName;
|
|
167
|
+
// MySQL supports prefix length
|
|
168
|
+
if (col.length) {
|
|
169
|
+
colDef += `(${col.length})`;
|
|
170
|
+
}
|
|
171
|
+
// MySQL supports sort order
|
|
172
|
+
if (col.sort) {
|
|
173
|
+
colDef += ` ${col.sort}`;
|
|
174
|
+
}
|
|
175
|
+
return colDef;
|
|
176
|
+
}).join(', ');
|
|
96
177
|
}
|
|
97
|
-
return
|
|
178
|
+
return index.columnNames.map(c => this.quote(c)).join(', ');
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Append MySQL-specific index suffixes like INVISIBLE.
|
|
182
|
+
*/
|
|
183
|
+
appendMySqlIndexSuffix(sql, index) {
|
|
184
|
+
// MySQL 8.0+ supports INVISIBLE indexes
|
|
185
|
+
if (index.invisible) {
|
|
186
|
+
sql += ' invisible';
|
|
187
|
+
}
|
|
188
|
+
return sql;
|
|
98
189
|
}
|
|
99
190
|
async getAllColumns(connection, tables) {
|
|
100
191
|
const sql = `select table_name as table_name,
|
package/dialects/mysql/index.js
CHANGED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { type EntityProperty, type IsolationLevel, RawQueryFragment, type SimpleColumnMeta, Type } from '@mikro-orm/core';
|
|
2
|
+
import { AbstractSqlPlatform } from '../../AbstractSqlPlatform.js';
|
|
3
|
+
import type { IndexDef } from '../../typings.js';
|
|
4
|
+
import { PostgreSqlNativeQueryBuilder } from './PostgreSqlNativeQueryBuilder.js';
|
|
5
|
+
import { PostgreSqlSchemaHelper } from './PostgreSqlSchemaHelper.js';
|
|
6
|
+
import { PostgreSqlExceptionConverter } from './PostgreSqlExceptionConverter.js';
|
|
7
|
+
export declare class BasePostgreSqlPlatform extends AbstractSqlPlatform {
|
|
8
|
+
protected readonly schemaHelper: PostgreSqlSchemaHelper;
|
|
9
|
+
protected readonly exceptionConverter: PostgreSqlExceptionConverter;
|
|
10
|
+
createNativeQueryBuilder(): PostgreSqlNativeQueryBuilder;
|
|
11
|
+
usesReturningStatement(): boolean;
|
|
12
|
+
usesCascadeStatement(): boolean;
|
|
13
|
+
supportsNativeEnums(): boolean;
|
|
14
|
+
usesEnumCheckConstraints(): boolean;
|
|
15
|
+
supportsMaterializedViews(): boolean;
|
|
16
|
+
supportsCustomPrimaryKeyNames(): boolean;
|
|
17
|
+
getCurrentTimestampSQL(length: number): string;
|
|
18
|
+
getDateTimeTypeDeclarationSQL(column: {
|
|
19
|
+
length?: number;
|
|
20
|
+
}): string;
|
|
21
|
+
getDefaultDateTimeLength(): number;
|
|
22
|
+
getTimeTypeDeclarationSQL(): string;
|
|
23
|
+
getIntegerTypeDeclarationSQL(column: {
|
|
24
|
+
length?: number;
|
|
25
|
+
autoincrement?: boolean;
|
|
26
|
+
generated?: string;
|
|
27
|
+
}): string;
|
|
28
|
+
getBigIntTypeDeclarationSQL(column: {
|
|
29
|
+
autoincrement?: boolean;
|
|
30
|
+
}): string;
|
|
31
|
+
getTinyIntTypeDeclarationSQL(column: {
|
|
32
|
+
length?: number;
|
|
33
|
+
unsigned?: boolean;
|
|
34
|
+
autoincrement?: boolean;
|
|
35
|
+
}): string;
|
|
36
|
+
getUuidTypeDeclarationSQL(column: {
|
|
37
|
+
length?: number;
|
|
38
|
+
}): string;
|
|
39
|
+
getFullTextWhereClause(prop: EntityProperty): string;
|
|
40
|
+
supportsCreatingFullTextIndex(): boolean;
|
|
41
|
+
getFullTextIndexExpression(indexName: string, schemaName: string | undefined, tableName: string, columns: SimpleColumnMeta[]): string;
|
|
42
|
+
normalizeColumnType(type: string, options: {
|
|
43
|
+
length?: number;
|
|
44
|
+
precision?: number;
|
|
45
|
+
scale?: number;
|
|
46
|
+
autoincrement?: boolean;
|
|
47
|
+
}): string;
|
|
48
|
+
getMappedType(type: string): Type<unknown>;
|
|
49
|
+
getRegExpOperator(val?: unknown, flags?: string): string;
|
|
50
|
+
getRegExpValue(val: RegExp): {
|
|
51
|
+
$re: string;
|
|
52
|
+
$flags?: string;
|
|
53
|
+
};
|
|
54
|
+
isBigIntProperty(prop: EntityProperty): boolean;
|
|
55
|
+
getArrayDeclarationSQL(): string;
|
|
56
|
+
getFloatDeclarationSQL(): string;
|
|
57
|
+
getDoubleDeclarationSQL(): string;
|
|
58
|
+
getEnumTypeDeclarationSQL(column: {
|
|
59
|
+
fieldNames: string[];
|
|
60
|
+
items?: unknown[];
|
|
61
|
+
nativeEnumName?: string;
|
|
62
|
+
}): string;
|
|
63
|
+
supportsMultipleStatements(): boolean;
|
|
64
|
+
getBeginTransactionSQL(options?: {
|
|
65
|
+
isolationLevel?: IsolationLevel;
|
|
66
|
+
readOnly?: boolean;
|
|
67
|
+
}): string[];
|
|
68
|
+
marshallArray(values: string[]): string;
|
|
69
|
+
unmarshallArray(value: string): string[];
|
|
70
|
+
getVarcharTypeDeclarationSQL(column: {
|
|
71
|
+
length?: number;
|
|
72
|
+
}): string;
|
|
73
|
+
getCharTypeDeclarationSQL(column: {
|
|
74
|
+
length?: number;
|
|
75
|
+
}): string;
|
|
76
|
+
getIntervalTypeDeclarationSQL(column: {
|
|
77
|
+
length?: number;
|
|
78
|
+
}): string;
|
|
79
|
+
getBlobDeclarationSQL(): string;
|
|
80
|
+
getJsonDeclarationSQL(): string;
|
|
81
|
+
getSearchJsonPropertyKey(path: string[], type: string | undefined | Type, aliased: boolean, value?: unknown): string | RawQueryFragment;
|
|
82
|
+
getJsonIndexDefinition(index: IndexDef): string[];
|
|
83
|
+
quoteIdentifier(id: string | {
|
|
84
|
+
toString: () => string;
|
|
85
|
+
}, quote?: string): string;
|
|
86
|
+
private pad;
|
|
87
|
+
/** @internal */
|
|
88
|
+
formatDate(date: Date): string;
|
|
89
|
+
indexForeignKeys(): boolean;
|
|
90
|
+
getDefaultMappedType(type: string): Type<unknown>;
|
|
91
|
+
supportsSchemas(): boolean;
|
|
92
|
+
getDefaultSchemaName(): string | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* Returns the default name of index for the given columns
|
|
95
|
+
* cannot go past 63 character length for identifiers in MySQL
|
|
96
|
+
*/
|
|
97
|
+
getIndexName(tableName: string, columns: string[], type: 'index' | 'unique' | 'foreign' | 'primary' | 'sequence'): string;
|
|
98
|
+
getDefaultPrimaryName(tableName: string, columns: string[]): string;
|
|
99
|
+
/**
|
|
100
|
+
* @inheritDoc
|
|
101
|
+
*/
|
|
102
|
+
castColumn(prop?: {
|
|
103
|
+
columnTypes?: string[];
|
|
104
|
+
}): string;
|
|
105
|
+
getDefaultClientUrl(): string;
|
|
106
|
+
}
|