@mikro-orm/knex 6.2.9-dev.8 → 6.2.9

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.
@@ -28,6 +28,12 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
28
28
  nativeUpdate<T extends object>(entityName: string, where: FilterQuery<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T> & UpsertOptions<T>): Promise<QueryResult<T>>;
29
29
  nativeUpdateMany<T extends object>(entityName: string, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T> & UpsertManyOptions<T>): Promise<QueryResult<T>>;
30
30
  nativeDelete<T extends object>(entityName: string, where: FilterQuery<T> | string | any, options?: DeleteOptions<T>): Promise<QueryResult<T>>;
31
+ /**
32
+ * Fast comparison for collection snapshots that are represented by PK arrays.
33
+ * Compares scalars via `===` and fallbacks to Utils.equals()` for more complex types like Buffer.
34
+ * Always expects the same length of the arrays, since we only compare PKs of the same entity type.
35
+ */
36
+ private comparePrimaryKeyArrays;
31
37
  syncCollections<T extends object, O extends object>(collections: Iterable<Collection<T, O>>, options?: DriverMethodOptions): Promise<void>;
32
38
  loadFromPivotTable<T extends object, O extends object>(prop: EntityProperty, owners: Primary<O>[][], where?: FilterQuery<any>, orderBy?: OrderDefinition<T>, ctx?: Transaction, options?: FindOptions<T, any, any, any>, pivotJoin?: boolean): Promise<Dictionary<T[]>>;
33
39
  private getPivotOrderBy;
@@ -389,12 +389,21 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
389
389
  const usedDups = [];
