orchid-orm 1.14.4 → 1.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { columnTypes, QueryHooks, getColumnTypes, addQueryOn, VirtualColumn, pushQueryValue, isQueryReturnsAll, getQueryAs, toSQLCacheKey, OrchidOrmInternalError, NotFoundError, Adapter, Db, anyShape, getClonedQueryData } from 'pqb';
1
+ import { columnTypes, QueryHooks, getColumnTypes, getQueryAs, setQueryObjectValue, pushQueryOn, VirtualColumn, pushQueryValue, isQueryReturnsAll, toSQLCacheKey, OrchidOrmInternalError, NotFoundError, Adapter, Db, anyShape, getClonedQueryData } from 'pqb';
2
2
  export { OrchidOrmError, OrchidOrmInternalError, columnTypes, raw, testTransaction } from 'pqb';
3
- import { getStackTrace, applyMixins, getCallerFilePath, snakeCaseKey, toSnakeCase } from 'orchid-core';
3
+ import { getStackTrace, applyMixins, getCallerFilePath, snakeCaseKey, toSnakeCase, emptyArray, toArray } from 'orchid-core';
4
4
  import { AsyncLocalStorage } from 'node:async_hooks';
5
5
 
6
6
  const createBaseTable = ({
@@ -81,7 +81,6 @@ const create = (columnTypes, filePathOrStack, snakeCase, nowSQL, exportAs = "Bas
81
81
  belongsTo(fn, options) {
82
82
  return {
83
83
  type: "belongsTo",
84
- returns: "one",
85
84
  fn,
86
85
  options
87
86
  };
@@ -89,7 +88,6 @@ const create = (columnTypes, filePathOrStack, snakeCase, nowSQL, exportAs = "Bas
89
88
  hasOne(fn, options) {
90
89
  return {
91
90
  type: "hasOne",
92
- returns: "one",
93
91
  fn,
94
92
  options
95
93
  };
@@ -97,7 +95,6 @@ const create = (columnTypes, filePathOrStack, snakeCase, nowSQL, exportAs = "Bas
97
95
  hasMany(fn, options) {
98
96
  return {
99
97
  type: "hasMany",
100
- returns: "many",
101
98
  fn,
102
99
  options
103
100
  };
@@ -105,7 +102,6 @@ const create = (columnTypes, filePathOrStack, snakeCase, nowSQL, exportAs = "Bas
105
102
  hasAndBelongsToMany(fn, options) {
106
103
  return {
107
104
  type: "hasAndBelongsToMany",
108
- returns: "many",
109
105
  fn,
110
106
  options
111
107
  };
@@ -116,6 +112,98 @@ const create = (columnTypes, filePathOrStack, snakeCase, nowSQL, exportAs = "Bas
116
112
  return base;
117
113
  };
118
114
 
115
+ const getThroughRelation = (table, through) => {
116
+ var _a;
117
+ return (_a = table.relations[through]) == null ? void 0 : _a.relationConfig;
118
+ };
119
+ const getSourceRelation = (throughRelation, source) => {
120
+ var _a;
121
+ return (_a = throughRelation.table.relations[source]) == null ? void 0 : _a.relationConfig;
122
+ };
123
+ const hasRelationHandleCreate = (q, ctx, item, rowIndex, key, primaryKeys, nestedInsert) => {
124
+ const value = item[key];
125
+ if ((!value.create || Array.isArray(value.create) && value.create.length === 0) && (!value.connect || Array.isArray(value.connect) && value.connect.length === 0) && (!value.connectOrCreate || Array.isArray(value.connectOrCreate) && value.connectOrCreate.length === 0))
126
+ return;
127
+ const store = ctx;
128
+ if (!store.hasRelation)
129
+ store.hasRelation = {};
130
+ const values = [rowIndex, value];
131
+ if (store.hasRelation[key]) {
132
+ store.hasRelation[key].push(values);
133
+ return;
134
+ }
135
+ q.q.wrapInTransaction = true;
136
+ const relationData = [values];
137
+ store.hasRelation[key] = relationData;
138
+ q._afterCreate(
139
+ primaryKeys,
140
+ (rows, q2) => nestedInsert(
141
+ q2,
142
+ relationData.map(([rowIndex2, data]) => [
143
+ rows[rowIndex2],
144
+ data
145
+ ])
146
+ )
147
+ );
148
+ };
149
+ const hasRelationHandleUpdate = (q, set, key, primaryKeys, nestedUpdate) => {
150
+ const value = set[key];
151
+ if (!value.set && !("upsert" in value) && (!value.disconnect || Array.isArray(value.disconnect) && value.disconnect.length === 0) && (!value.delete || Array.isArray(value.delete) && value.delete.length === 0) && (!value.update || Array.isArray(value.update.where) && value.update.where.length === 0) && (!value.create || Array.isArray(value.create) && value.create.length === 0))
152
+ return;
153
+ selectIfNotSelected(q, primaryKeys);
154
+ q.q.wrapInTransaction = true;
155
+ q._afterUpdate(q.primaryKeys, (rows, q2) => {
156
+ return nestedUpdate(
157
+ q2,
158
+ rows,
159
+ value
160
+ );
161
+ });
162
+ };
163
+ const selectIfNotSelected = (q, columns) => {
164
+ const select = q.q.select || [];
165
+ if (!select.includes("*")) {
166
+ for (const column of columns) {
167
+ if (!select.includes(column)) {
168
+ select.push(column);
169
+ }
170
+ }
171
+ q.q.select = select;
172
+ }
173
+ };
174
+ const relationWhere = (len, keys, valueKeys) => (params) => {
175
+ const obj = {};
176
+ for (let i = 0; i < len; i++) {
177
+ obj[keys[i]] = params[valueKeys[i]];
178
+ }
179
+ return obj;
180
+ };
181
+ function joinHasThrough(q, fromQuery, toQuery, throughRelation, sourceRelation) {
182
+ return q.whereExists(
183
+ throughRelation.joinQuery(fromQuery, throughRelation.query),
184
+ () => {
185
+ const as = getQueryAs(toQuery);
186
+ return sourceRelation.joinQuery(
187
+ throughRelation.query,
188
+ sourceRelation.query.as(as)
189
+ );
190
+ }
191
+ );
192
+ }
193
+ function joinHasRelation(fromQuery, toQuery, primaryKeys, foreignKeys, len) {
194
+ const q = toQuery.clone();
195
+ setQueryObjectValue(
196
+ q,
197
+ "joinedShapes",
198
+ fromQuery.q.as || fromQuery.table,
199
+ fromQuery.q.shape
200
+ );
201
+ for (let i = 0; i < len; i++) {
202
+ pushQueryOn(q, fromQuery, toQuery, foreignKeys[i], primaryKeys[i]);
203
+ }
204
+ return q;
205
+ }
206
+
119
207
  class BelongsToVirtualColumn extends VirtualColumn {
120
208
  constructor(key, state) {
121
209
  super();
@@ -127,16 +215,19 @@ class BelongsToVirtualColumn extends VirtualColumn {
127
215
  create(q, ctx, item, rowIndex) {
128
216
  const {
129
217
  key,
130
- state: { foreignKey, primaryKey }
218
+ state: { primaryKeys, foreignKeys }
131
219
  } = this;
132
- let columnIndex = ctx.columns.get(foreignKey);
133
- if (columnIndex === void 0) {
134
- ctx.columns.set(foreignKey, columnIndex = ctx.columns.size);
135
- }
220
+ const columnIndexes = foreignKeys.map((key2) => {
221
+ let index = ctx.columns.get(key2);
222
+ if (index === void 0) {
223
+ ctx.columns.set(key2, index = ctx.columns.size);
224
+ }
225
+ return index;
226
+ });
136
227
  const store = ctx;
137
228
  if (!store.belongsTo)
138
229
  store.belongsTo = {};
139
- const values = [rowIndex, columnIndex, item[key]];
230
+ const values = [rowIndex, columnIndexes, item[key]];
140
231
  if (store.belongsTo[key]) {
141
232
  store.belongsTo[key].push(values);
142
233
  return;
@@ -150,9 +241,13 @@ class BelongsToVirtualColumn extends VirtualColumn {
150
241
  relationData.map(([, , data]) => data)
151
242
  );
152
243
  const { values: values2 } = q2.q;
153
- relationData.forEach(([rowIndex2, columnIndex2], index) => {
154
- values2[rowIndex2][columnIndex2] = inserted[index][primaryKey];
155
- });
244
+ for (let i = 0, len = relationData.length; i < len; i++) {
245
+ const [rowIndex2, columnIndexes2] = relationData[i];
246
+ const row = values2[rowIndex2];
247
+ for (let c = 0, len2 = columnIndexes2.length; c < len2; c++) {
248
+ row[columnIndexes2[c]] = inserted[i][primaryKeys[c]];
249
+ }
250
+ }
156
251
  });
157
252
  }
158
253
  update(q, ctx, set) {
@@ -164,68 +259,91 @@ class BelongsToVirtualColumn extends VirtualColumn {
164
259
  }
165
260
  }
166
261
  const makeBelongsToMethod = (relation, relationName, query) => {
167
- const { primaryKey, foreignKey } = relation.options;
168
- const state = { query, primaryKey, foreignKey };
262
+ const primaryKeys = "columns" in relation.options ? relation.options.references : [relation.options.primaryKey];
263
+ const foreignKeys = "columns" in relation.options ? relation.options.columns : [relation.options.foreignKey];
264
+ const len = primaryKeys.length;
265
+ const state = { query, primaryKeys, foreignKeys, len };
266
+ const makeWhere = relationWhere(len, primaryKeys, foreignKeys);
267
+ const join = (fromQuery, toQuery, primaryKeys2, foreignKeys2) => {
268
+ const q = toQuery.clone();
269
+ setQueryObjectValue(
270
+ q,
271
+ "joinedShapes",
272
+ fromQuery.q.as || fromQuery.table,
273
+ fromQuery.q.shape
274
+ );
275
+ for (let i = 0; i < len; i++) {
276
+ pushQueryOn(q, fromQuery, toQuery, primaryKeys2[i], foreignKeys2[i]);
277
+ }
278
+ return q;
279
+ };
169
280
  return {
170
281
  returns: "one",
171
- method: (params) => {
172
- return query.where({ [primaryKey]: params[foreignKey] });
282
+ method(params) {
283
+ return query.where(makeWhere(params));
173
284
  },
174
285
  virtualColumn: new BelongsToVirtualColumn(relationName, state),
175
286
  joinQuery(fromQuery, toQuery) {
176
- return addQueryOn(toQuery, fromQuery, toQuery, primaryKey, foreignKey);
287
+ return join(fromQuery, toQuery, primaryKeys, foreignKeys);
177
288
  },
178
289
  reverseJoin(fromQuery, toQuery) {
179
- return addQueryOn(fromQuery, toQuery, fromQuery, foreignKey, primaryKey);
290
+ return join(toQuery, fromQuery, foreignKeys, primaryKeys);
180
291
  }
181
292
  };
182
293
  };
183
- const nestedInsert$3 = ({ query, primaryKey }) => {
294
+ const nestedInsert$3 = ({ query, primaryKeys }) => {
184
295
  return async (_, data) => {
185
- const connectOrCreate = data.filter(
186
- (item) => Boolean(item.connectOrCreate)
187
- );
188
296
  const t = query.clone();
297
+ const items = [];
298
+ for (const item of data) {
299
+ if (item.connectOrCreate) {
300
+ items.push(item);
301
+ }
302
+ }
189
303
  let connectOrCreated;
190
- if (connectOrCreate.length) {
191
- connectOrCreated = await Promise.all(
192
- connectOrCreate.map(
193
- (item) => t.findBy(item.connectOrCreate.where)._takeOptional()
194
- )
195
- );
304
+ if (items.length) {
305
+ for (let i = 0, len = items.length; i < len; i++) {
306
+ items[i] = t.findByOptional(
307
+ items[i].connectOrCreate.where
308
+ );
309
+ }
310
+ connectOrCreated = await Promise.all(items);
196
311
  } else {
197
- connectOrCreated = [];
312
+ connectOrCreated = emptyArray;
198
313
  }
199
314
  let connectOrCreatedI = 0;
200
- const create = data.filter(
201
- (item) => {
202
- if (item.connectOrCreate) {
203
- return !connectOrCreated[connectOrCreatedI++];
204
- } else {
205
- return Boolean(item.create);
206
- }
315
+ items.length = 0;
316
+ for (const item of data) {
317
+ if (item.connectOrCreate) {
318
+ if (!connectOrCreated[connectOrCreatedI++])
319
+ items.push(item);
320
+ } else if (item.create) {
321
+ items.push(item);
207
322
  }
208
- );
323
+ }
209
324
  let created;
210
- if (create.length) {
211
- created = await t.select(primaryKey)._createMany(
212
- create.map(
213
- (item) => "create" in item ? item.create : item.connectOrCreate.create
214
- )
215
- );
325
+ if (items.length) {
326
+ for (let i = 0, len = items.length; i < len; i++) {
327
+ items[i] = "create" in items[i] ? items[i].create : items[i].connectOrCreate.create;
328
+ }
329
+ created = await t.select(...primaryKeys)._createMany(items);
216
330
  } else {
217
- created = [];
331
+ created = emptyArray;
332
+ }
333
+ items.length = 0;
334
+ for (const item of data) {
335
+ if (item.connect) {
336
+ items.push(item);
337
+ }
218
338
  }
219
- const connect = data.filter(
220
- (item) => Boolean(item.connect)
221
- );
222
339
  let connected;
223
- if (connect.length) {
224
- connected = await Promise.all(
225
- connect.map((item) => t.findBy(item.connect)._take())
226
- );
340
+ if (items.length) {
341
+ for (let i = 0, len = items.length; i < len; i++) {
342
+ items[i] = t.findBy(items[i].connect);
343
+ }
344
+ connected = await Promise.all(items);
227
345
  } else {
228
- connected = [];
346
+ connected = emptyArray;
229
347
  }
230
348
  let createdI = 0;
231
349
  let connectedI = 0;
@@ -235,125 +353,122 @@ const nestedInsert$3 = ({ query, primaryKey }) => {
235
353
  });
236
354
  };
237
355
  };
238
- const nestedUpdate$3 = ({ query, primaryKey, foreignKey }) => {
356
+ const nestedUpdate$3 = ({ query, primaryKeys, foreignKeys, len }) => {
239
357
  return (q, update, params, state) => {
240
- var _a, _b, _c;
358
+ var _a;
241
359
  if (params.upsert && isQueryReturnsAll(q)) {
242
360
  throw new Error("`upsert` option is not allowed in a batch update");
243
361
  }
244
362
  let idsForDelete;
245
363
  q._beforeUpdate(async (q2) => {
246
364
  if (params.disconnect) {
247
- update[foreignKey] = null;
365
+ for (const key of foreignKeys) {
366
+ update[key] = null;
367
+ }
248
368
  } else if (params.set) {
249
- if (primaryKey in params.set) {
250
- update[foreignKey] = params.set[primaryKey];
251
- } else {
252
- update[foreignKey] = await query.findBy(params.set)._get(primaryKey);
369
+ let loadPrimaryKeys;
370
+ let loadForeignKeys;
371
+ for (let i = 0; i < len; i++) {
372
+ const primaryKey = primaryKeys[i];
373
+ if (primaryKey in params.set) {
374
+ update[foreignKeys[i]] = params.set[primaryKey];
375
+ } else {
376
+ (loadPrimaryKeys != null ? loadPrimaryKeys : loadPrimaryKeys = []).push(primaryKey);
377
+ (loadForeignKeys != null ? loadForeignKeys : loadForeignKeys = []).push(foreignKeys[i]);
378
+ }
379
+ }
380
+ if (loadPrimaryKeys) {
381
+ const record = await query.select(...loadPrimaryKeys)._findBy(params.set);
382
+ for (let i = 0, len2 = loadPrimaryKeys.length; i < len2; i++) {
383
+ update[loadForeignKeys[i]] = record[loadPrimaryKeys[i]];
384
+ }
253
385
  }
254
386
  } else if (params.create) {
255
- update[foreignKey] = await query.get(primaryKey)._create(params.create);
387
+ const q3 = query.clone();
388
+ q3.q.select = primaryKeys;
389
+ const record = await q3._create(params.create);
390
+ for (let i = 0; i < len; i++) {
391
+ update[foreignKeys[i]] = record[primaryKeys[i]];
392
+ }
256
393
  } else if (params.delete) {
257
394
  const selectQuery = q2.clone();
258
395
  selectQuery.q.type = void 0;
259
- idsForDelete = await selectQuery._pluck(foreignKey);
260
- update[foreignKey] = null;
396
+ selectQuery.q.distinct = emptyArray;
397
+ idsForDelete = await selectQuery._rows();
398
+ for (const foreignKey of foreignKeys) {
399
+ update[foreignKey] = null;
400
+ }
261
401
  }
262
402
  });
263
403
  const { upsert } = params;
264
404
  if (upsert || params.update || params.delete) {
265
- if (!((_a = q.q.select) == null ? void 0 : _a.includes("*")) && !((_b = q.q.select) == null ? void 0 : _b.includes(foreignKey))) {
266
- q._select(foreignKey);
267
- }
405
+ selectIfNotSelected(q, foreignKeys);
268
406
  }
269
407
  if (upsert) {
270
- ((_c = state.queries) != null ? _c : state.queries = []).push(async (queryResult) => {
408
+ ((_a = state.queries) != null ? _a : state.queries = []).push(async (queryResult) => {
271
409
  var _a2;
272
- const id = queryResult.rows[0][foreignKey];
273
- if (id !== null) {
274
- await query.findBy({ [primaryKey]: id })._update(upsert.update);
410
+ const row = queryResult.rows[0];
411
+ let obj = {};
412
+ for (let i = 0; i < len; i++) {
413
+ const id = row[foreignKeys[i]];
414
+ if (id === null) {
415
+ obj = void 0;
416
+ break;
417
+ }
418
+ obj[primaryKeys[i]] = id;
419
+ }
420
+ if (obj) {
421
+ await query.findBy(obj)._update(upsert.update);
275
422
  } else {
276
423
  const data = typeof upsert.create === "function" ? upsert.create() : upsert.create;
277
- const result = await query.select(primaryKey)._create(data);
278
- ((_a2 = state.updateData) != null ? _a2 : state.updateData = {})[foreignKey] = result[primaryKey];
424
+ const result = await query.select(...primaryKeys)._create(data);
425
+ for (let i = 0; i < len; i++) {
426
+ ((_a2 = state.updateData) != null ? _a2 : state.updateData = {})[foreignKeys[i]] = result[primaryKeys[i]];
427
+ }
279
428
  }
280
429
  });
281
430
  } else if (params.delete || params.update) {
282
431
  q._afterUpdate([], async (data) => {
283
- const id = params.delete ? { in: idsForDelete } : Array.isArray(data) ? data.length === 0 ? null : {
284
- in: data.map((item) => item[foreignKey]).filter((id2) => id2 !== null)
285
- } : data[foreignKey];
286
- if (id !== void 0 && id !== null) {
287
- const t = query.where({
288
- [primaryKey]: id
289
- });
290
- if (params.delete) {
291
- await t._delete();
292
- } else if (params.update) {
293
- await t._update(params.update);
432
+ let ids;
433
+ if (params.delete) {
434
+ ids = idsForDelete;
435
+ } else {
436
+ ids = [];
437
+ for (const item of data) {
438
+ let row;
439
+ for (const foreignKey of foreignKeys) {
440
+ const id = item[foreignKey];
441
+ if (id === null) {
442
+ row = void 0;
443
+ break;
444
+ } else {
445
+ (row != null ? row : row = []).push(id);
446
+ }
447
+ }
448
+ if (row)
449
+ ids.push(row);
294
450
  }
295
451
  }
452
+ if (!(ids == null ? void 0 : ids.length))
453
+ return;
454
+ const t = query.whereIn(
455
+ primaryKeys,
456
+ ids
457
+ );
458
+ if (params.delete) {
459
+ await t._delete();
460
+ } else {
461
+ await t._update(
462
+ params.update
463
+ );
464
+ }
296
465
  });
297
466
  }
298
467
  return !params.update && !params.upsert;
299
468
  };
300
469
  };
301
470
 
302
- const getThroughRelation = (table, through) => {
303
- var _a;
304
- return (_a = table.relations[through]) == null ? void 0 : _a.relationConfig;
305
- };
306
- const getSourceRelation = (throughRelation, source) => {
307
- var _a;
308
- return (_a = throughRelation.table.relations[source]) == null ? void 0 : _a.relationConfig;
309
- };
310
- const hasRelationHandleCreate = (q, ctx, item, rowIndex, key, primaryKey, nestedInsert) => {
311
- const value = item[key];
312
- if ((!value.create || Array.isArray(value.create) && value.create.length === 0) && (!value.connect || Array.isArray(value.connect) && value.connect.length === 0) && (!value.connectOrCreate || Array.isArray(value.connectOrCreate) && value.connectOrCreate.length === 0))
313
- return;
314
- const store = ctx;
315
- if (!store.hasRelation)
316
- store.hasRelation = {};
317
- const values = [rowIndex, value];
318
- if (store.hasRelation[key]) {
319
- store.hasRelation[key].push(values);
320
- return;
321
- }
322
- q.q.wrapInTransaction = true;
323
- const relationData = [values];
324
- store.hasRelation[key] = relationData;
325
- q._afterCreate(
326
- [primaryKey],
327
- (rows, q2) => nestedInsert(
328
- q2,
329
- relationData.map(([rowIndex2, data]) => [
330
- rows[rowIndex2],
331
- data
332
- ])
333
- )
334
- );
335
- };
336
- const hasRelationHandleUpdate = (q, set, key, primaryKey, nestedUpdate) => {
337
- var _a, _b;
338
- const value = set[key];
339
- if (!value.set && !("upsert" in value) && (!value.disconnect || Array.isArray(value.disconnect) && value.disconnect.length === 0) && (!value.delete || Array.isArray(value.delete) && value.delete.length === 0) && (!value.update || Array.isArray(value.update.where) && value.update.where.length === 0) && (!value.create || Array.isArray(value.create) && value.create.length === 0))
340
- return;
341
- if (!((_a = q.q.select) == null ? void 0 : _a.includes("*")) && !((_b = q.q.select) == null ? void 0 : _b.includes(primaryKey))) {
342
- q._select(primaryKey);
343
- }
344
- q.q.wrapInTransaction = true;
345
- q._afterUpdate(q.primaryKeys, (rows, q2) => {
346
- return nestedUpdate(
347
- q2,
348
- rows,
349
- value
350
- );
351
- });
352
- };
353
-
354
471
  var __defProp$5 = Object.defineProperty;
355
- var __defProps$3 = Object.defineProperties;
356
- var __getOwnPropDescs$3 = Object.getOwnPropertyDescriptors;
357
472
  var __getOwnPropSymbols$5 = Object.getOwnPropertySymbols;
358
473
  var __hasOwnProp$5 = Object.prototype.hasOwnProperty;
359
474
  var __propIsEnum$5 = Object.prototype.propertyIsEnumerable;
@@ -369,7 +484,6 @@ var __spreadValues$5 = (a, b) => {
369
484
  }
370
485
  return a;
371
486
  };
372
- var __spreadProps$3 = (a, b) => __defProps$3(a, __getOwnPropDescs$3(b));
373
487
  class HasOneVirtualColumn extends VirtualColumn {
374
488
  constructor(key, state) {
375
489
  super();
@@ -385,7 +499,7 @@ class HasOneVirtualColumn extends VirtualColumn {
385
499
  item,
386
500
  rowIndex,
387
501
  this.key,
388
- this.state.primaryKey,
502
+ this.state.primaryKeys,
389
503
  this.nestedInsert
390
504
  );
391
505
  }
@@ -399,7 +513,7 @@ class HasOneVirtualColumn extends VirtualColumn {
399
513
  q,
400
514
  set,
401
515
  this.key,
402
- this.state.primaryKey,
516
+ this.state.primaryKeys,
403
517
  this.nestedUpdate
404
518
  );
405
519
  }
@@ -421,46 +535,49 @@ const makeHasOneMethod = (table, relation, relationName, query) => {
421
535
  );
422
536
  },
423
537
  joinQuery(fromQuery, toQuery) {
424
- return toQuery.whereExists(
425
- throughRelation.joinQuery(fromQuery, throughRelation.query),
426
- () => {
427
- const as = getQueryAs(toQuery);
428
- return sourceRelation.joinQuery(
429
- throughRelation.query,
430
- sourceRelation.query.as(as)
431
- );
432
- }
538
+ return joinHasThrough(
539
+ toQuery,
540
+ fromQuery,
541
+ toQuery,
542
+ throughRelation,
543
+ sourceRelation
433
544
  );
434
545
  },
435
546
  reverseJoin(fromQuery, toQuery) {
436
- return fromQuery.whereExists(
437
- throughRelation.joinQuery(fromQuery, throughRelation.query),
438
- () => {
439
- const as = getQueryAs(toQuery);
440
- return sourceRelation.joinQuery(
441
- throughRelation.query,
442
- sourceRelation.query.as(as)
443
- );
444
- }
547
+ return joinHasThrough(
548
+ fromQuery,
549
+ fromQuery,
550
+ toQuery,
551
+ throughRelation,
552
+ sourceRelation
445
553
  );
446
554
  }
447
555
  };
448
556
  }
449
- const { primaryKey, foreignKey } = relation.options;
450
- const state = { query, primaryKey, foreignKey };
451
- const fromQuerySelect = [{ selectAs: { [foreignKey]: primaryKey } }];
557
+ const primaryKeys = "columns" in relation.options ? relation.options.columns : [relation.options.primaryKey];
558
+ const foreignKeys = "columns" in relation.options ? relation.options.references : [relation.options.foreignKey];
559
+ const state = { query, primaryKeys, foreignKeys };
560
+ const len = primaryKeys.length;
561
+ const reversedOn = {};
562
+ for (let i = 0; i < len; i++) {
563
+ reversedOn[foreignKeys[i]] = primaryKeys[i];
564
+ }
565
+ const fromQuerySelect = [{ selectAs: reversedOn }];
452
566
  return {
453
567
  returns: "one",
454
568
  method: (params) => {
455
- const values = { [foreignKey]: params[primaryKey] };
569
+ const values = {};
570
+ for (let i = 0; i < len; i++) {
571
+ values[foreignKeys[i]] = params[primaryKeys[i]];
572
+ }
456
573
  return query.where(values)._defaults(values);
457
574
  },
458
575
  virtualColumn: new HasOneVirtualColumn(relationName, state),
459
576
  joinQuery(fromQuery, toQuery) {
460
- return addQueryOn(toQuery, fromQuery, toQuery, foreignKey, primaryKey);
577
+ return joinHasRelation(fromQuery, toQuery, primaryKeys, foreignKeys, len);
461
578
  },
462
579
  reverseJoin(fromQuery, toQuery) {
463
- return addQueryOn(fromQuery, toQuery, fromQuery, primaryKey, foreignKey);
580
+ return joinHasRelation(toQuery, fromQuery, foreignKeys, primaryKeys, len);
464
581
  },
465
582
  modifyRelatedQuery(relationQuery) {
466
583
  return (query2) => {
@@ -473,57 +590,88 @@ const makeHasOneMethod = (table, relation, relationName, query) => {
473
590
  }
474
591
  };
475
592
  };
476
- const nestedInsert$2 = ({ query, primaryKey, foreignKey }) => {
593
+ const nestedInsert$2 = ({ query, primaryKeys, foreignKeys }) => {
477
594
  return async (_, data) => {
478
- const connect = data.filter(
479
- (item) => Boolean(item[1].connect || item[1].connectOrCreate)
480
- );
481
595
  const t = query.clone();
596
+ const items = [];
597
+ for (const item of data) {
598
+ if (item[1].connect || item[1].connectOrCreate) {
599
+ items.push(item);
600
+ }
601
+ }
482
602
  let connected;
483
- if (connect.length) {
484
- connected = await Promise.all(
485
- connect.map(([selfData, item]) => {
486
- const data2 = { [foreignKey]: selfData[primaryKey] };
487
- return "connect" in item ? t.where(item.connect)._updateOrThrow(data2) : t.where(item.connectOrCreate.where)._update(data2);
488
- })
489
- );
603
+ if (items.length) {
604
+ for (let i = 0, len = items.length; i < len; i++) {
605
+ const [selfData, item] = items[i];
606
+ const data2 = {};
607
+ for (let i2 = 0; i2 < len; i2++) {
608
+ data2[foreignKeys[i2]] = selfData[primaryKeys[i2]];
609
+ }
610
+ items[i] = "connect" in item ? t.where(item.connect)._updateOrThrow(data2) : t.where(
611
+ item.connectOrCreate.where
612
+ )._update(data2);
613
+ }
614
+ connected = await Promise.all(items);
490
615
  } else {
491
616
  connected = [];
492
617
  }
493
618
  let connectedI = 0;
494
- const create = data.filter(
495
- (item) => {
496
- if (item[1].connectOrCreate) {
497
- return !connected[connectedI++];
619
+ items.length = 0;
620
+ for (const item of data) {
621
+ if (item[1].connectOrCreate) {
622
+ if (!connected[connectedI++]) {
623
+ items.push(item);
498
624
  }
499
- return Boolean(item[1].create);
625
+ } else if (item[1].create) {
626
+ items.push(item);
500
627
  }
501
- );
502
- if (create.length) {
503
- await t._count()._createMany(
504
- create.map(([selfData, item]) => __spreadValues$5({
505
- [foreignKey]: selfData[primaryKey]
506
- }, "create" in item ? item.create : item.connectOrCreate.create))
507
- );
628
+ }
629
+ if (items.length) {
630
+ for (let i = 0, len = items.length; i < len; i++) {
631
+ const [selfData, item] = items[i];
632
+ const data2 = __spreadValues$5({}, "create" in item ? item.create : item.connectOrCreate.create);
633
+ for (let i2 = 0; i2 < primaryKeys.length; i2++) {
634
+ data2[foreignKeys[i2]] = selfData[primaryKeys[i2]];
635
+ }
636
+ items[i] = data2;
637
+ }
638
+ await t._count()._createMany(items);
508
639
  }
509
640
  };
510
641
  };
511
- const nestedUpdate$2 = ({ query, primaryKey, foreignKey }) => {
642
+ const nestedUpdate$2 = ({ query, primaryKeys, foreignKeys }) => {
643
+ const len = primaryKeys.length;
644
+ const setNulls = {};
645
+ for (const foreignKey of foreignKeys) {
646
+ setNulls[foreignKey] = null;
647
+ }
512
648
  return async (_, data, params) => {
513
649
  const t = query.clone();
514
- const ids = data.map((item) => item[primaryKey]);
515
- const currentRelationsQuery = t.where({
516
- [foreignKey]: { in: ids }
517
- });
650
+ const ids = data.map(
651
+ (item) => primaryKeys.map((primaryKey) => item[primaryKey])
652
+ );
653
+ const currentRelationsQuery = t.whereIn(
654
+ foreignKeys,
655
+ ids
656
+ );
518
657
  if (params.create || params.disconnect || params.set) {
519
- await currentRelationsQuery._update({ [foreignKey]: null });
658
+ await currentRelationsQuery._update(
659
+ setNulls
660
+ );
661
+ const record = data[0];
520
662
  if (params.create) {
521
- await t._count()._create(__spreadProps$3(__spreadValues$5({}, params.create), {
522
- [foreignKey]: data[0][primaryKey]
523
- }));
663
+ const obj = __spreadValues$5({}, params.create);
664
+ for (let i = 0; i < len; i++) {
665
+ obj[foreignKeys[i]] = record[primaryKeys[i]];
666
+ }
667
+ await t._count()._create(obj);
524
668
  }
525
669
  if (params.set) {
526
- await t._where(params.set)._update({ [foreignKey]: data[0][primaryKey] });
670
+ const obj = {};
671
+ for (let i = 0; i < len; i++) {
672
+ obj[foreignKeys[i]] = record[primaryKeys[i]];
673
+ }
674
+ await t._where(params.set)._update(obj);
527
675
  }
528
676
  } else if (params.update) {
529
677
  await currentRelationsQuery._update(params.update);
@@ -531,13 +679,23 @@ const nestedUpdate$2 = ({ query, primaryKey, foreignKey }) => {
531
679
  await currentRelationsQuery._delete();
532
680
  } else if (params.upsert) {
533
681
  const { update, create } = params.upsert;
534
- const updatedIds = await currentRelationsQuery._pluck(foreignKey)._update(update);
682
+ currentRelationsQuery.q.select = foreignKeys;
683
+ const updatedIds = await currentRelationsQuery._rows()._update(update);
535
684
  if (updatedIds.length < ids.length) {
536
685
  const data2 = typeof create === "function" ? create() : create;
537
686
  await t.createMany(
538
- ids.filter((id) => !updatedIds.includes(id)).map((id) => __spreadProps$3(__spreadValues$5({}, data2), {
539
- [foreignKey]: id
540
- }))
687
+ ids.reduce((rows, ids2) => {
688
+ if (!updatedIds.some(
689
+ (updated) => updated.every((value, i) => value === ids2[i])
690
+ )) {
691
+ const obj = __spreadValues$5({}, data2);
692
+ for (let i = 0; i < len; i++) {
693
+ obj[foreignKeys[i]] = ids2[i];
694
+ }
695
+ rows.push(obj);
696
+ }
697
+ return rows;
698
+ }, [])
541
699
  );
542
700
  }
543
701
  }
@@ -545,8 +703,6 @@ const nestedUpdate$2 = ({ query, primaryKey, foreignKey }) => {
545
703
  };
546
704
 
547
705
  var __defProp$4 = Object.defineProperty;
548
- var __defProps$2 = Object.defineProperties;
549
- var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors;
550
706
  var __getOwnPropSymbols$4 = Object.getOwnPropertySymbols;
551
707
  var __hasOwnProp$4 = Object.prototype.hasOwnProperty;
552
708
  var __propIsEnum$4 = Object.prototype.propertyIsEnumerable;
@@ -562,7 +718,6 @@ var __spreadValues$4 = (a, b) => {
562
718
  }
563
719
  return a;
564
720
  };
565
- var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b));
566
721
  class HasManyVirtualColumn extends VirtualColumn {
567
722
  constructor(key, state) {
568
723
  super();
@@ -578,7 +733,7 @@ class HasManyVirtualColumn extends VirtualColumn {
578
733
  item,
579
734
  rowIndex,
580
735
  this.key,
581
- this.state.primaryKey,
736
+ this.state.primaryKeys,
582
737
  this.nestedInsert
583
738
  );
584
739
  }
@@ -592,7 +747,7 @@ class HasManyVirtualColumn extends VirtualColumn {
592
747
  q,
593
748
  set,
594
749
  this.key,
595
- this.state.primaryKey,
750
+ this.state.primaryKeys,
596
751
  this.nestedUpdate
597
752
  );
598
753
  }
@@ -618,46 +773,49 @@ const makeHasManyMethod = (table, relation, relationName, query) => {
618
773
  );
619
774
  },
620
775
  joinQuery(fromQuery, toQuery) {
621
- return toQuery.whereExists(
622
- throughRelation.joinQuery(fromQuery, throughRelation.query),
623
- () => {
624
- const as = getQueryAs(toQuery);
625
- return sourceRelation.joinQuery(
626
- throughRelation.query,
627
- sourceRelation.query.as(as)
628
- );
629
- }
776
+ return joinHasThrough(
777
+ toQuery,
778
+ fromQuery,
779
+ toQuery,
780
+ throughRelation,
781
+ sourceRelation
630
782
  );
631
783
  },
632
784
  reverseJoin(fromQuery, toQuery) {
633
- return fromQuery.whereExists(
634
- throughRelation.joinQuery(fromQuery, throughRelation.query),
635
- () => {
636
- const as = getQueryAs(toQuery);
637
- return sourceRelation.joinQuery(
638
- throughRelation.query,
639
- sourceRelation.query.as(as)
640
- );
641
- }
785
+ return joinHasThrough(
786
+ fromQuery,
787
+ fromQuery,
788
+ toQuery,
789
+ throughRelation,
790
+ sourceRelation
642
791
  );
643
792
  }
644
793
  };
645
794
  }
646
- const { primaryKey, foreignKey } = relation.options;
647
- const state = { query, primaryKey, foreignKey };
648
- const fromQuerySelect = [{ selectAs: { [foreignKey]: primaryKey } }];
795
+ const primaryKeys = "columns" in relation.options ? relation.options.columns : [relation.options.primaryKey];
796
+ const foreignKeys = "columns" in relation.options ? relation.options.references : [relation.options.foreignKey];
797
+ const state = { query, primaryKeys, foreignKeys };
798
+ const len = primaryKeys.length;
799
+ const reversedOn = {};
800
+ for (let i = 0; i < len; i++) {
801
+ reversedOn[foreignKeys[i]] = primaryKeys[i];
802
+ }
803
+ const fromQuerySelect = [{ selectAs: reversedOn }];
649
804
  return {
650
805
  returns: "many",
651
806
  method: (params) => {
652
- const values = { [foreignKey]: params[primaryKey] };
807
+ const values = {};
808
+ for (let i = 0; i < len; i++) {
809
+ values[foreignKeys[i]] = params[primaryKeys[i]];
810
+ }
653
811
  return query.where(values)._defaults(values);
654
812
  },
655
813
  virtualColumn: new HasManyVirtualColumn(relationName, state),
656
814
  joinQuery(fromQuery, toQuery) {
657
- return addQueryOn(toQuery, fromQuery, toQuery, foreignKey, primaryKey);
815
+ return joinHasRelation(fromQuery, toQuery, primaryKeys, foreignKeys, len);
658
816
  },
659
817
  reverseJoin(fromQuery, toQuery) {
660
- return addQueryOn(fromQuery, toQuery, fromQuery, primaryKey, foreignKey);
818
+ return joinHasRelation(toQuery, fromQuery, foreignKeys, primaryKeys, len);
661
819
  },
662
820
  modifyRelatedQuery(relationQuery) {
663
821
  return (query2) => {
@@ -670,121 +828,150 @@ const makeHasManyMethod = (table, relation, relationName, query) => {
670
828
  }
671
829
  };
672
830
  };
673
- const getWhereForNestedUpdate = (data, params, primaryKey, foreignKey) => {
674
- const where = {
675
- [foreignKey]: { in: data.map((item) => item[primaryKey]) }
676
- };
677
- if (params) {
678
- if (Array.isArray(params)) {
679
- where.OR = params;
680
- } else {
681
- Object.assign(where, params);
682
- }
683
- }
684
- return where;
831
+ const getWhereForNestedUpdate = (t, data, params, primaryKeys, foreignKeys) => {
832
+ return t.where({
833
+ IN: {
834
+ columns: foreignKeys,
835
+ values: data.map((item) => primaryKeys.map((key) => item[key]))
836
+ },
837
+ OR: params ? toArray(params) : void 0
838
+ });
685
839
  };
686
- const nestedInsert$1 = ({ query, primaryKey, foreignKey }) => {
840
+ const nestedInsert$1 = ({ query, primaryKeys, foreignKeys }) => {
841
+ const len = primaryKeys.length;
687
842
  return async (_, data) => {
688
- const connect = data.filter(
689
- (item) => Boolean(item[1].connect)
690
- );
691
843
  const t = query.clone();
692
- if (connect.length) {
693
- await Promise.all(
694
- connect.flatMap(
695
- ([selfData, { connect: connect2 }]) => t.or(...connect2)._updateOrThrow({
696
- [foreignKey]: selfData[primaryKey]
697
- })
698
- )
699
- );
844
+ const items = [];
845
+ for (const item of data) {
846
+ if (item[1].connect) {
847
+ items.push(item);
848
+ }
849
+ }
850
+ if (items.length) {
851
+ for (let i = 0, len2 = items.length; i < len2; i++) {
852
+ const [selfData, { connect }] = items[i];
853
+ const obj = {};
854
+ for (let i2 = 0; i2 < len2; i2++) {
855
+ obj[foreignKeys[i2]] = selfData[primaryKeys[i2]];
856
+ }
857
+ items[i] = t.or(...connect)._updateOrThrow(obj);
858
+ }
859
+ await Promise.all(items);
860
+ }
861
+ items.length = 0;
862
+ for (const item of data) {
863
+ if (item[1].connectOrCreate) {
864
+ items.push(item);
865
+ }
700
866
  }
701
- const connectOrCreate = data.filter(
702
- (item) => Boolean(item[1].connectOrCreate)
703
- );
704
867
  let connected;
705
- if (connectOrCreate.length) {
706
- connected = await Promise.all(
707
- connectOrCreate.flatMap(
708
- ([selfData, { connectOrCreate: connectOrCreate2 }]) => connectOrCreate2.map(
709
- (item) => t.where(item.where)._update({
710
- [foreignKey]: selfData[primaryKey]
711
- })
712
- )
713
- )
714
- );
868
+ if (items.length) {
869
+ const queries = [];
870
+ for (let i = 0, len2 = items.length; i < len2; i++) {
871
+ const [selfData, { connectOrCreate }] = items[i];
872
+ for (const item of connectOrCreate) {
873
+ const obj = {};
874
+ for (let i2 = 0; i2 < len2; i2++) {
875
+ obj[foreignKeys[i2]] = selfData[primaryKeys[i2]];
876
+ }
877
+ queries.push(
878
+ t.where(item.where)._update(obj)
879
+ );
880
+ }
881
+ }
882
+ connected = await Promise.all(queries);
715
883
  } else {
716
884
  connected = [];
717
885
  }
718
886
  let connectedI = 0;
719
- const create = data.filter(
720
- (item) => {
721
- if (item[1].connectOrCreate) {
722
- const length = item[1].connectOrCreate.length;
723
- connectedI += length;
724
- for (let i = length; i > 0; i--) {
725
- if (connected[connectedI - i] === 0)
726
- return true;
887
+ items.length = 0;
888
+ for (const item of data) {
889
+ if (item[1].connectOrCreate) {
890
+ const length = item[1].connectOrCreate.length;
891
+ connectedI += length;
892
+ for (let i = length; i > 0; i--) {
893
+ if (connected[connectedI - i] === 0) {
894
+ items.push(item);
895
+ break;
727
896
  }
728
897
  }
729
- return Boolean(item[1].create);
898
+ } else if (item[1].create) {
899
+ items.push(item);
730
900
  }
731
- );
901
+ }
732
902
  connectedI = 0;
733
- if (create.length) {
734
- await t._createMany(
735
- create.flatMap(([selfData, { create: create2 = [], connectOrCreate: connectOrCreate2 = [] }]) => {
736
- return [
737
- ...create2.map((item) => __spreadValues$4({
738
- [foreignKey]: selfData[primaryKey]
739
- }, item)),
740
- ...connectOrCreate2.filter(() => connected[connectedI++] === 0).map((item) => __spreadValues$4({
741
- [foreignKey]: selfData[primaryKey]
742
- }, item.create))
743
- ];
744
- })
745
- );
903
+ if (items.length) {
904
+ const records = [];
905
+ for (const [selfData, { create, connectOrCreate }] of items) {
906
+ const obj = {};
907
+ for (let i = 0; i < len; i++) {
908
+ obj[foreignKeys[i]] = selfData[primaryKeys[i]];
909
+ }
910
+ if (create) {
911
+ for (const item of create) {
912
+ records.push(__spreadValues$4(__spreadValues$4({}, item), obj));
913
+ }
914
+ }
915
+ if (connectOrCreate) {
916
+ for (const item of connectOrCreate) {
917
+ if (connected[connectedI++] === 0) {
918
+ records.push(__spreadValues$4(__spreadValues$4({}, item.create), obj));
919
+ }
920
+ }
921
+ }
922
+ }
923
+ await t._createMany(records);
746
924
  }
747
925
  };
748
926
  };
749
- const nestedUpdate$1 = ({ query, primaryKey, foreignKey }) => {
927
+ const nestedUpdate$1 = ({ query, primaryKeys, foreignKeys }) => {
928
+ const len = primaryKeys.length;
750
929
  return async (_, data, params) => {
751
930
  var _a;
752
931
  const t = query.clone();
753
932
  if (params.create) {
933
+ const obj = {};
934
+ for (let i = 0; i < len; i++) {
935
+ obj[foreignKeys[i]] = data[0][primaryKeys[i]];
936
+ }
754
937
  await t._count()._createMany(
755
- params.create.map((create) => __spreadProps$2(__spreadValues$4({}, create), {
756
- [foreignKey]: data[0][primaryKey]
757
- }))
938
+ params.create.map((create) => __spreadValues$4(__spreadValues$4({}, create), obj))
758
939
  );
759
940
  delete t.q[toSQLCacheKey];
760
941
  }
761
942
  if (params.disconnect || params.set) {
762
- await t.where(
763
- getWhereForNestedUpdate(
764
- data,
765
- params.disconnect,
766
- primaryKey,
767
- foreignKey
768
- )
769
- )._update({ [foreignKey]: null });
943
+ const obj = {};
944
+ for (const foreignKey of foreignKeys) {
945
+ obj[foreignKey] = null;
946
+ }
947
+ await getWhereForNestedUpdate(
948
+ t,
949
+ data,
950
+ params.disconnect,
951
+ primaryKeys,
952
+ foreignKeys
953
+ )._update(obj);
770
954
  if (params.set) {
771
955
  delete t.q[toSQLCacheKey];
956
+ const obj2 = {};
957
+ for (let i = 0; i < len; i++) {
958
+ obj2[foreignKeys[i]] = data[0][primaryKeys[i]];
959
+ }
772
960
  await t.where(
773
961
  Array.isArray(params.set) ? {
774
962
  OR: params.set
775
963
  } : params.set
776
- )._update({ [foreignKey]: data[0][primaryKey] });
964
+ )._update(obj2);
777
965
  }
778
966
  }
779
967
  if (params.delete || params.update) {
780
968
  delete t.q[toSQLCacheKey];
781
- const q = t._where(
782
- getWhereForNestedUpdate(
783
- data,
784
- params.delete || ((_a = params.update) == null ? void 0 : _a.where),
785
- primaryKey,
786
- foreignKey
787
- )
969
+ const q = getWhereForNestedUpdate(
970
+ t,
971
+ data,
972
+ params.delete || ((_a = params.update) == null ? void 0 : _a.where),
973
+ primaryKeys,
974
+ foreignKeys
788
975
  );
789
976
  if (params.delete) {
790
977
  await q._delete();
@@ -829,7 +1016,7 @@ class HasAndBelongsToManyVirtualColumn extends VirtualColumn {
829
1016
  item,
830
1017
  rowIndex,
831
1018
  this.key,
832
- this.state.primaryKey,
1019
+ this.state.primaryKeys,
833
1020
  this.nestedInsert
834
1021
  );
835
1022
  }
@@ -838,7 +1025,7 @@ class HasAndBelongsToManyVirtualColumn extends VirtualColumn {
838
1025
  q,
839
1026
  set,
840
1027
  this.key,
841
- this.state.primaryKey,
1028
+ this.state.primaryKeys,
842
1029
  this.nestedUpdate
843
1030
  );
844
1031
  }
@@ -851,23 +1038,48 @@ const removeColumnName = (column) => {
851
1038
  return cloned;
852
1039
  };
853
1040
  const makeHasAndBelongsToManyMethod = (table, qb, relation, relationName, query) => {
854
- const {
855
- primaryKey: pk,
856
- foreignKey: fk,
857
- associationPrimaryKey: apk,
858
- associationForeignKey: afk,
859
- joinTable
860
- } = relation.options;
861
- const foreignKeyFull = `${joinTable}.${fk}`;
862
- const associationForeignKeyFull = `${joinTable}.${afk}`;
863
- const associationPrimaryKeyFull = `${getQueryAs(query)}.${apk}`;
1041
+ let primaryKeys;
1042
+ let foreignKeys;
1043
+ let joinTable;
1044
+ let throughForeignKeys;
1045
+ let throughPrimaryKeys;
1046
+ const { options } = relation;
1047
+ if ("columns" in options) {
1048
+ primaryKeys = options.columns;
1049
+ foreignKeys = options.references;
1050
+ joinTable = options.through.table;
1051
+ throughForeignKeys = options.through.columns;
1052
+ throughPrimaryKeys = options.through.references;
1053
+ } else {
1054
+ primaryKeys = [options.primaryKey];
1055
+ foreignKeys = [options.foreignKey];
1056
+ joinTable = options.joinTable;
1057
+ throughForeignKeys = [options.associationForeignKey];
1058
+ throughPrimaryKeys = [options.associationPrimaryKey];
1059
+ }
1060
+ const foreignKeysFull = foreignKeys.map((key) => `${joinTable}.${key}`);
1061
+ const throughForeignKeysFull = throughForeignKeys.map(
1062
+ (key) => `${joinTable}.${key}`
1063
+ );
1064
+ const foreignTable = getQueryAs(query);
1065
+ const throughPrimaryKeysFull = throughPrimaryKeys.map(
1066
+ (key) => `${foreignTable}.${key}`
1067
+ );
1068
+ const len = primaryKeys.length;
1069
+ const throughLen = throughPrimaryKeys.length;
864
1070
  const baseQuery = Object.create(qb.baseQuery);
865
1071
  baseQuery.baseQuery = baseQuery;
866
1072
  baseQuery.table = joinTable;
867
- baseQuery.shape = {
868
- [fk]: removeColumnName(table.shape[pk]),
869
- [afk]: removeColumnName(query.shape[apk])
870
- };
1073
+ const shape = {};
1074
+ for (let i = 0; i < len; i++) {
1075
+ shape[foreignKeys[i]] = removeColumnName(table.shape[primaryKeys[i]]);
1076
+ }
1077
+ for (let i = 0; i < throughLen; i++) {
1078
+ shape[throughForeignKeys[i]] = removeColumnName(
1079
+ query.shape[throughPrimaryKeys[i]]
1080
+ );
1081
+ }
1082
+ baseQuery.shape = shape;
871
1083
  baseQuery.q = __spreadProps$1(__spreadValues$3({}, baseQuery.q), {
872
1084
  shape: baseQuery.shape
873
1085
  });
@@ -875,31 +1087,56 @@ const makeHasAndBelongsToManyMethod = (table, qb, relation, relationName, query)
875
1087
  const state = {
876
1088
  relatedTableQuery: query,
877
1089
  joinTableQuery: subQuery,
878
- primaryKey: pk,
879
- foreignKey: fk,
880
- associationPrimaryKey: apk,
881
- associationForeignKey: afk,
882
- foreignKeyFull,
883
- associationForeignKeyFull,
884
- associationPrimaryKeyFull
1090
+ primaryKeys,
1091
+ foreignKeys,
1092
+ throughForeignKeys,
1093
+ throughPrimaryKeys,
1094
+ foreignKeysFull,
1095
+ throughForeignKeysFull,
1096
+ throughPrimaryKeysFull
885
1097
  };
1098
+ const joinQuery = (toQuery, tableAs, foreignAs) => {
1099
+ return toQuery.whereExists(subQuery, (q) => {
1100
+ for (let i = 0; i < throughLen; i++) {
1101
+ q._on(
1102
+ throughForeignKeysFull[i],
1103
+ `${foreignAs}.${throughPrimaryKeys[i]}`
1104
+ );
1105
+ }
1106
+ for (let i = 0; i < len; i++) {
1107
+ q._on(foreignKeysFull[i], `${tableAs}.${primaryKeys[i]}`);
1108
+ }
1109
+ return q;
1110
+ });
1111
+ };
1112
+ const obj = {};
1113
+ for (let i = 0; i < len; i++) {
1114
+ obj[foreignKeys[i]] = primaryKeys[i];
1115
+ }
1116
+ const selectPrimaryKeysAsForeignKeys = [{ selectAs: obj }];
886
1117
  return {
887
1118
  returns: "many",
888
1119
  method(params) {
889
- return query.whereExists(
890
- subQuery,
891
- (q) => q.on(associationForeignKeyFull, associationPrimaryKeyFull).where({
892
- [foreignKeyFull]: params[pk]
893
- })
894
- );
1120
+ return query.whereExists(subQuery, (q) => {
1121
+ q = q.clone();
1122
+ const where = {};
1123
+ for (let i = 0; i < len; i++) {
1124
+ where[foreignKeysFull[i]] = params[primaryKeys[i]];
1125
+ }
1126
+ for (let i = 0; i < throughLen; i++) {
1127
+ q._on(throughForeignKeysFull[i], throughPrimaryKeysFull[i]);
1128
+ }
1129
+ return q._where(where);
1130
+ });
895
1131
  },
896
1132
  virtualColumn: new HasAndBelongsToManyVirtualColumn(relationName, state),
897
1133
  // joinQuery can be a property of RelationQuery and be used by whereExists and other stuff which needs it
898
1134
  // and the chained query itself may be a query around this joinQuery
899
1135
  joinQuery(fromQuery, toQuery) {
900
- const join = toQuery.whereExists(
901
- subQuery,
902
- (q) => q._on(associationForeignKeyFull, `${getQueryAs(toQuery)}.${apk}`)._on(foreignKeyFull, `${getQueryAs(fromQuery)}.${pk}`)
1136
+ const join = joinQuery(
1137
+ toQuery,
1138
+ getQueryAs(fromQuery),
1139
+ getQueryAs(toQuery)
903
1140
  );
904
1141
  join.q.joinedShapes = __spreadProps$1(__spreadValues$3({}, join.q.joinedShapes), {
905
1142
  [fromQuery.q.as || fromQuery.table]: fromQuery.q.shape
@@ -907,10 +1144,7 @@ const makeHasAndBelongsToManyMethod = (table, qb, relation, relationName, query)
907
1144
  return join;
908
1145
  },
909
1146
  reverseJoin(fromQuery, toQuery) {
910
- return fromQuery.whereExists(
911
- subQuery,
912
- (q) => q._on(associationForeignKeyFull, `${getQueryAs(toQuery)}.${apk}`)._on(foreignKeyFull, `${getQueryAs(fromQuery)}.${pk}`)
913
- );
1147
+ return joinQuery(fromQuery, getQueryAs(fromQuery), getQueryAs(toQuery));
914
1148
  },
915
1149
  modifyRelatedQuery(relationQuery) {
916
1150
  const ref = {};
@@ -922,14 +1156,12 @@ const makeHasAndBelongsToManyMethod = (table, qb, relation, relationName, query)
922
1156
  );
923
1157
  }
924
1158
  const fromQuery = ref.q.clone();
925
- fromQuery.q.select = [{ selectAs: { [fk]: pk } }];
926
- const createdCount = await subQuery.count()._createFrom(
927
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
928
- fromQuery,
929
- {
930
- [afk]: result[0][apk]
931
- }
932
- );
1159
+ fromQuery.q.select = selectPrimaryKeysAsForeignKeys;
1160
+ const data = {};
1161
+ for (let i = 0; i < throughLen; i++) {
1162
+ data[throughForeignKeys[i]] = result[0][throughPrimaryKeys[i]];
1163
+ }
1164
+ const createdCount = await subQuery.count()._createFrom(fromQuery, data);
933
1165
  if (createdCount === 0) {
934
1166
  throw new NotFoundError(fromQuery);
935
1167
  }
@@ -941,97 +1173,127 @@ const makeHasAndBelongsToManyMethod = (table, qb, relation, relationName, query)
941
1173
  };
942
1174
  };
943
1175
  const queryJoinTable = (state, data, conditions) => {
944
- const t = state.joinTableQuery.clone();
945
- const where = {
946
- [state.foreignKey]: { in: data.map((item) => item[state.primaryKey]) }
947
- };
1176
+ const t = state.joinTableQuery.where({
1177
+ IN: {
1178
+ columns: state.foreignKeys,
1179
+ values: data.map((item) => state.primaryKeys.map((key) => item[key]))
1180
+ }
1181
+ });
948
1182
  if (conditions) {
949
- where[state.associationForeignKey] = {
950
- in: state.relatedTableQuery.where(
951
- Array.isArray(conditions) ? { OR: conditions } : conditions
952
- )._select(state.associationPrimaryKey)
953
- };
1183
+ t._where({
1184
+ IN: {
1185
+ columns: state.throughForeignKeys,
1186
+ values: state.relatedTableQuery.where(conditionsToWhereArg(conditions))._select(...state.throughPrimaryKeys)
1187
+ }
1188
+ });
954
1189
  }
955
- return t._where(where);
956
- };
957
- const queryRelatedTable = (query, conditions) => {
958
- return query.where(
959
- Array.isArray(conditions) ? { OR: conditions } : conditions
960
- );
1190
+ return t;
961
1191
  };
962
- const insertToJoinTable = (state, joinTableTransaction, data, ids) => {
963
- return joinTableTransaction._count()._createMany(
964
- data.flatMap(
965
- (item) => ids.map((id) => ({
966
- [state.foreignKey]: item[state.primaryKey],
967
- [state.associationForeignKey]: id
968
- }))
969
- )
970
- );
1192
+ const conditionsToWhereArg = (conditions) => Array.isArray(conditions) ? { OR: conditions } : conditions;
1193
+ const insertToJoinTable = (state, joinTableTransaction, data, idsRows) => {
1194
+ const len = state.primaryKeys.length;
1195
+ const throughLen = state.throughPrimaryKeys.length;
1196
+ const records = [];
1197
+ for (const item of data) {
1198
+ const obj = {};
1199
+ for (let i = 0; i < len; i++) {
1200
+ obj[state.foreignKeys[i]] = item[state.primaryKeys[i]];
1201
+ }
1202
+ for (const ids of idsRows) {
1203
+ const record = __spreadValues$3({}, obj);
1204
+ for (let i = 0; i < throughLen; i++) {
1205
+ record[state.throughForeignKeys[i]] = ids[i];
1206
+ }
1207
+ records.push(record);
1208
+ }
1209
+ }
1210
+ return joinTableTransaction._count()._createMany(records);
971
1211
  };
972
1212
  const nestedInsert = ({
973
1213
  relatedTableQuery,
974
1214
  joinTableQuery,
975
- primaryKey,
976
- foreignKey,
977
- associationPrimaryKey,
978
- associationForeignKey
1215
+ primaryKeys,
1216
+ foreignKeys,
1217
+ throughPrimaryKeys,
1218
+ throughForeignKeys
979
1219
  }) => {
1220
+ const len = primaryKeys.length;
1221
+ const throughLen = primaryKeys.length;
980
1222
  return async (_, data) => {
981
- const connect = data.filter(
982
- (item) => Boolean(item[1].connect)
983
- );
984
1223
  const t = relatedTableQuery.clone();
1224
+ const items = [];
1225
+ for (const item of data) {
1226
+ if (item[1].connect) {
1227
+ items.push(item);
1228
+ }
1229
+ }
985
1230
  let connected;
986
- if (connect.length) {
987
- connected = await Promise.all(
988
- connect.flatMap(
989
- ([, { connect: connect2 }]) => connect2.map(
990
- (item) => t.select(associationPrimaryKey)._findBy(item)._take()
991
- )
992
- )
993
- );
1231
+ if (items.length) {
1232
+ const queries = [];
1233
+ for (const [, { connect }] of items) {
1234
+ for (const item of connect) {
1235
+ queries.push(
1236
+ t.select(...throughPrimaryKeys)._findBy(item)._take()
1237
+ );
1238
+ }
1239
+ }
1240
+ connected = await Promise.all(queries);
994
1241
  } else {
995
1242
  connected = [];
996
1243
  }
997
- const connectOrCreate = data.filter(
998
- (item) => Boolean(item[1].connectOrCreate)
999
- );
1244
+ items.length = 0;
1245
+ for (const item of data) {
1246
+ if (item[1].connectOrCreate) {
1247
+ items.push(item);
1248
+ }
1249
+ }
1000
1250
  let connectOrCreated;
1001
- if (connectOrCreate.length) {
1002
- connectOrCreated = await Promise.all(
1003
- connectOrCreate.flatMap(
1004
- ([, { connectOrCreate: connectOrCreate2 }]) => connectOrCreate2.map(
1005
- (item) => t.select(associationPrimaryKey)._findBy(item.where)._takeOptional()
1006
- )
1007
- )
1008
- );
1251
+ if (items.length) {
1252
+ const queries = [];
1253
+ for (const [, { connectOrCreate }] of items) {
1254
+ for (const item of connectOrCreate) {
1255
+ queries.push(
1256
+ t.select(...throughPrimaryKeys)._findBy(item.where)._takeOptional()
1257
+ );
1258
+ }
1259
+ }
1260
+ connectOrCreated = await Promise.all(queries);
1009
1261
  } else {
1010
1262
  connectOrCreated = [];
1011
1263
  }
1012
1264
  let connectOrCreateI = 0;
1013
- const create = data.filter(
1014
- (item) => {
1015
- if (item[1].connectOrCreate) {
1016
- const length = item[1].connectOrCreate.length;
1017
- connectOrCreateI += length;
1018
- for (let i = length; i > 0; i--) {
1019
- if (!connectOrCreated[connectOrCreateI - i])
1020
- return true;
1265
+ items.length = 0;
1266
+ for (const item of data) {
1267
+ if (item[1].connectOrCreate) {
1268
+ const length = item[1].connectOrCreate.length;
1269
+ connectOrCreateI += length;
1270
+ for (let i = length; i > 0; i--) {
1271
+ if (!connectOrCreated[connectOrCreateI - i]) {
1272
+ items.push(item);
1273
+ break;
1021
1274
  }
1022
1275
  }
1023
- return Boolean(item[1].create);
1276
+ } else if (item[1].create) {
1277
+ items.push(item);
1024
1278
  }
1025
- );
1279
+ }
1026
1280
  connectOrCreateI = 0;
1027
1281
  let created;
1028
- if (create.length) {
1029
- created = await t.select(associationPrimaryKey)._createMany(
1030
- create.flatMap(([, { create: create2 = [], connectOrCreate: connectOrCreate2 = [] }]) => [
1031
- ...create2,
1032
- ...connectOrCreate2.filter(() => !connectOrCreated[connectOrCreateI++]).map((item) => item.create)
1033
- ])
1034
- );
1282
+ if (items.length) {
1283
+ const records2 = [];
1284
+ for (const [, { create, connectOrCreate }] of items) {
1285
+ if (create) {
1286
+ records2.push(...create);
1287
+ }
1288
+ if (connectOrCreate) {
1289
+ for (const item of connectOrCreate) {
1290
+ if (!connectOrCreated[connectOrCreateI++]) {
1291
+ records2.push(item.create);
1292
+ }
1293
+ }
1294
+ }
1295
+ }
1296
+ created = await t.select(...throughPrimaryKeys)._createMany(records2);
1035
1297
  } else {
1036
1298
  created = [];
1037
1299
  }
@@ -1039,95 +1301,110 @@ const nestedInsert = ({
1039
1301
  let createI = 0;
1040
1302
  let connectI = 0;
1041
1303
  connectOrCreateI = 0;
1042
- data.forEach(([, data2], index) => {
1043
- if (data2.create || data2.connectOrCreate) {
1044
- if (data2.create) {
1045
- const len = data2.create.length;
1046
- allKeys[index][1] = created.slice(createI, createI + len);
1047
- createI += len;
1304
+ for (let index = 0, len2 = data.length; index < len2; index++) {
1305
+ const item = data[index][1];
1306
+ if (item.create || item.connectOrCreate) {
1307
+ if (item.create) {
1308
+ const len3 = item.create.length;
1309
+ allKeys[index][1] = created.slice(createI, createI + len3);
1310
+ createI += len3;
1048
1311
  }
1049
- if (data2.connectOrCreate) {
1312
+ if (item.connectOrCreate) {
1050
1313
  const arr = [];
1051
1314
  allKeys[index][1] = arr;
1052
- const len = data2.connectOrCreate.length;
1053
- for (let i = 0; i < len; i++) {
1054
- const item = connectOrCreated[connectOrCreateI++];
1055
- if (item) {
1056
- arr.push(item);
1315
+ const len3 = item.connectOrCreate.length;
1316
+ for (let i = 0; i < len3; i++) {
1317
+ const item2 = connectOrCreated[connectOrCreateI++];
1318
+ if (item2) {
1319
+ arr.push(item2);
1057
1320
  } else {
1058
1321
  arr.push(created[createI++]);
1059
1322
  }
1060
1323
  }
1061
1324
  }
1062
1325
  }
1063
- if (data2.connect) {
1064
- const len = data2.connect.length;
1065
- allKeys[index][1] = connected.slice(connectI, connectI + len);
1066
- connectI += len;
1326
+ if (item.connect) {
1327
+ const len3 = item.connect.length;
1328
+ allKeys[index][1] = connected.slice(connectI, connectI + len3);
1329
+ connectI += len3;
1067
1330
  }
1068
- });
1069
- await joinTableQuery.count()._createMany(
1070
- allKeys.flatMap(([selfData, relationKeys]) => {
1071
- const selfKey = selfData[primaryKey];
1072
- return relationKeys.map((relationData) => ({
1073
- [foreignKey]: selfKey,
1074
- [associationForeignKey]: relationData[associationPrimaryKey]
1075
- }));
1076
- })
1077
- );
1331
+ }
1332
+ const records = [];
1333
+ for (const [selfData, relationKeys] of allKeys) {
1334
+ const obj = {};
1335
+ for (let i = 0; i < len; i++) {
1336
+ obj[foreignKeys[i]] = selfData[primaryKeys[i]];
1337
+ }
1338
+ for (const relationData of relationKeys) {
1339
+ const record = __spreadValues$3({}, obj);
1340
+ for (let i = 0; i < throughLen; i++) {
1341
+ record[throughForeignKeys[i]] = relationData[throughPrimaryKeys[i]];
1342
+ }
1343
+ records.push(record);
1344
+ }
1345
+ }
1346
+ await joinTableQuery.count()._createMany(records);
1078
1347
  };
1079
1348
  };
1080
1349
  const nestedUpdate = (state) => {
1350
+ const len = state.primaryKeys.length;
1351
+ const throughLen = state.throughPrimaryKeys.length;
1081
1352
  return async (_, data, params) => {
1082
1353
  if (params.create) {
1083
- const ids = await state.relatedTableQuery.pluck(state.associationPrimaryKey)._createMany(params.create);
1084
- await state.joinTableQuery.createMany(
1085
- data.flatMap(
1086
- (item) => ids.map((id) => ({
1087
- [state.foreignKey]: item[state.primaryKey],
1088
- [state.associationForeignKey]: id
1089
- }))
1090
- )
1091
- );
1354
+ const idsRows = await state.relatedTableQuery.select(...state.throughPrimaryKeys)._rows()._createMany(params.create);
1355
+ const records = [];
1356
+ for (const item of data) {
1357
+ const obj = {};
1358
+ for (let i = 0; i < len; i++) {
1359
+ obj[state.foreignKeys[i]] = item[state.primaryKeys[i]];
1360
+ }
1361
+ for (const ids of idsRows) {
1362
+ const record = __spreadValues$3({}, obj);
1363
+ for (let i = 0; i < throughLen; i++) {
1364
+ record[state.throughForeignKeys[i]] = ids[i];
1365
+ }
1366
+ records.push(record);
1367
+ }
1368
+ }
1369
+ await state.joinTableQuery.createMany(records);
1092
1370
  }
1093
1371
  if (params.update) {
1094
- await state.relatedTableQuery.whereExists(
1095
- state.joinTableQuery,
1096
- (q) => (
1097
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1372
+ await state.relatedTableQuery.whereExists(state.joinTableQuery, (q) => {
1373
+ for (let i = 0; i < throughLen; i++) {
1098
1374
  q._on(
1099
- state.associationForeignKeyFull,
1100
- state.associationPrimaryKeyFull
1101
- )._where({
1102
- IN: {
1103
- columns: [state.foreignKeyFull],
1104
- values: [data.map((item) => item[state.primaryKey])]
1105
- }
1106
- })
1107
- )
1108
- )._where(
1109
- Array.isArray(params.update.where) ? { OR: params.update.where } : params.update.where
1110
- )._update(params.update.data);
1375
+ state.throughForeignKeysFull[i],
1376
+ state.throughPrimaryKeysFull[i]
1377
+ );
1378
+ }
1379
+ return q._where({
1380
+ IN: {
1381
+ columns: state.foreignKeysFull,
1382
+ values: data.map(
1383
+ (item) => state.primaryKeys.map((key) => item[key])
1384
+ )
1385
+ }
1386
+ });
1387
+ })._where(conditionsToWhereArg(params.update.where))._update(params.update.data);
1111
1388
  }
1112
1389
  if (params.disconnect) {
1113
1390
  await queryJoinTable(state, data, params.disconnect)._delete();
1114
1391
  }
1115
1392
  if (params.delete) {
1116
1393
  const j = queryJoinTable(state, data, params.delete);
1117
- const ids = await j._pluck(state.associationForeignKey)._delete();
1118
- await queryRelatedTable(state.relatedTableQuery, {
1119
- [state.associationPrimaryKey]: { in: ids }
1394
+ const idsRows = await j._select(...state.throughForeignKeys)._rows()._delete();
1395
+ await state.relatedTableQuery.where({
1396
+ IN: {
1397
+ columns: state.throughPrimaryKeys,
1398
+ values: idsRows
1399
+ }
1120
1400
  })._delete();
1121
1401
  }
1122
1402
  if (params.set) {
1123
1403
  const j = queryJoinTable(state, data);
1124
1404
  await j._delete();
1125
1405
  delete j.q[toSQLCacheKey];
1126
- const ids = await queryRelatedTable(
1127
- state.relatedTableQuery,
1128
- params.set
1129
- )._pluck(state.associationPrimaryKey);
1130
- await insertToJoinTable(state, j, data, ids);
1406
+ const idsRows = await state.relatedTableQuery.where(conditionsToWhereArg(params.set))._select(...state.throughPrimaryKeys)._rows();
1407
+ await insertToJoinTable(state, j, data, idsRows);
1131
1408
  }
1132
1409
  };
1133
1410
  };