@mikro-orm/knex 6.2.10-dev.9 → 6.2.10-dev.90

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.
@@ -538,7 +538,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
538
538
  let sql = `update ${this.getTableName(meta, options)} set `;
539
539
  const addParams = (prop, value) => {
540
540
  if (prop.kind === core_1.ReferenceKind.EMBEDDED && prop.object) {
541
- if (prop.array) {
541
+ if (prop.array && value) {
542
542
  for (let i = 0; i < value.length; i++) {
543
543
  const item = value[i];
544
544
  value[i] = this.mapDataToFieldNames(item, false, prop.embeddedProps, options.convertCustomTypes);
@@ -1099,9 +1099,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
1099
1099
  if (!prop) {
1100
1100
  throw new Error(`Trying to order by not existing property ${meta.className}.${propName}`);
1101
1101
  }
1102
+ let path = parentPath;
1102
1103
  const meta2 = this.metadata.find(prop.type);
1103
1104
  const childOrder = orderHint[prop.name];
1104
- let path = `${parentPath}.${propName}`;
1105
+ if (![core_1.ReferenceKind.MANY_TO_ONE, core_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind) || !prop.owner || core_1.Utils.isPlainObject(childOrder)) {
1106
+ path += `.${propName}`;
1107
+ }
1105
1108
  if (prop.kind === core_1.ReferenceKind.MANY_TO_MANY && typeof childOrder !== 'object') {
1106
1109
  path += '[pivot]';
1107
1110
  }
@@ -1,4 +1,4 @@
1
- import { type EntityMetadata, type EntityProperty, type Primary } from '@mikro-orm/core';
1
+ import { type EntityMetadata, type EntityProperty, type Primary, type Transaction } from '@mikro-orm/core';
2
2
  import { type AbstractSqlDriver } from './AbstractSqlDriver';
3
3
  export declare class PivotCollectionPersister<Entity extends object> {
4
4
  private readonly meta;
@@ -10,7 +10,7 @@ export declare class PivotCollectionPersister<Entity extends object> {
10
10
  private readonly deletes;
11
11
  private readonly batchSize;
12
12
  private order;
13
- constructor(meta: EntityMetadata<Entity>, driver: AbstractSqlDriver, ctx?: any, schema?: string | undefined);
13
+ constructor(meta: EntityMetadata<Entity>, driver: AbstractSqlDriver, ctx?: Transaction | undefined, schema?: string | undefined);
14
14
  enqueueUpdate(prop: EntityProperty<Entity>, insertDiff: Primary<Entity>[][], deleteDiff: Primary<Entity>[][] | boolean, pks: Primary<Entity>[]): void;
15
15
  private enqueueInsert;
16
16
  private enqueueDelete;
@@ -78,7 +78,7 @@ class MySqlSchemaHelper extends SchemaHelper_1.SchemaHelper {
78
78
  nullif(table_schema, schema()) as schema_name,
79
79
  column_name as column_name,
80
80
  column_default as column_default,
81
- column_comment as column_comment,
81
+ nullif(column_comment, '') as column_comment,
82
82
  is_nullable as is_nullable,
83
83
  data_type as data_type,
84
84
  column_type as column_type,
@@ -30,6 +30,9 @@ export declare abstract class BaseSqlitePlatform extends AbstractSqlPlatform {
30
30
  }): string;
31
31
  getFloatDeclarationSQL(): string;
32
32
  getBooleanTypeDeclarationSQL(): string;
33
+ getCharTypeDeclarationSQL(column: {
34
+ length?: number;
35
+ }): string;
33
36
  getVarcharTypeDeclarationSQL(column: {
34
37
  length?: number;
35
38
  }): string;
@@ -38,6 +38,9 @@ class BaseSqlitePlatform extends AbstractSqlPlatform_1.AbstractSqlPlatform {
38
38
  getBooleanTypeDeclarationSQL() {
39
39
  return 'integer';
40
40
  }
41
+ getCharTypeDeclarationSQL(column) {
42
+ return 'text';
43
+ }
41
44
  getVarcharTypeDeclarationSQL(column) {
42
45
  return 'text';
43
46
  }
@@ -1,7 +1,7 @@
1
1
  import type { Connection, Dictionary } from '@mikro-orm/core';
2
2
  import type { AbstractSqlConnection } from '../../AbstractSqlConnection';
3
3
  import { SchemaHelper } from '../../schema/SchemaHelper';
4
- import type { CheckDef, Column, IndexDef } from '../../typings';
4
+ import type { CheckDef, Column, IndexDef, TableDifference } from '../../typings';
5
5
  export declare abstract class BaseSqliteSchemaHelper extends SchemaHelper {
6
6
  disableForeignKeysSQL(): string;
7
7
  enableForeignKeysSQL(): string;
@@ -24,4 +24,5 @@ export declare abstract class BaseSqliteSchemaHelper extends SchemaHelper {
24
24
  * Implicit indexes will be ignored when diffing
25
25
  */
26
26
  isImplicitIndex(name: string): boolean;
27
+ getAlterTable(changedTable: TableDifference, wrap?: boolean): Promise<string>;
27
28
  }
@@ -168,5 +168,22 @@ class BaseSqliteSchemaHelper extends SchemaHelper_1.SchemaHelper {
168
168
  // Ignore indexes with reserved names, e.g. autoindexes
169
169
  return name.startsWith('sqlite_');
170
170
  }
171
+ async getAlterTable(changedTable, wrap) {
172
+ wrap ??= this.options.disableForeignKeys;
173
+ const tempName = `${(changedTable.toTable.name)}__temp_alter`;
174
+ const quotedName = this.platform.quoteIdentifier(changedTable.toTable.name);
175
+ const quotedTempName = this.platform.quoteIdentifier(tempName);
176
+ const createSql = await this.dump(this.createTable(changedTable.toTable), '');
177
+ const [first, ...rest] = createSql.split('\n');
178
+ return [
179
+ 'pragma foreign_keys = off;',
180
+ first.replace(`create table ${quotedName}`, `create table ${quotedTempName}`),
181
+ `insert into ${quotedTempName} select * from ${quotedName};`,
182
+ `drop table ${quotedName};`,
183
+ `alter table ${quotedTempName} rename to ${quotedName};`,
184
+ ...rest,
185
+ 'pragma foreign_keys = on;',
186
+ ].join('\n');
187
+ }
171
188
  }
172
189
  exports.BaseSqliteSchemaHelper = BaseSqliteSchemaHelper;
@@ -2,5 +2,10 @@ import { MonkeyPatchable } from '../../MonkeyPatchable';
2
2
  export declare class LibSqlKnexDialect extends MonkeyPatchable.BetterSqlite3Dialect {
3
3
  get driverName(): string;
4
4
  _driver(): any;
5
+ _query(this: any, connection: any, obj: any): Promise<any>;
6
+ acquireRawConnection(this: any): Promise<any>;
5
7
  tableCompiler(): any;
8
+ validateConnection(connection: any): boolean;
9
+ private getCallMethod;
10
+ private isRunQuery;
6
11
  }
@@ -10,9 +10,76 @@ class LibSqlKnexDialect extends MonkeyPatchable_1.MonkeyPatchable.BetterSqlite3D
10
10
  _driver() {
11
11
  return require('libsql');
12
12
  }
13
+ async _query(connection, obj) {
14
+ /* istanbul ignore next */
15
+ if (!obj.sql) {
16
+ throw new Error('The query is empty');
17
+ }
18
+ /* istanbul ignore next */
19
+ if (!connection) {
20
+ throw new Error('No connection provided');
21
+ }
22
+ const callMethod = this.getCallMethod(obj);
23
+ const statement = connection.prepare(obj.sql);
24
+ const bindings = this._formatBindings(obj.bindings);
25
+ const response = await statement[callMethod](bindings);
26
+ obj.response = response;
27
+ obj.context = {
28
+ lastID: response.lastInsertRowid,
29
+ changes: response.changes,
30
+ };
31
+ return obj;
32
+ }
33
+ async acquireRawConnection() {
34
+ const connection = new this.driver(this.connectionSettings.filename, {
35
+ ...this.connectionSettings,
36
+ });
37
+ connection.__created = Date.now();
38
+ return connection;
39
+ }
13
40
  tableCompiler() {
14
41
  // eslint-disable-next-line prefer-rest-params
15
42
  return new SqliteTableCompiler_1.SqliteTableCompiler(this, ...arguments);
16
43
  }
44
+ validateConnection(connection) {
45
+ if (connection.memory) {
46
+ return true;
47
+ }
48
+ /* istanbul ignore next */
49
+ return connection.__created > Date.now() - 10_000;
50
+ }
51
+ getCallMethod(obj) {
52
+ if (obj.method === 'raw') {
53
+ const query = obj.sql.trim().toLowerCase();
54
+ if ((query.startsWith('insert into') || query.startsWith('update ')) && query.includes(' returning ')) {
55
+ return 'all';
56
+ }
57
+ if (this.isRunQuery(query)) {
58
+ return 'run';
59
+ }
60
+ }
61
+ /* istanbul ignore next */
62
+ switch (obj.method) {
63
+ case 'insert':
64
+ case 'update':
65
+ return obj.returning ? 'all' : 'run';
66
+ case 'counter':
67
+ case 'del':
68
+ return 'run';
69
+ default:
70
+ return 'all';
71
+ }
72
+ }
73
+ isRunQuery(query) {
74
+ query = query.trim().toLowerCase();
75
+ /* istanbul ignore next */
76
+ if ((query.startsWith('insert into') || query.startsWith('update ')) && query.includes(' returning ')) {
77
+ return false;
78
+ }
79
+ return query.startsWith('insert into') ||
80
+ query.startsWith('update') ||
81
+ query.startsWith('delete') ||
82
+ query.startsWith('truncate');
83
+ }
17
84
  }
18
85
  exports.LibSqlKnexDialect = LibSqlKnexDialect;
package/index.mjs CHANGED
@@ -33,6 +33,7 @@ export const ChangeSet = mod.ChangeSet;
33
33
  export const ChangeSetComputer = mod.ChangeSetComputer;
34
34
  export const ChangeSetPersister = mod.ChangeSetPersister;
35
35
  export const ChangeSetType = mod.ChangeSetType;
36
+ export const CharacterType = mod.CharacterType;
36
37
  export const Check = mod.Check;
37
38
  export const CheckConstraintViolationException = mod.CheckConstraintViolationException;
38
39
  export const Collection = mod.Collection;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/knex",
3
- "version": "6.2.10-dev.9",
3
+ "version": "6.2.10-dev.90",
4
4
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -66,7 +66,7 @@
66
66
  "@mikro-orm/core": "^6.2.9"
67
67
  },
68
68
  "peerDependencies": {
69
- "@mikro-orm/core": "6.2.10-dev.9",
69
+ "@mikro-orm/core": "6.2.10-dev.90",
70
70
  "better-sqlite3": "*",
71
71
  "libsql": "*",
72
72
  "mariadb": "*"
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { inspect } from 'util';
3
2
  import { type EntityKey, type EntityProperty, type MetadataStorage } from '@mikro-orm/core';
4
3
  import type { ICriteriaNode, ICriteriaNodeProcessOptions, IQueryBuilder } from '../typings';
@@ -70,7 +70,8 @@ class ObjectCriteriaNode extends CriteriaNode_1.CriteriaNode {
70
70
  const primaryKey = this.key && this.metadata.find(this.entityName).primaryKeys.includes(field);
71
71
  if (childNode.shouldInline(payload)) {
72
72
  const childAlias = qb.getAliasForJoinPath(childNode.getPath(), options);
73
- this.inlineChildPayload(o, payload, field, alias, childAlias);
73
+ const a = qb.helper.isTableNameAliasRequired(qb.type) ? alias : undefined;
74
+ this.inlineChildPayload(o, payload, field, a, childAlias);
74
75
  }
75
76
  else if (childNode.shouldRename(payload)) {
76
77
  o[childNode.renameFieldToPK(qb)] = payload;
@@ -149,7 +150,6 @@ class ObjectCriteriaNode extends CriteriaNode_1.CriteriaNode {
149
150
  o[k] = payload[k];
150
151
  }
151
152
  else {
152
- o[`${childAlias}.${k}`] = payload[k];
153
153
  o[this.aliased(k, childAlias)] = payload[k];
154
154
  }
155
155
  }
@@ -1,7 +1,6 @@
1
- /// <reference types="node" />
2
1
  import { inspect } from 'util';
3
2
  import type { Knex } from 'knex';
4
- import { type AnyEntity, type ConnectionType, type Dictionary, type EntityData, type EntityKey, type EntityMetadata, type EntityName, type EntityProperty, type FlushMode, type GroupOperator, type Loaded, LockMode, type LoggingOptions, type MetadataStorage, type ObjectQuery, PopulateHint, type PopulateOptions, type QBFilterQuery, type QBQueryOrderMap, QueryFlag, type QueryOrderMap, type QueryResult, type RequiredEntityData, type ExpandProperty } from '@mikro-orm/core';
3
+ import { type AnyEntity, type ConnectionType, type Dictionary, type EntityData, type EntityKey, type EntityMetadata, type EntityName, type EntityProperty, type FlushMode, type GroupOperator, type Loaded, LockMode, type LoggingOptions, type MetadataStorage, type ObjectQuery, PopulateHint, type PopulateOptions, type QBFilterQuery, type QBQueryOrderMap, QueryFlag, type QueryOrderMap, type QueryResult, RawQueryFragment, type RequiredEntityData, type ExpandProperty } from '@mikro-orm/core';
5
4
  import { JoinType, QueryType } from './enums';
6
5
  import type { AbstractSqlDriver } from '../AbstractSqlDriver';
7
6
  import { type Alias, QueryBuilderHelper } from './QueryBuilderHelper';
@@ -54,9 +53,9 @@ export type QBField2<Entity, RootAlias extends string, Context> = (EntityKey<Ent
54
53
  export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias extends string = never, Hint extends string = never, Context extends object = never> {
55
54
  protected readonly metadata: MetadataStorage;
56
55
  protected readonly driver: AbstractSqlDriver;
57
- protected readonly context?: Knex.Transaction<any, any[]> | undefined;
56
+ protected readonly context?: Knex.Transaction | undefined;
58
57
  protected connectionType?: ConnectionType | undefined;
59
- protected em?: SqlEntityManager<AbstractSqlDriver<import("..").AbstractSqlConnection, AbstractSqlPlatform>> | undefined;
58
+ protected em?: SqlEntityManager | undefined;
60
59
  protected loggerContext?: (LoggingOptions & Dictionary) | undefined;
61
60
  get mainAlias(): Alias<Entity>;
62
61
  get alias(): string;
@@ -88,7 +87,7 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
88
87
  protected _having: Dictionary;
89
88
  protected _returning?: Field<Entity>[];
90
89
  protected _onConflict?: {
91
- fields: string[];
90
+ fields: string[] | RawQueryFragment;
92
91
  ignore?: boolean;
93
92
  merge?: EntityData<Entity> | Field<Entity>[];
94
93
  where?: QBFilterQuery<Entity>;
@@ -119,7 +118,7 @@ export declare class QueryBuilder<Entity extends object = AnyEntity, RootAlias e
119
118
  /**
120
119
  * @internal
121
120
  */
122
- constructor(entityName: EntityName<Entity> | QueryBuilder<Entity, any, any>, metadata: MetadataStorage, driver: AbstractSqlDriver, context?: Knex.Transaction<any, any[]> | undefined, alias?: string, connectionType?: ConnectionType | undefined, em?: SqlEntityManager<AbstractSqlDriver<import("..").AbstractSqlConnection, AbstractSqlPlatform>> | undefined, loggerContext?: (LoggingOptions & Dictionary) | undefined);
121
+ constructor(entityName: EntityName<Entity> | QueryBuilder<Entity, any, any>, metadata: MetadataStorage, driver: AbstractSqlDriver, context?: Knex.Transaction | undefined, alias?: string, connectionType?: ConnectionType | undefined, em?: SqlEntityManager | undefined, loggerContext?: (LoggingOptions & Dictionary) | undefined);
123
122
  select(fields: Field<Entity> | Field<Entity>[], distinct?: boolean): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
124
123
  addSelect(fields: Field<Entity> | Field<Entity>[]): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
125
124
  distinct(): SelectQueryBuilder<Entity, RootAlias, Hint, Context>;
@@ -348,11 +348,13 @@ class QueryBuilder {
348
348
  this.ensureNotFinalized();
349
349
  this._onConflict ??= [];
350
350
  this._onConflict.push({
351
- fields: core_1.Utils.asArray(fields).flatMap(f => {
352
- const key = f.toString();
353
- /* istanbul ignore next */
354
- return meta.properties[key]?.fieldNames ?? [key];
355
- }),
351
+ fields: core_1.Utils.isRawSql(fields)
352
+ ? fields
353
+ : core_1.Utils.asArray(fields).flatMap(f => {
354
+ const key = f.toString();
355
+ /* istanbul ignore next */
356
+ return meta.properties[key]?.fieldNames ?? [key];
357
+ }),
356
358
  });
357
359
  return this;
358
360
  }
@@ -1222,7 +1224,7 @@ class QueryBuilder {
1222
1224
  const prop = this.helper.getProperty(f, a);
1223
1225
  const type = this.platform.castColumn(prop);
1224
1226
  const fieldName = this.helper.mapper(field, this.type, undefined, null);
1225
- if (!prop?.persist && !prop?.formula && !pks.includes(fieldName)) {
1227
+ if (!prop?.persist && !prop?.formula && !prop?.hasConvertToJSValueSQL && !pks.includes(fieldName)) {
1226
1228
  addToSelect.push(fieldName);
1227
1229
  }
1228
1230
  const key = (0, core_1.raw)(`min(${this.knex.ref(fieldName)}${type})`);
@@ -1245,8 +1247,10 @@ class QueryBuilder {
1245
1247
  }
1246
1248
  return false;
1247
1249
  });
1250
+ /* istanbul ignore next */
1248
1251
  if (field instanceof core_1.RawQueryFragment) {
1249
- knexQuery.select(this.platform.formatQuery(field.sql, field.params));
1252
+ const sql = this.platform.formatQuery(field.sql, field.params);
1253
+ knexQuery.select(this.knex.raw(sql));
1250
1254
  }
1251
1255
  else if (field) {
1252
1256
  knexQuery.select(field);
@@ -1,5 +1,5 @@
1
1
  import type { Knex } from 'knex';
2
- import { type Dictionary, type EntityData, type EntityKey, type EntityMetadata, type EntityProperty, type FlatQueryOrderMap, LockMode, type QBFilterQuery } from '@mikro-orm/core';
2
+ import { type Dictionary, type EntityData, type EntityKey, type EntityMetadata, type EntityProperty, type FlatQueryOrderMap, LockMode, type QBFilterQuery, RawQueryFragment } from '@mikro-orm/core';
3
3
  import { JoinType, QueryType } from './enums';
4
4
  import type { Field, JoinOptions } from '../typings';
5
5
  import type { AbstractSqlDriver } from '../AbstractSqlDriver';
@@ -34,7 +34,7 @@ export declare class QueryBuilderHelper {
34
34
  isSimpleRegExp(re: any): re is RegExp;
35
35
  getRegExpParam(re: RegExp): string;
36
36
  appendOnConflictClause<T>(type: QueryType, onConflict: {
37
- fields: string[];
37
+ fields: string[] | RawQueryFragment;
38
38
  ignore?: boolean;
39
39
  merge?: EntityData<T> | Field<T>[];
40
40
  where?: QBFilterQuery<T>;
@@ -67,7 +67,8 @@ class QueryBuilderHelper {
67
67
  }
68
68
  const rawField = core_1.RawQueryFragment.getKnownFragment(field);
69
69
  if (rawField) {
70
- return this.knex.raw(rawField.sql, rawField.params);
70
+ // sometimes knex is confusing the binding positions, we need to interpolate early
71
+ return this.knex.raw(this.platform.formatQuery(rawField.sql, rawField.params));
71
72
  }
72
73
  const [a, f] = this.splitField(field);
73
74
  const prop = this.getProperty(f, a);
@@ -194,7 +195,8 @@ class QueryBuilderHelper {
194
195
  join.primaryKeys.forEach((primaryKey, idx) => {
195
196
  const right = `${join.alias}.${join.joinColumns[idx]}`;
196
197
  if (join.prop.formula) {
197
- const left = join.prop.formula(join.ownerAlias);
198
+ const alias = this.platform.quoteIdentifier(join.ownerAlias);
199
+ const left = join.prop.formula(alias);
198
200
  conditions.push(`${left} = ${this.knex.ref(right)}`);
199
201
  return;
200
202
  }
@@ -352,7 +354,16 @@ class QueryBuilderHelper {
352
354
  }
353
355
  appendOnConflictClause(type, onConflict, qb) {
354
356
  onConflict.forEach(item => {
355
- const sub = item.fields.length > 0 ? qb.onConflict(item.fields) : qb.onConflict();
357
+ let sub;
358
+ if (core_1.Utils.isRawSql(item.fields)) {
359
+ sub = qb.onConflict(this.knex.raw(item.fields.sql, item.fields.params));
360
+ }
361
+ else if (item.fields.length > 0) {
362
+ sub = qb.onConflict(item.fields);
363
+ }
364
+ else {
365
+ sub = qb.onConflict();
366
+ }
356
367
  core_1.Utils.runIfNotEmpty(() => sub.ignore(), item.ignore);
357
368
  core_1.Utils.runIfNotEmpty(() => {
358
369
  let mergeParam = item.merge;
@@ -442,6 +453,9 @@ class QueryBuilderHelper {
442
453
  const tmp = value[op].length === 1 && core_1.Utils.isPlainObject(value[op][0]) ? fields.map(f => value[op][0][f]) : value[op];
443
454
  value[op] = this.knex.raw(`(${fields.map(() => '?').join(', ')})`, tmp);
444
455
  }
456
+ if (value[op] instanceof core_1.RawQueryFragment) {
457
+ value[op] = this.knex.raw(value[op].sql, value[op].params);
458
+ }
445
459
  if (this.subQueries[key]) {
446
460
  return void qb[m](this.knex.raw(`(${this.subQueries[key]})`), replacement, value[op]);
447
461
  }
@@ -25,7 +25,7 @@ export declare class DatabaseTable {
25
25
  removeColumn(name: string): void;
26
26
  getIndexes(): IndexDef[];
27
27
  getChecks(): CheckDef[];
28
- init(cols: Column[], indexes: IndexDef[] | undefined, checks: CheckDef<unknown>[] | undefined, pks: string[], fks?: Dictionary<ForeignKey>, enums?: Dictionary<string[]>): void;
28
+ init(cols: Column[], indexes: IndexDef[] | undefined, checks: CheckDef[] | undefined, pks: string[], fks?: Dictionary<ForeignKey>, enums?: Dictionary<string[]>): void;
29
29
  addColumn(column: Column): void;
30
30
  addColumnFromProperty(prop: EntityProperty, meta: EntityMetadata, config: Configuration): void;
31
31
  private getIndexName;
@@ -70,17 +70,11 @@ class DatabaseTable {
70
70
  prop.length = undefined;
71
71
  }
72
72
  }
73
- if (mappedType instanceof core_1.DateTimeType || mappedType instanceof core_1.IntervalType) {
74
- const match = prop.columnTypes[idx].match(/\w+\((\d+)\)/);
75
- if (match) {
76
- prop.length ??= +match[1];
77
- }
78
- else {
79
- prop.length ??= this.platform.getDefaultDateTimeLength();
80
- }
81
- }
82
73
  if (prop.length == null && prop.columnTypes[idx]) {
83
74
  prop.length = this.platform.getSchemaHelper().inferLengthFromColumnType(prop.columnTypes[idx]);
75
+ if (typeof mappedType.getDefaultLength !== 'undefined') {
76
+ prop.length ??= mappedType.getDefaultLength(this.platform);
77
+ }
84
78
  }
85
79
  const primary = !meta.compositePK && !!prop.primary && prop.kind === core_1.ReferenceKind.SCALAR && this.platform.isNumericColumn(mappedType);
86
80
  this.columns[field] = {
@@ -171,7 +165,7 @@ class DatabaseTable {
171
165
  getEntityDeclaration(namingStrategy, schemaHelper, scalarPropertiesForRelations) {
172
166
  const { fksOnColumnProps, fksOnStandaloneProps, columnFks, fkIndexes, nullableForeignKeys, skippedColumnNames, } = this.foreignKeysToProps(namingStrategy, scalarPropertiesForRelations);
173
167
  const name = namingStrategy.getEntityName(this.name, this.schema);
174
- const schema = new core_1.EntitySchema({ name, collection: this.name, schema: this.schema });
168
+ const schema = new core_1.EntitySchema({ name, collection: this.name, schema: this.schema, comment: this.comment });
175
169
  const compositeFkIndexes = {};
176
170
  const compositeFkUniques = {};
177
171
  const potentiallyUnmappedIndexes = this.indexes.filter(index => !index.primary // Skip primary index. Whether it's in use by scalar column or FK, it's already mapped.
@@ -505,6 +499,7 @@ class DatabaseTable {
505
499
  columnOptions.length = column.length;
506
500
  columnOptions.precision = column.precision;
507
501
  columnOptions.scale = column.scale;
502
+ columnOptions.comment = column.comment;
508
503
  columnOptions.enum = !!column.enumItems?.length;
509
504
  columnOptions.items = column.enumItems;
510
505
  }
@@ -542,7 +537,10 @@ class DatabaseTable {
542
537
  }
543
538
  return {
544
539
  name: prop,
545
- type: fk ? runtimeType : (core_1.Utils.entries(core_1.t).find(([k, v]) => Object.getPrototypeOf(column.mappedType) === v.prototype)?.[0] ?? runtimeType),
540
+ type: fk ? runtimeType : (core_1.Utils.keys(core_1.t).find(k => {
541
+ const typeInCoreMap = this.platform.getMappedType(k);
542
+ return (typeInCoreMap !== core_1.Type.getType(core_1.UnknownType) || k === 'unknown') && typeInCoreMap === column.mappedType;
543
+ }) ?? runtimeType),
546
544
  runtimeType,
547
545
  kind,
548
546
  generated: column.generated,
@@ -558,6 +556,7 @@ class DatabaseTable {
558
556
  length: column.length,
559
557
  precision: column.precision,
560
558
  scale: column.scale,
559
+ comment: column.comment,
561
560
  index: index ? index.keyName : undefined,
562
561
  unique: unique ? unique.keyName : undefined,
563
562
  enum: !!column.enumItems?.length,
@@ -601,8 +600,7 @@ class DatabaseTable {
601
600
  // If this column is using an enum.
602
601
  if (column.enumItems?.length) {
603
602
  // We will create a new enum name for this type and set it as the property type as well.
604
- // The enum name will be a concatenation of the table name and the column name.
605
- return namingStrategy.getClassName(this.name + '_' + column.name, '_');
603
+ return namingStrategy.getEnumClassName(column.name, this.name, this.schema);
606
604
  }
607
605
  return column.mappedType?.runtimeType ?? 'unknown';
608
606
  }
@@ -369,7 +369,10 @@ class SchemaComparator {
369
369
  }
370
370
  const defaultRule = ['restrict', 'no action'];
371
371
  const rule = (key, method) => {
372
- return (key[method] ?? defaultRule[0]).toLowerCase().replace(defaultRule[1], defaultRule[0]);
372
+ return (key[method] ?? defaultRule[0])
373
+ .toLowerCase()
374
+ .replace(defaultRule[1], defaultRule[0])
375
+ .replace(/"/g, '');
373
376
  };
374
377
  const compare = (method) => rule(key1, method) === rule(key2, method);
375
378
  return !compare('updateRule') || !compare('deleteRule');
@@ -415,7 +418,8 @@ class SchemaComparator {
415
418
  log(`'unsigned' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
416
419
  changedProperties.add('unsigned');
417
420
  }
418
- if (!this.hasSameDefaultValue(fromColumn, toColumn)) {
421
+ if (!(fromColumn.ignoreSchemaChanges?.includes('default') ||
422
+ toColumn.ignoreSchemaChanges?.includes('default')) && !this.hasSameDefaultValue(fromColumn, toColumn)) {
419
423
  log(`'default' changed for column ${tableName}.${fromColumn.name}`, { fromColumn, toColumn });
420
424
  changedProperties.add('default');
421
425
  }
@@ -2,7 +2,7 @@ import { type Connection, type Dictionary } from '@mikro-orm/core';
2
2
  import type { Knex } from 'knex';
3
3
  import type { AbstractSqlConnection } from '../AbstractSqlConnection';
4
4
  import type { AbstractSqlPlatform } from '../AbstractSqlPlatform';
5
- import type { CheckDef, Column, IndexDef, Table, TableDifference } from '../typings';
5
+ import type { CheckDef, Column, ForeignKey, IndexDef, Table, TableDifference } from '../typings';
6
6
  import type { DatabaseSchema } from './DatabaseSchema';
7
7
  import type { DatabaseTable } from './DatabaseTable';
8
8
  export declare abstract class SchemaHelper {
@@ -58,4 +58,20 @@ export declare abstract class SchemaHelper {
58
58
  * Uses `raw` method injected in `AbstractSqlConnection` to allow adding custom queries inside alter statements.
59
59
  */
60
60
  pushTableQuery(table: Knex.TableBuilder, expression: string, grouping?: string): void;
61
+ dump(builder: Knex.SchemaBuilder | string, append: string): Promise<string>;
62
+ createTable(tableDef: DatabaseTable, alter?: boolean): Knex.SchemaBuilder;
63
+ createForeignKey(table: Knex.CreateTableBuilder, foreignKey: ForeignKey, schema?: string): void;
64
+ splitTableName(name: string): [string | undefined, string];
65
+ getReferencedTableName(referencedTableName: string, schema?: string): string;
66
+ createIndex(table: Knex.CreateTableBuilder, index: IndexDef, tableDef: DatabaseTable, createPrimary?: boolean): void;
67
+ createCheck(table: Knex.CreateTableBuilder, check: CheckDef): void;
68
+ createSchemaBuilder(schema?: string): Knex.SchemaBuilder;
69
+ getAlterTable?(changedTable: TableDifference, wrap?: boolean): Promise<string>;
70
+ get knex(): Knex;
71
+ get options(): {
72
+ disableForeignKeys?: boolean;
73
+ createForeignKeyConstraints?: boolean;
74
+ ignoreSchema?: string[];
75
+ managementDbName?: string;
76
+ };
61
77
  }
@@ -30,7 +30,11 @@ class SchemaHelper {
30
30
  return core_1.Utils.flatten(pks);
31
31
  }
32
32
  inferLengthFromColumnType(type) {
33
- return undefined;
33
+ const match = type.match(/^\w+\s*(?:\(\s*(\d+)\s*\)|$)/);
34
+ if (!match) {
35
+ return;
36
+ }
37
+ return +match[1];
34
38
  }
35
39
  async getForeignKeys(connection, tableName, schemaName) {
36
40
  const fks = await connection.execute(this.getForeignKeysSQL(tableName, schemaName));
@@ -61,8 +65,7 @@ class SchemaHelper {
61
65
  }
62
66
  async loadInformationSchema(schema, connection, tables, schemas) {
63
67
  for (const t of tables) {
64
- const table = schema.addTable(t.table_name, t.schema_name);
65
- table.comment = t.table_comment;
68
+ const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
66
69
  const cols = await this.getColumns(connection, table.name, table.schema);
67
70
  const indexes = await this.getIndexes(connection, table.name, table.schema);
68
71
  const checks = await this.getChecks(connection, table.name, table.schema, cols);
@@ -273,5 +276,137 @@ class SchemaHelper {
273
276
  pushTableQuery(table, expression, grouping = 'alterTable') {
274
277
  table._statements.push({ grouping, method: 'raw', args: [expression] });
275
278
  }
279
+ async dump(builder, append) {
280
+ if (typeof builder === 'string') {
281
+ return builder ? builder + (builder.endsWith(';') ? '' : ';') + append : '';
282
+ }
283
+ const sql = await builder.generateDdlCommands();
284
+ const queries = [...sql.pre, ...sql.sql, ...sql.post];
285
+ if (queries.length === 0) {
286
+ return '';
287
+ }
288
+ const dump = `${queries.map(q => typeof q === 'object' ? q.sql : q).join(';\n')};${append}`;
289
+ const tmp = dump.replace(/pragma table_.+/ig, '').replace(/\n\n+/g, '\n').trim();
290
+ return tmp ? tmp + append : '';
291
+ }
292
+ createTable(tableDef, alter) {
293
+ return this.createSchemaBuilder(tableDef.schema).createTable(tableDef.name, table => {
294
+ tableDef.getColumns().forEach(column => {
295
+ const col = this.createTableColumn(table, column, tableDef, undefined, alter);
296
+ this.configureColumn(column, col, this.knex);
297
+ });
298
+ for (const index of tableDef.getIndexes()) {
299
+ const createPrimary = !tableDef.getColumns().some(c => c.autoincrement && c.primary) || this.hasNonDefaultPrimaryKeyName(tableDef);
300
+ this.createIndex(table, index, tableDef, createPrimary);
301
+ }
302
+ for (const check of tableDef.getChecks()) {
303
+ this.createCheck(table, check);
304
+ }
305
+ if (tableDef.comment) {
306
+ const comment = this.platform.quoteValue(tableDef.comment).replace(/^'|'$/g, '');
307
+ table.comment(comment);
308
+ }
309
+ if (!this.supportsSchemaConstraints()) {
310
+ for (const fk of Object.values(tableDef.getForeignKeys())) {
311
+ this.createForeignKey(table, fk);
312
+ }
313
+ }
314
+ this.finalizeTable(table, this.platform.getConfig().get('charset'), this.platform.getConfig().get('collate'));
315
+ });
316
+ }
317
+ createForeignKey(table, foreignKey, schema) {
318
+ if (!this.options.createForeignKeyConstraints) {
319
+ return;
320
+ }
321
+ const builder = table
322
+ .foreign(foreignKey.columnNames, foreignKey.constraintName)
323
+ .references(foreignKey.referencedColumnNames)
324
+ .inTable(this.getReferencedTableName(foreignKey.referencedTableName, schema))
325
+ .withKeyName(foreignKey.constraintName);
326
+ if (foreignKey.localTableName !== foreignKey.referencedTableName || this.platform.supportsMultipleCascadePaths()) {
327
+ if (foreignKey.updateRule) {
328
+ builder.onUpdate(foreignKey.updateRule);
329
+ }
330
+ if (foreignKey.deleteRule) {
331
+ builder.onDelete(foreignKey.deleteRule);
332
+ }
333
+ }
334
+ if (foreignKey.deferMode) {
335
+ builder.deferrable(foreignKey.deferMode);
336
+ }
337
+ }
338
+ splitTableName(name) {
339
+ const parts = name.split('.');
340
+ const tableName = parts.pop();
341
+ const schemaName = parts.pop();
342
+ return [schemaName, tableName];
343
+ }
344
+ getReferencedTableName(referencedTableName, schema) {
345
+ const [schemaName, tableName] = this.splitTableName(referencedTableName);
346
+ schema = schemaName ?? schema ?? this.platform.getConfig().get('schema');
347
+ /* istanbul ignore next */
348
+ if (schema && schemaName === '*') {
349
+ return `${schema}.${referencedTableName.replace(/^\*\./, '')}`;
350
+ }
351
+ if (!schemaName || schemaName === this.platform.getDefaultSchemaName()) {
352
+ return tableName;
353
+ }
354
+ return `${schemaName}.${tableName}`;
355
+ }
356
+ createIndex(table, index, tableDef, createPrimary = false) {
357
+ if (index.primary && !createPrimary) {
358
+ return;
359
+ }
360
+ if (index.expression) {
361
+ this.pushTableQuery(table, index.expression);
362
+ }
363
+ else if (index.primary) {
364
+ const keyName = this.hasNonDefaultPrimaryKeyName(tableDef) ? index.keyName : undefined;
365
+ table.primary(index.columnNames, keyName);
366
+ }
367
+ else if (index.unique) {
368
+ // JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
369
+ if (index.columnNames.some(column => column.includes('.'))) {
370
+ const columns = this.platform.getJsonIndexDefinition(index);
371
+ table.index(columns.map(column => this.knex.raw(column)), index.keyName, { indexType: 'unique' });
372
+ }
373
+ else {
374
+ table.unique(index.columnNames, { indexName: index.keyName, deferrable: index.deferMode });
375
+ }
376
+ }
377
+ else if (index.type === 'fulltext') {
378
+ const columns = index.columnNames.map(name => ({ name, type: tableDef.getColumn(name).type }));
379
+ if (this.platform.supportsCreatingFullTextIndex()) {
380
+ this.pushTableQuery(table, this.platform.getFullTextIndexExpression(index.keyName, tableDef.schema, tableDef.name, columns));
381
+ }
382
+ }
383
+ else {
384
+ // JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
385
+ if (index.columnNames.some(column => column.includes('.'))) {
386
+ const columns = this.platform.getJsonIndexDefinition(index);
387
+ table.index(columns.map(column => this.knex.raw(column)), index.keyName, index.type);
388
+ }
389
+ else {
390
+ table.index(index.columnNames, index.keyName, index.type);
391
+ }
392
+ }
393
+ }
394
+ createCheck(table, check) {
395
+ table.check(check.expression, {}, check.name);
396
+ }
397
+ createSchemaBuilder(schema) {
398
+ const builder = this.knex.schema;
399
+ if (schema && schema !== this.platform.getDefaultSchemaName()) {
400
+ builder.withSchema(schema);
401
+ }
402
+ return builder;
403
+ }
404
+ get knex() {
405
+ const connection = this.platform.getConfig().getDriver().getConnection();
406
+ return connection.getKnex();
407
+ }
408
+ get options() {
409
+ return this.platform.getConfig().get('schemaGenerator');
410
+ }
276
411
  }
277
412
  exports.SchemaHelper = SchemaHelper;
@@ -5,10 +5,10 @@ import type { AbstractSqlDriver } from '../AbstractSqlDriver';
5
5
  export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<AbstractSqlDriver> implements ISchemaGenerator {
6
6
  protected readonly helper: import("./SchemaHelper").SchemaHelper;
7
7
  protected readonly options: {
8
- disableForeignKeys?: boolean | undefined;
9
- createForeignKeyConstraints?: boolean | undefined;
10
- ignoreSchema?: string[] | undefined;
11
- managementDbName?: string | undefined;
8
+ disableForeignKeys?: boolean;
9
+ createForeignKeyConstraints?: boolean;
10
+ ignoreSchema?: string[];
11
+ managementDbName?: string;
12
12
  };
13
13
  protected lastEnsuredDatabase?: string;
14
14
  static register(orm: MikroORM): void;
@@ -38,14 +38,11 @@ export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<Abstract
38
38
  dropTables?: boolean;
39
39
  schema?: string;
40
40
  }): Promise<string>;
41
- private getReferencedTableName;
42
- private createForeignKey;
43
41
  /**
44
42
  * We need to drop foreign keys first for all tables to allow dropping PK constraints.
45
43
  */
46
44
  private preAlterTable;
47
45
  private postAlterTable;
48
- private splitTableName;
49
46
  private alterTable;
50
47
  /**
51
48
  * creates new database and connects to it
@@ -57,11 +54,7 @@ export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<Abstract
57
54
  ctx?: Transaction;
58
55
  }): Promise<void>;
59
56
  private wrapSchema;
60
- private createSchemaBuilder;
61
- private createTable;
62
- private createIndex;
63
57
  private dropIndex;
64
- private createCheck;
65
58
  private dropCheck;
66
59
  private dropTable;
67
60
  private createForeignKeys;
@@ -59,7 +59,7 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
59
59
  continue;
60
60
  }
61
61
  const sql = this.helper.getCreateNamespaceSQL(namespace);
62
- ret += await this.dump(this.knex.schema.raw(sql), '\n');
62
+ ret += await this.dump(sql, '\n');
63
63
  }
64
64
  if (this.platform.supportsNativeEnums()) {
65
65
  const created = [];
@@ -70,14 +70,14 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
70
70
  }
71
71
  created.push(enumName);
72
72
  const sql = this.helper.getCreateNativeEnumSQL(enumOptions.name, enumOptions.items, this.getSchemaName(enumOptions, options));
73
- ret += await this.dump(this.knex.schema.raw(sql), '\n');
73
+ ret += await this.dump(sql, '\n');
74
74
  }
75
75
  }
76
76
  for (const tableDef of toSchema.getTables()) {
77
- ret += await this.dump(this.createTable(tableDef));
77
+ ret += await this.dump(this.helper.createTable(tableDef));
78
78
  }
79
79
  for (const tableDef of toSchema.getTables()) {
80
- ret += await this.dump(this.createSchemaBuilder(tableDef.schema).alterTable(tableDef.name, table => this.createForeignKeys(table, tableDef, options.schema)));
80
+ ret += await this.dump(this.helper.createSchemaBuilder(tableDef.schema).alterTable(tableDef.name, table => this.createForeignKeys(table, tableDef, options.schema)));
81
81
  }
82
82
  return this.wrapSchema(ret, { wrap });
83
83
  }
@@ -124,7 +124,7 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
124
124
  const table = schema.getTable(meta.tableName);
125
125
  if (!this.platform.usesCascadeStatement() && table && (!wrap || options.dropForeignKeys)) {
126
126
  for (const fk of Object.values(table.getForeignKeys())) {
127
- const builder = this.createSchemaBuilder(table.schema).alterTable(table.name, tbl => {
127
+ const builder = this.helper.createSchemaBuilder(table.schema).alterTable(table.name, tbl => {
128
128
  tbl.dropForeign(fk.columnNames, fk.constraintName);
129
129
  });
130
130
  ret += await this.dump(builder, '\n');
@@ -137,7 +137,7 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
137
137
  if (this.platform.supportsNativeEnums()) {
138
138
  for (const columnName of Object.keys(schema.getNativeEnums())) {
139
139
  const sql = this.helper.getDropNativeEnumSQL(columnName, options.schema ?? this.config.get('schema'));
140
- ret += await this.dump(this.knex.schema.raw(sql), '\n');
140
+ ret += await this.dump(sql, '\n');
141
141
  }
142
142
  }
143
143
  if (options.dropMigrationsTable) {
@@ -191,28 +191,28 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
191
191
  if (this.platform.supportsSchemas()) {
192
192
  for (const newNamespace of schemaDiff.newNamespaces) {
193
193
  const sql = this.helper.getCreateNamespaceSQL(newNamespace);
194
- ret += await this.dump(this.knex.schema.raw(sql), '\n');
194
+ ret += await this.dump(sql, '\n');
195
195
  }
196
196
  }
197
197
  if (this.platform.supportsNativeEnums()) {
198
198
  for (const newNativeEnum of schemaDiff.newNativeEnums) {
199
199
  const sql = this.helper.getCreateNativeEnumSQL(newNativeEnum.name, newNativeEnum.items, this.getSchemaName(newNativeEnum, options));
200
- ret += await this.dump(this.knex.schema.raw(sql), '\n');
200
+ ret += await this.dump(sql, '\n');
201
201
  }
202
202
  }
203
- if (!options.safe) {
203
+ if (!options.safe && this.options.createForeignKeyConstraints) {
204
204
  for (const orphanedForeignKey of schemaDiff.orphanedForeignKeys) {
205
- const [schemaName, tableName] = this.splitTableName(orphanedForeignKey.localTableName);
206
- ret += await this.dump(this.createSchemaBuilder(schemaName).alterTable(tableName, table => {
205
+ const [schemaName, tableName] = this.helper.splitTableName(orphanedForeignKey.localTableName);
206
+ ret += await this.dump(this.helper.createSchemaBuilder(schemaName).alterTable(tableName, table => {
207
207
  return table.dropForeign(orphanedForeignKey.columnNames, orphanedForeignKey.constraintName);
208
208
  }));
209
209
  }
210
210
  }
211
211
  for (const newTable of Object.values(schemaDiff.newTables)) {
212
- ret += await this.dump(this.createTable(newTable, true));
212
+ ret += await this.dump(this.helper.createTable(newTable, true));
213
213
  }
214
214
  for (const newTable of Object.values(schemaDiff.newTables)) {
215
- ret += await this.dump(this.createSchemaBuilder(newTable.schema).alterTable(newTable.name, table => {
215
+ ret += await this.dump(this.helper.createSchemaBuilder(newTable.schema).alterTable(newTable.name, table => {
216
216
  this.createForeignKeys(table, newTable, options.schema);
217
217
  }));
218
218
  }
@@ -228,7 +228,11 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
228
228
  }
229
229
  for (const changedTable of Object.values(schemaDiff.changedTables)) {
230
230
  for (const builder of this.alterTable(changedTable, options.safe)) {
231
- ret += await this.dump(builder);
231
+ let diff = await this.dump(builder);
232
+ if (diff.includes('CREATE TABLE `_knex_temp_alter') && this.helper.getAlterTable) {
233
+ diff = await this.helper.getAlterTable(changedTable, options.wrap);
234
+ }
235
+ ret += diff;
232
236
  }
233
237
  }
234
238
  for (const changedTable of Object.values(schemaDiff.changedTables)) {
@@ -239,50 +243,17 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
239
243
  if (!options.safe && this.platform.supportsNativeEnums()) {
240
244
  for (const removedNativeEnum of schemaDiff.removedNativeEnums) {
241
245
  const sql = this.helper.getDropNativeEnumSQL(removedNativeEnum.name, removedNativeEnum.schema);
242
- ret += await this.dump(this.knex.schema.raw(sql), '\n');
246
+ ret += await this.dump(sql, '\n');
243
247
  }
244
248
  }
245
249
  if (options.dropTables && !options.safe) {
246
250
  for (const removedNamespace of schemaDiff.removedNamespaces) {
247
251
  const sql = this.helper.getDropNamespaceSQL(removedNamespace);
248
- ret += await this.dump(this.knex.schema.raw(sql), '\n');
252
+ ret += await this.dump(sql, '\n');
249
253
  }
250
254
  }
251
255
  return this.wrapSchema(ret, options);
252
256
  }
253
- getReferencedTableName(referencedTableName, schema) {
254
- const [schemaName, tableName] = this.splitTableName(referencedTableName);
255
- schema = schemaName ?? schema ?? this.config.get('schema');
256
- /* istanbul ignore next */
257
- if (schema && schemaName === '*') {
258
- return `${schema}.${referencedTableName.replace(/^\*\./, '')}`;
259
- }
260
- if (!schemaName || schemaName === this.platform.getDefaultSchemaName()) {
261
- return tableName;
262
- }
263
- return `${schemaName}.${tableName}`;
264
- }
265
- createForeignKey(table, foreignKey, schema) {
266
- if (!this.options.createForeignKeyConstraints) {
267
- return;
268
- }
269
- const builder = table
270
- .foreign(foreignKey.columnNames, foreignKey.constraintName)
271
- .references(foreignKey.referencedColumnNames)
272
- .inTable(this.getReferencedTableName(foreignKey.referencedTableName, schema))
273
- .withKeyName(foreignKey.constraintName);
274
- if (foreignKey.localTableName !== foreignKey.referencedTableName || this.platform.supportsMultipleCascadePaths()) {
275
- if (foreignKey.updateRule) {
276
- builder.onUpdate(foreignKey.updateRule);
277
- }
278
- if (foreignKey.deleteRule) {
279
- builder.onDelete(foreignKey.deleteRule);
280
- }
281
- }
282
- if (foreignKey.deferMode) {
283
- builder.deferrable(foreignKey.deferMode);
284
- }
285
- }
286
257
  /**
287
258
  * We need to drop foreign keys first for all tables to allow dropping PK constraints.
288
259
  */
@@ -290,8 +261,8 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
290
261
  const ret = [];
291
262
  const push = (sql) => sql ? ret.push(this.knex.schema.raw(sql)) : undefined;
292
263
  push(this.helper.getPreAlterTable(diff, safe));
293
- const [schemaName, tableName] = this.splitTableName(diff.name);
294
- ret.push(this.createSchemaBuilder(schemaName).alterTable(tableName, table => {
264
+ const [schemaName, tableName] = this.helper.splitTableName(diff.name);
265
+ ret.push(this.helper.createSchemaBuilder(schemaName).alterTable(tableName, table => {
295
266
  for (const foreignKey of Object.values(diff.removedForeignKeys)) {
296
267
  table.dropForeign(foreignKey.columnNames, foreignKey.constraintName);
297
268
  }
@@ -307,15 +278,9 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
307
278
  push(this.helper.getPostAlterTable(diff, safe));
308
279
  return ret;
309
280
  }
310
- splitTableName(name) {
311
- const parts = name.split('.');
312
- const tableName = parts.pop();
313
- const schemaName = parts.pop();
314
- return [schemaName, tableName];
315
- }
316
281
  alterTable(diff, safe) {
317
282
  const ret = [];
318
- const [schemaName, tableName] = this.splitTableName(diff.name);
283
+ const [schemaName, tableName] = this.helper.splitTableName(diff.name);
319
284
  if (this.platform.supportsNativeEnums()) {
320
285
  const changedNativeEnums = [];
321
286
  for (const { column, changedProperties } of Object.values(diff.changedColumns)) {
@@ -334,7 +299,7 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
334
299
  ret.push(...newItems.map(val => this.knex.schema.raw(this.helper.getAlterNativeEnumSQL(enumName, schemaName, val))));
335
300
  });
336
301
  }
337
- ret.push(this.createSchemaBuilder(schemaName).alterTable(tableName, table => {
302
+ ret.push(this.helper.createSchemaBuilder(schemaName).alterTable(tableName, table => {
338
303
  for (const index of Object.values(diff.removedIndexes)) {
339
304
  this.dropIndex(table, index);
340
305
  }
@@ -352,7 +317,7 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
352
317
  this.helper.pushTableQuery(table, this.helper.getDropColumnsSQL(tableName, Object.values(diff.removedColumns), schemaName));
353
318
  }
354
319
  }));
355
- ret.push(this.createSchemaBuilder(schemaName).alterTable(tableName, table => {
320
+ ret.push(this.helper.createSchemaBuilder(schemaName).alterTable(tableName, table => {
356
321
  for (const column of Object.values(diff.addedColumns)) {
357
322
  const col = this.helper.createTableColumn(table, column, diff.fromTable, undefined, true);
358
323
  this.helper.configureColumn(column, col, this.knex);
@@ -360,7 +325,7 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
360
325
  if (foreignKey && this.options.createForeignKeyConstraints) {
361
326
  delete diff.addedForeignKeys[foreignKey.constraintName];
362
327
  const builder = col.references(foreignKey.referencedColumnNames[0])
363
- .inTable(this.getReferencedTableName(foreignKey.referencedTableName))
328
+ .inTable(this.helper.getReferencedTableName(foreignKey.referencedTableName))
364
329
  .withKeyName(foreignKey.constraintName)
365
330
  .onUpdate(foreignKey.updateRule)
366
331
  .onDelete(foreignKey.deleteRule);
@@ -394,31 +359,31 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
394
359
  this.helper.pushTableQuery(table, this.helper.getRenameColumnSQL(tableName, oldColumnName, column, schemaName));
395
360
  }
396
361
  for (const foreignKey of Object.values(diff.addedForeignKeys)) {
397
- this.createForeignKey(table, foreignKey);
362
+ this.helper.createForeignKey(table, foreignKey, undefined);
398
363
  }
399
364
  for (const foreignKey of Object.values(diff.changedForeignKeys)) {
400
- this.createForeignKey(table, foreignKey);
365
+ this.helper.createForeignKey(table, foreignKey, undefined);
401
366
  }
402
367
  for (const index of Object.values(diff.addedIndexes)) {
403
- this.createIndex(table, index, diff.toTable);
368
+ this.helper.createIndex(table, index, diff.toTable);
404
369
  }
405
370
  for (const index of Object.values(diff.changedIndexes)) {
406
- this.createIndex(table, index, diff.toTable, true);
371
+ this.helper.createIndex(table, index, diff.toTable, true);
407
372
  }
408
373
  for (const [oldIndexName, index] of Object.entries(diff.renamedIndexes)) {
409
374
  if (index.unique) {
410
375
  this.dropIndex(table, index, oldIndexName);
411
- this.createIndex(table, index, diff.toTable);
376
+ this.helper.createIndex(table, index, diff.toTable);
412
377
  }
413
378
  else {
414
379
  this.helper.pushTableQuery(table, this.helper.getRenameIndexSQL(diff.name, index, oldIndexName));
415
380
  }
416
381
  }
417
382
  for (const check of Object.values(diff.addedChecks)) {
418
- this.createCheck(table, check);
383
+ this.helper.createCheck(table, check);
419
384
  }
420
385
  for (const check of Object.values(diff.changedChecks)) {
421
- this.createCheck(table, check);
386
+ this.helper.createCheck(table, check);
422
387
  }
423
388
  if ('changedComment' in diff) {
424
389
  const comment = diff.changedComment ? this.platform.quoteValue(diff.changedComment).replace(/^'|'$/g, '') : '';
@@ -483,76 +448,6 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
483
448
  ret += this.helper.getSchemaEnd();
484
449
  return ret;
485
450
  }
486
- createSchemaBuilder(schema) {
487
- const builder = this.knex.schema;
488
- if (schema && schema !== this.platform.getDefaultSchemaName()) {
489
- builder.withSchema(schema);
490
- }
491
- return builder;
492
- }
493
- createTable(tableDef, alter) {
494
- return this.createSchemaBuilder(tableDef.schema).createTable(tableDef.name, table => {
495
- tableDef.getColumns().forEach(column => {
496
- const col = this.helper.createTableColumn(table, column, tableDef, undefined, alter);
497
- this.helper.configureColumn(column, col, this.knex);
498
- });
499
- for (const index of tableDef.getIndexes()) {
500
- const createPrimary = !tableDef.getColumns().some(c => c.autoincrement && c.primary) || this.helper.hasNonDefaultPrimaryKeyName(tableDef);
501
- this.createIndex(table, index, tableDef, createPrimary);
502
- }
503
- for (const check of tableDef.getChecks()) {
504
- this.createCheck(table, check);
505
- }
506
- if (tableDef.comment) {
507
- const comment = this.platform.quoteValue(tableDef.comment).replace(/^'|'$/g, '');
508
- table.comment(comment);
509
- }
510
- if (!this.helper.supportsSchemaConstraints()) {
511
- for (const fk of Object.values(tableDef.getForeignKeys())) {
512
- this.createForeignKey(table, fk);
513
- }
514
- }
515
- this.helper.finalizeTable(table, this.config.get('charset'), this.config.get('collate'));
516
- });
517
- }
518
- createIndex(table, index, tableDef, createPrimary = false) {
519
- if (index.primary && !createPrimary) {
520
- return;
521
- }
522
- if (index.primary) {
523
- const keyName = this.helper.hasNonDefaultPrimaryKeyName(tableDef) ? index.keyName : undefined;
524
- table.primary(index.columnNames, keyName);
525
- }
526
- else if (index.unique) {
527
- // JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
528
- if (index.columnNames.some(column => column.includes('.'))) {
529
- const columns = this.platform.getJsonIndexDefinition(index);
530
- table.index(columns.map(column => this.knex.raw(column)), index.keyName, { indexType: 'unique' });
531
- }
532
- else {
533
- table.unique(index.columnNames, { indexName: index.keyName, deferrable: index.deferMode });
534
- }
535
- }
536
- else if (index.expression) {
537
- this.helper.pushTableQuery(table, index.expression);
538
- }
539
- else if (index.type === 'fulltext') {
540
- const columns = index.columnNames.map(name => ({ name, type: tableDef.getColumn(name).type }));
541
- if (this.platform.supportsCreatingFullTextIndex()) {
542
- this.helper.pushTableQuery(table, this.platform.getFullTextIndexExpression(index.keyName, tableDef.schema, tableDef.name, columns));
543
- }
544
- }
545
- else {
546
- // JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
547
- if (index.columnNames.some(column => column.includes('.'))) {
548
- const columns = this.platform.getJsonIndexDefinition(index);
549
- table.index(columns.map(column => this.knex.raw(column)), index.keyName, index.type);
550
- }
551
- else {
552
- table.index(index.columnNames, index.keyName, index.type);
553
- }
554
- }
555
- }
556
451
  dropIndex(table, index, oldIndexName = index.keyName) {
557
452
  if (index.primary) {
558
453
  table.dropPrimary(oldIndexName);
@@ -564,14 +459,11 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
564
459
  table.dropIndex(index.columnNames, oldIndexName);
565
460
  }
566
461
  }
567
- createCheck(table, check) {
568
- table.check(check.expression, {}, check.name);
569
- }
570
462
  dropCheck(table, check) {
571
463
  table.dropChecks(check.name);
572
464
  }
573
465
  dropTable(name, schema) {
574
- let builder = this.createSchemaBuilder(schema).dropTableIfExists(name);
466
+ let builder = this.helper.createSchemaBuilder(schema).dropTableIfExists(name);
575
467
  if (this.platform.usesCascadeStatement()) {
576
468
  builder = this.knex.schema.raw(builder.toQuery() + ' cascade');
577
469
  }
@@ -582,18 +474,11 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
582
474
  return;
583
475
  }
584
476
  for (const fk of Object.values(tableDef.getForeignKeys())) {
585
- this.createForeignKey(table, fk, schema);
477
+ this.helper.createForeignKey(table, fk, schema);
586
478
  }
587
479
  }
588
480
  async dump(builder, append = '\n\n') {
589
- const sql = await builder.generateDdlCommands();
590
- const queries = [...sql.pre, ...sql.sql, ...sql.post];
591
- if (queries.length === 0) {
592
- return '';
593
- }
594
- const dump = `${queries.map(q => typeof q === 'object' ? q.sql : q).join(';\n')};${append}`;
595
- const tmp = dump.replace(/pragma table_.+/ig, '').replace(/\n\n+/g, '\n').trim();
596
- return tmp ? tmp + append : '';
481
+ return this.helper.dump(builder, append);
597
482
  }
598
483
  get knex() {
599
484
  return this.connection.getKnex();
package/typings.d.ts CHANGED
@@ -47,7 +47,7 @@ export interface Column {
47
47
  unique?: boolean;
48
48
  /** mysql only */
49
49
  extra?: string;
50
- ignoreSchemaChanges?: ('type' | 'extra')[];
50
+ ignoreSchemaChanges?: ('type' | 'extra' | 'default')[];
51
51
  }
52
52
  export interface ForeignKey {
53
53
  columnNames: string[];
@@ -129,6 +129,8 @@ export interface IQueryBuilder<T> {
129
129
  readonly alias: string;
130
130
  readonly type?: QueryType;
131
131
  _fields?: Field<T>[];
132
+ /** @internal */
133
+ helper: any;
132
134
  select(fields: Field<T> | Field<T>[], distinct?: boolean): this;
133
135
  addSelect(fields: string | string[]): this;
134
136
  from<T extends AnyEntity<T> = AnyEntity>(target: EntityName<T> | IQueryBuilder<T>, aliasName?: string): IQueryBuilder<T>;