390
390
  props.forEach(prop => {
391
391
  if (prop.fieldNames.length > 1) {
392
- const param = core_1.Utils.flatten([...row[prop.name] ?? prop.fieldNames.map(() => null)]);
393
- const key = param.map(() => '?');
392
+ const newFields = [];
393
+ const allParam = [...row[prop.name] ?? prop.fieldNames.map(() => null)];
394
+ const newParam = [];
394
395
  prop.fieldNames.forEach((field, idx) => {
396
+ if (usedDups.includes(field)) {
397
+ return;
398
+ }
399
+ newFields.push(field);
400
+ newParam.push(allParam[idx]);
401
+ });
402
+ const param = core_1.Utils.flatten(newParam);
403
+ newFields.forEach((field, idx) => {
395
404
  if (!duplicates.includes(field) || !usedDups.includes(field)) {
396
405
  params.push(param[idx]);
397
- keys.push(key[idx]);
406
+ keys.push('?');
398
407
  usedDups.push(field);
399
408
  }
400
409
  });
@@ -622,6 +631,26 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
622
631
  const qb = this.createQueryBuilder(entityName, options.ctx, 'write', false).delete(where).withSchema(this.getSchemaName(meta, options));
623
632
  return this.rethrow(qb.execute('run', false));
624
633
  }
634
+ /**
635
+ * Fast comparison for collection snapshots that are represented by PK arrays.
636
+ * Compares scalars via `===` and fallbacks to Utils.equals()` for more complex types like Buffer.
637
+ * Always expects the same length of the arrays, since we only compare PKs of the same entity type.
638
+ */
639
+ comparePrimaryKeyArrays(a, b) {
640
+ for (let i = a.length; i-- !== 0;) {
641
+ if (['number', 'string', 'bigint', 'boolean'].includes(typeof a[i])) {
642
+ if (a[i] !== b[i]) {
643
+ return false;
644
+ }
645
+ }
646
+ else {
647
+ if (!core_1.Utils.equals(a[i], b[i])) {
648
+ return false;
649
+ }
650
+ }
651
+ }
652
+ return true;
653
+ }
625
654
  async syncCollections(collections, options) {
626
655
  const groups = {};
627
656
  for (const coll of collections) {
@@ -629,7 +658,7 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
629
658
  const meta = wrapped.__meta;
630
659
  const pks = wrapped.getPrimaryKeys(true);
631
660
  const snap = coll.getSnapshot();
632
- const includes = (arr, item) => !!arr.find(i => core_1.Utils.equals(i, item));
661
+ const includes = (arr, item) => !!arr.find(i => this.comparePrimaryKeyArrays(i, item));
633
662
  const snapshot = snap ? snap.map(item => (0, core_1.helper)(item).getPrimaryKeys(true)) : [];
634
663
  const current = coll.getItems(false).map(item => (0, core_1.helper)(item).getPrimaryKeys(true));
635
664
  const deleteDiff = snap ? snapshot.filter(item => !includes(current, item)) : true;
@@ -639,8 +668,12 @@ class AbstractSqlDriver extends core_1.DatabaseDriver {
639
668
  // wrong order if we just delete and insert to the end (only owning sides can have fixed order)
640
669
  if (coll.property.owner && coll.property.fixedOrder && !equals && Array.isArray(deleteDiff)) {
641
670
  deleteDiff.length = insertDiff.length = 0;
642
- deleteDiff.push(...snapshot);
643
- insertDiff.push(...current);
671
+ for (const item of snapshot) {
672
+ deleteDiff.push(item);
673
+ }
674
+ for (const item of current) {
675
+ insertDiff.push(item);
676
+ }
644
677
  }
645
678
  if (coll.property.kind === core_1.ReferenceKind.ONE_TO_MANY) {
646
679
  const cols = coll.property.referencedColumnNames;
@@ -8,6 +8,7 @@ export declare class PivotCollectionPersister<Entity extends object> {
8
8
  private readonly platform;
9
9
  private readonly inserts;
10
10
  private readonly deletes;
11
+ private readonly batchSize;
11
12
  private order;
12
13
  constructor(meta: EntityMetadata<Entity>, driver: AbstractSqlDriver, ctx?: any, schema?: string | undefined);
13
14
  enqueueUpdate(prop: EntityProperty<Entity>, insertDiff: Primary<Entity>[][], deleteDiff: Primary<Entity>[][] | boolean, pks: Primary<Entity>[]): void;
@@ -44,6 +44,7 @@ class PivotCollectionPersister {
44
44
  platform;
45
45
  inserts = new Map();
46
46
  deletes = new Map();
47
+ batchSize;
47
48
  order = 0;
48
49
  constructor(meta, driver, ctx, schema) {
49
50
  this.meta = meta;
@@ -51,6 +52,7 @@ class PivotCollectionPersister {
51
52
  this.ctx = ctx;
52
53
  this.schema = schema;
53
54
  this.platform = this.driver.getPlatform();
55
+ this.batchSize = this.driver.config.get('batchSize');
54
56
  }
55
57
  enqueueUpdate(prop, insertDiff, deleteDiff, pks) {
56
58
  if (insertDiff.length) {
@@ -90,13 +92,18 @@ class PivotCollectionPersister {
90
92
  }
91
93
  async execute() {
92
94
  if (this.deletes.size > 0) {
93
- const knex = this.driver.createQueryBuilder(this.meta.className, this.ctx, 'write')
94
- .withSchema(this.schema)
95
- .getKnex();
96
- for (const item of this.deletes.values()) {
97
- knex.orWhere(item.getCondition());
95
+ const deletes = [...this.deletes.values()];
96
+ for (let i = 0; i < deletes.length; i += this.batchSize) {
97
+ const chunk = deletes.slice(i, i + this.batchSize);
98
+ const cond = { $or: [] };
99
+ for (const item of chunk) {
100
+ cond.$or.push(item.getCondition());
101
+ }
102
+ await this.driver.nativeDelete(this.meta.className, cond, {
103
+ ctx: this.ctx,
104
+ schema: this.schema,
105
+ });
98
106
  }
99
- await this.driver.execute(knex.delete());
100
107
  }
101
108
  if (this.inserts.size === 0) {
102
109
  return;
@@ -108,12 +115,15 @@ class PivotCollectionPersister {
108
115
  items = items.filter(i => i);
109
116
  /* istanbul ignore else */
110
117
  if (this.platform.allowsMultiInsert()) {
111
- await this.driver.nativeInsertMany(this.meta.className, items, {
112
- ctx: this.ctx,
113
- schema: this.schema,
114
- convertCustomTypes: false,
115
- processCollections: false,
116
- });
118
+ for (let i = 0; i < items.length; i += this.batchSize) {
119
+ const chunk = items.slice(i, i + this.batchSize);
120
+ await this.driver.nativeInsertMany(this.meta.className, chunk, {
121
+ ctx: this.ctx,
122
+ schema: this.schema,
123
+ convertCustomTypes: false,
124
+ processCollections: false,
125
+ });
126
+ }
117
127
  }
118
128
  else {
119
129
  await core_1.Utils.runSerial(items, item => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/knex",
3
- "version": "6.2.9-dev.8",
3
+ "version": "6.2.9",
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",
@@ -63,9 +63,23 @@
63
63
  "sqlstring": "2.3.3"
64
64
  },
65
65
  "devDependencies": {
66
- "@mikro-orm/core": "^6.2.8"
66
+ "@mikro-orm/core": "^6.2.9"
67
67
  },
68
68
  "peerDependencies": {
69
- "@mikro-orm/core": "6.2.9-dev.8"
69
+ "@mikro-orm/core": "^6.0.0",
70
+ "better-sqlite3": "*",
71
+ "libsql": "*",
72
+ "mariadb": "*"
73
+ },
74
+ "peerDependenciesMeta": {
75
+ "better-sqlite3": {
76
+ "optional": true
77
+ },
78
+ "libsql": {
79
+ "optional": true
80
+ },
81
+ "mariadb": {
82
+ "optional": true
83
+ }
70
84
  }
71
85
  }
@@ -158,6 +158,7 @@ class DatabaseTable {
158
158
  constraint: !prop.fieldNames.some((d) => d.includes('.')),
159
159
  primary: false,
160
160
  unique: true,
161
+ deferMode: prop.deferMode,
161
162
  });
162
163
  }
163
164
  }
@@ -484,7 +484,7 @@ class SchemaComparator {
484
484
  // index that has no constraints.
485
485
  return true;
486
486
  }
487
- return index1.primary === index2.primary && index1.unique === index2.unique;
487
+ return index1.primary === index2.primary && index1.unique === index2.unique && index1.deferMode === index2.deferMode;
488
488
  }
489
489
  diffExpression(expr1, expr2) {
490
490
  // expressions like check constraints might be normalized by the driver,
@@ -90,11 +90,11 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
90
90
  await this.execute(sql);
91
91
  }
92
92
  async createNamespace(name) {
93
- const sql = await this.helper.getCreateNamespaceSQL(name);
93
+ const sql = this.helper.getCreateNamespaceSQL(name);
94
94
  await this.execute(sql);
95
95
  }
96
96
  async dropNamespace(name) {
97
- const sql = await this.helper.getDropNamespaceSQL(name);
97
+ const sql = this.helper.getDropNamespaceSQL(name);
98
98
  await this.execute(sql);
99
99
  }
100
100
  async clearDatabase(options) {
@@ -359,14 +359,17 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
359
359
  const foreignKey = Object.values(diff.addedForeignKeys).find(fk => fk.columnNames.length === 1 && fk.columnNames[0] === column.name);
360
360
  if (foreignKey && this.options.createForeignKeyConstraints) {
361
361
  delete diff.addedForeignKeys[foreignKey.constraintName];
362
- col.references(foreignKey.referencedColumnNames[0])
362
+ const builder = col.references(foreignKey.referencedColumnNames[0])
363
363
  .inTable(this.getReferencedTableName(foreignKey.referencedTableName))
364
364
  .withKeyName(foreignKey.constraintName)
365
365
  .onUpdate(foreignKey.updateRule)
366
366
  .onDelete(foreignKey.deleteRule);
367
+ if (foreignKey.deferMode) {
368
+ builder.deferrable(foreignKey.deferMode);
369
+ }
367
370
  }
368
371
  }
369
- for (const { column, changedProperties, fromColumn } of Object.values(diff.changedColumns)) {
372
+ for (const { column, changedProperties } of Object.values(diff.changedColumns)) {
370
373
  if (changedProperties.size === 1 && changedProperties.has('comment')) {
371
374
  continue;
372
375
  }
@@ -527,7 +530,7 @@ class SqlSchemaGenerator extends core_1.AbstractSchemaGenerator {
527
530
  table.index(columns.map(column => this.knex.raw(column)), index.keyName, { indexType: 'unique' });
528
531
  }
529
532
  else {
530
- table.unique(index.columnNames, { indexName: index.keyName });
533
+ table.unique(index.columnNames, { indexName: index.keyName, deferrable: index.deferMode });
531
534
  }
532
535
  }
533
536
  else if (index.expression) {
package/typings.d.ts CHANGED
@@ -73,6 +73,7 @@ export interface IndexDef {
73
73
  storageEngineIndexType?: 'hash' | 'btree';
74
74
  predicate?: Knex.QueryBuilder;
75
75
  }>;
76
+ deferMode?: DeferMode;
76
77
  }
77
78
  export interface CheckDef<T = unknown> {
78
79
  name: string;