orchid-orm 1.3.15 → 1.4.16

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/index.d.ts +59 -54
  3. package/dist/index.esm.js +777 -547
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +776 -546
  6. package/dist/index.js.map +1 -1
  7. package/jest-setup.ts +4 -0
  8. package/package.json +8 -4
  9. package/src/appCodeUpdater/appCodeUpdater.ts +19 -0
  10. package/src/appCodeUpdater/fileChanges.ts +41 -0
  11. package/src/appCodeUpdater/testUtils.ts +31 -0
  12. package/src/appCodeUpdater/tsUtils.ts +137 -0
  13. package/src/appCodeUpdater/updateMainFile.test.ts +230 -0
  14. package/src/appCodeUpdater/updateMainFile.ts +163 -0
  15. package/src/appCodeUpdater/updateTableFile.ts +19 -0
  16. package/src/index.ts +5 -1
  17. package/src/orm.test.ts +13 -13
  18. package/src/orm.ts +21 -21
  19. package/src/relations/belongsTo.test.ts +1 -1
  20. package/src/relations/belongsTo.ts +291 -186
  21. package/src/relations/hasAndBelongsToMany.test.ts +1 -1
  22. package/src/relations/hasAndBelongsToMany.ts +292 -218
  23. package/src/relations/hasMany.test.ts +16 -10
  24. package/src/relations/hasMany.ts +243 -172
  25. package/src/relations/hasOne.test.ts +10 -10
  26. package/src/relations/hasOne.ts +211 -138
  27. package/src/relations/relations.ts +85 -77
  28. package/src/relations/utils.ts +154 -4
  29. package/src/repo.test.ts +29 -29
  30. package/src/repo.ts +6 -6
  31. package/src/{model.test.ts → table.test.ts} +15 -15
  32. package/src/{model.ts → table.ts} +17 -17
  33. package/src/test-utils/test-db.ts +15 -15
  34. package/src/test-utils/{test-models.ts → test-tables.ts} +42 -42
  35. package/src/transaction.test.ts +1 -1
  36. package/src/transaction.ts +4 -4
  37. package/src/utils.ts +9 -0
  38. package/tsconfig.json +1 -0
package/dist/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
- import { getColumnTypes, isQueryReturnsAll, addQueryOn, getQueryAs, toSqlCacheKey, pushQueryValue, NotFoundError, relationQueryKey, Db, Adapter, anyShape, columnTypes, getClonedQueryData } from 'pqb';
1
+ import { getColumnTypes, addQueryOn, VirtualColumn, pushQueryValue, isQueryReturnsAll, getQueryAs, toSqlCacheKey, NotFoundError, relationQueryKey, Db, Adapter, anyShape, columnTypes, getClonedQueryData } from 'pqb';
2
2
 
3
- const createModel = (options) => {
4
- return class Model {
3
+ const createBaseTable = (options) => {
4
+ return class BaseTable {
5
5
  constructor() {
6
6
  this.setColumns = (fn) => {
7
7
  const shape = getColumnTypes(options.columnTypes, fn);
@@ -47,150 +47,249 @@ const createModel = (options) => {
47
47
  };
48
48
  };
49
49
 
50
- const makeBelongsToMethod = (relation, query) => {
50
+ class BelongsToVirtualColumn extends VirtualColumn {
51
+ constructor(key, state) {
52
+ super();
53
+ this.key = key;
54
+ this.state = state;
55
+ this.nestedInsert = nestedInsert$3(this.state);
56
+ this.nestedUpdate = nestedUpdate$3(this.state);
57
+ }
58
+ create(q, ctx, item, rowIndex) {
59
+ const {
60
+ key,
61
+ state: { foreignKey, primaryKey }
62
+ } = this;
63
+ let columnIndex = ctx.columns.get(foreignKey);
64
+ if (columnIndex === void 0) {
65
+ ctx.columns.set(foreignKey, columnIndex = ctx.columns.size);
66
+ }
67
+ const store = ctx;
68
+ if (!store.belongsTo)
69
+ store.belongsTo = {};
70
+ const values = [rowIndex, columnIndex, item[key]];
71
+ if (store.belongsTo[key]) {
72
+ store.belongsTo[key].push(values);
73
+ return;
74
+ }
75
+ const relationData = [values];
76
+ store.belongsTo[key] = relationData;
77
+ q.query.wrapInTransaction = true;
78
+ pushQueryValue(q, "beforeCreate", async (q2) => {
79
+ const inserted = await this.nestedInsert(
80
+ q2,
81
+ relationData.map(([, , data]) => data)
82
+ );
83
+ const { values: values2 } = q2.query;
84
+ relationData.forEach(([rowIndex2, columnIndex2], index) => {
85
+ values2[rowIndex2][columnIndex2] = inserted[index][primaryKey];
86
+ });
87
+ });
88
+ }
89
+ update(q, ctx, set) {
90
+ q.query.wrapInTransaction = true;
91
+ const data = set[this.key];
92
+ if (this.nestedUpdate(q, set, data, ctx)) {
93
+ ctx.willSetKeys = true;
94
+ }
95
+ }
96
+ }
97
+ const makeBelongsToMethod = (relation, relationName, query) => {
51
98
  const { primaryKey, foreignKey } = relation.options;
99
+ const state = { query, primaryKey, foreignKey };
52
100
  return {
53
101
  returns: "one",
54
102
  method: (params) => {
55
103
  return query.findBy({ [primaryKey]: params[foreignKey] });
56
104
  },
57
- nestedInsert: async (q, data) => {
58
- const connectOrCreate = data.filter(
59
- (item) => Boolean(item.connectOrCreate)
105
+ virtualColumn: new BelongsToVirtualColumn(relationName, state),
106
+ joinQuery(fromQuery, toQuery) {
107
+ return addQueryOn(toQuery, fromQuery, toQuery, primaryKey, foreignKey);
108
+ },
109
+ reverseJoin(fromQuery, toQuery) {
110
+ return addQueryOn(fromQuery, toQuery, fromQuery, foreignKey, primaryKey);
111
+ },
112
+ primaryKey
113
+ };
114
+ };
115
+ const nestedInsert$3 = ({ query, primaryKey }) => {
116
+ return async (q, data) => {
117
+ const connectOrCreate = data.filter(
118
+ (item) => Boolean(item.connectOrCreate)
119
+ );
120
+ const t = query.transacting(q);
121
+ let connectOrCreated;
122
+ if (connectOrCreate.length) {
123
+ connectOrCreated = await Promise.all(
124
+ connectOrCreate.map(
125
+ (item) => t.findBy(item.connectOrCreate.where)._takeOptional()
126
+ )
60
127
  );
61
- const t = query.transacting(q);
62
- let connectOrCreated;
63
- if (connectOrCreate.length) {
64
- connectOrCreated = await Promise.all(
65
- connectOrCreate.map(
66
- (item) => t.findBy(item.connectOrCreate.where)._takeOptional()
67
- )
68
- );
69
- } else {
70
- connectOrCreated = [];
71
- }
72
- let connectOrCreatedI = 0;
73
- const create = data.filter(
74
- (item) => {
75
- if (item.connectOrCreate) {
76
- return !connectOrCreated[connectOrCreatedI++];
77
- } else {
78
- return Boolean(item.create);
79
- }
128
+ } else {
129
+ connectOrCreated = [];
130
+ }
131
+ let connectOrCreatedI = 0;
132
+ const create = data.filter(
133
+ (item) => {
134
+ if (item.connectOrCreate) {
135
+ return !connectOrCreated[connectOrCreatedI++];
136
+ } else {
137
+ return Boolean(item.create);
80
138
  }
81
- );
82
- let created;
83
- if (create.length) {
84
- created = await t.select(primaryKey)._createMany(
85
- create.map(
86
- (item) => "create" in item ? item.create : item.connectOrCreate.create
87
- )
88
- );
89
- } else {
90
- created = [];
91
139
  }
92
- const connect = data.filter(
93
- (item) => Boolean(item.connect)
140
+ );
141
+ let created;
142
+ if (create.length) {
143
+ created = await t.select(primaryKey)._createMany(
144
+ create.map(
145
+ (item) => "create" in item ? item.create : item.connectOrCreate.create
146
+ )
94
147
  );
95
- let connected;
96
- if (connect.length) {
97
- connected = await Promise.all(
98
- connect.map((item) => t.findBy(item.connect)._take())
99
- );
100
- } else {
101
- connected = [];
102
- }
103
- let createdI = 0;
104
- let connectedI = 0;
105
- connectOrCreatedI = 0;
106
- return data.map(
107
- (item) => item.connectOrCreate ? connectOrCreated[connectOrCreatedI++] || created[createdI++] : item.connect ? connected[connectedI++] : created[createdI++]
148
+ } else {
149
+ created = [];
150
+ }
151
+ const connect = data.filter(
152
+ (item) => Boolean(item.connect)
153
+ );
154
+ let connected;
155
+ if (connect.length) {
156
+ connected = await Promise.all(
157
+ connect.map((item) => t.findBy(item.connect)._take())
108
158
  );
109
- },
110
- nestedUpdate: (q, update, params, state) => {
111
- var _a, _b;
112
- if (params.upsert && isQueryReturnsAll(q)) {
113
- throw new Error("`upsert` option is not allowed in a batch update");
114
- }
115
- let idForDelete;
116
- q._beforeUpdate(async (q2) => {
117
- if (params.disconnect) {
118
- update[foreignKey] = null;
119
- } else if (params.set) {
120
- if (primaryKey in params.set) {
121
- update[foreignKey] = params.set[primaryKey];
122
- } else {
123
- update[foreignKey] = await query.transacting(q2)._findBy(params.set)._get(primaryKey);
124
- }
125
- } else if (params.create) {
126
- update[foreignKey] = await query.transacting(q2)._get(primaryKey)._create(params.create);
127
- } else if (params.delete) {
128
- const selectQuery = q2.transacting(q2);
129
- selectQuery.query.type = void 0;
130
- idForDelete = await selectQuery._getOptional(foreignKey);
131
- update[foreignKey] = null;
132
- }
133
- });
134
- const { upsert } = params;
135
- if (upsert || params.update || params.delete) {
136
- if (!((_a = q.query.select) == null ? void 0 : _a.includes("*")) && !((_b = q.query.select) == null ? void 0 : _b.includes(foreignKey))) {
137
- q._select(foreignKey);
159
+ } else {
160
+ connected = [];
161
+ }
162
+ let createdI = 0;
163
+ let connectedI = 0;
164
+ connectOrCreatedI = 0;
165
+ return data.map(
166
+ (item) => item.connectOrCreate ? connectOrCreated[connectOrCreatedI++] || created[createdI++] : item.connect ? connected[connectedI++] : created[createdI++]
167
+ );
168
+ };
169
+ };
170
+ const nestedUpdate$3 = ({ query, primaryKey, foreignKey }) => {
171
+ return (q, update, params, state) => {
172
+ var _a, _b;
173
+ if (params.upsert && isQueryReturnsAll(q)) {
174
+ throw new Error("`upsert` option is not allowed in a batch update");
175
+ }
176
+ let idForDelete;
177
+ q._beforeUpdate(async (q2) => {
178
+ if (params.disconnect) {
179
+ update[foreignKey] = null;
180
+ } else if (params.set) {
181
+ if (primaryKey in params.set) {
182
+ update[foreignKey] = params.set[primaryKey];
183
+ } else {
184
+ update[foreignKey] = await query.transacting(q2)._findBy(params.set)._get(primaryKey);
138
185
  }
186
+ } else if (params.create) {
187
+ update[foreignKey] = await query.transacting(q2)._get(primaryKey)._create(params.create);
188
+ } else if (params.delete) {
189
+ const selectQuery = q2.transacting(q2);
190
+ selectQuery.query.type = void 0;
191
+ idForDelete = await selectQuery._getOptional(foreignKey);
192
+ update[foreignKey] = null;
139
193
  }
140
- if (upsert) {
141
- if (!state.updateLater) {
142
- state.updateLater = {};
143
- state.updateLaterPromises = [];
194
+ });
195
+ const { upsert } = params;
196
+ if (upsert || params.update || params.delete) {
197
+ if (!((_a = q.query.select) == null ? void 0 : _a.includes("*")) && !((_b = q.query.select) == null ? void 0 : _b.includes(foreignKey))) {
198
+ q._select(foreignKey);
199
+ }
200
+ }
201
+ if (upsert) {
202
+ if (!state.updateLater) {
203
+ state.updateLater = {};
204
+ state.updateLaterPromises = [];
205
+ }
206
+ const { handleResult } = q.query;
207
+ q.query.handleResult = async (q2, queryResult) => {
208
+ const data = await handleResult(q2, queryResult);
209
+ const id = data[0][foreignKey];
210
+ if (id !== null) {
211
+ await query.transacting(q2)._findBy({ [primaryKey]: id })._update(upsert.update);
212
+ } else {
213
+ state.updateLaterPromises.push(
214
+ query.transacting(q2)._select(primaryKey)._create(upsert.create).then((result) => {
215
+ state.updateLater[foreignKey] = result[primaryKey];
216
+ })
217
+ );
144
218
  }
145
- const { handleResult } = q.query;
146
- q.query.handleResult = async (q2, queryResult) => {
147
- const data = await handleResult(q2, queryResult);
148
- const id = data[0][foreignKey];
149
- if (id !== null) {
150
- await query.transacting(q2)._findBy({ [primaryKey]: id })._update(upsert.update);
151
- } else {
152
- state.updateLaterPromises.push(
153
- query.transacting(q2)._select(primaryKey)._create(upsert.create).then((result) => {
154
- state.updateLater[foreignKey] = result[primaryKey];
155
- })
156
- );
157
- }
158
- return data;
159
- };
160
- } else if (params.delete || params.update) {
161
- q._afterQuery(async (q2, data) => {
162
- const id = params.delete ? idForDelete : Array.isArray(data) ? data.length === 0 ? null : {
163
- in: data.map((item) => item[foreignKey]).filter((id2) => id2 !== null)
164
- } : data[foreignKey];
165
- if (id !== void 0 && id !== null) {
166
- const t = query.transacting(q2)._findBy({
167
- [primaryKey]: id
168
- });
169
- if (params.delete) {
170
- await t._delete();
171
- } else if (params.update) {
172
- await t._update(params.update);
173
- }
219
+ return data;
220
+ };
221
+ } else if (params.delete || params.update) {
222
+ q._afterQuery(async (q2, data) => {
223
+ const id = params.delete ? idForDelete : Array.isArray(data) ? data.length === 0 ? null : {
224
+ in: data.map((item) => item[foreignKey]).filter((id2) => id2 !== null)
225
+ } : data[foreignKey];
226
+ if (id !== void 0 && id !== null) {
227
+ const t = query.transacting(q2)._findBy({
228
+ [primaryKey]: id
229
+ });
230
+ if (params.delete) {
231
+ await t._delete();
232
+ } else if (params.update) {
233
+ await t._update(params.update);
174
234
  }
175
- });
176
- }
177
- return !params.update && !params.upsert;
178
- },
179
- joinQuery(fromQuery, toQuery) {
180
- return addQueryOn(toQuery, fromQuery, toQuery, primaryKey, foreignKey);
181
- },
182
- reverseJoin(fromQuery, toQuery) {
183
- return addQueryOn(fromQuery, toQuery, fromQuery, foreignKey, primaryKey);
184
- },
185
- primaryKey
235
+ }
236
+ });
237
+ }
238
+ return !params.update && !params.upsert;
186
239
  };
187
240
  };
188
241
 
189
- const getThroughRelation = (model, through) => {
190
- return model.relations[through];
242
+ const getThroughRelation = (table, through) => {
243
+ return table.relations[through];
191
244
  };
192
245
  const getSourceRelation = (throughRelation, source) => {
193
- return throughRelation.model.relations[source];
246
+ return throughRelation.table.relations[source];
247
+ };
248
+ const hasRelationHandleCreate = (q, ctx, item, rowIndex, key, primaryKey, nestedInsert) => {
249
+ const value = item[key];
250
+ 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))
251
+ return;
252
+ const store = ctx;
253
+ if (!store.hasRelation)
254
+ store.hasRelation = {};
255
+ const values = [rowIndex, value];
256
+ if (store.hasRelation[key]) {
257
+ store.hasRelation[key].push(values);
258
+ return;
259
+ }
260
+ q.query.wrapInTransaction = true;
261
+ ctx.returnTypeAll = true;
262
+ ctx.requiredReturning[primaryKey] = true;
263
+ const relationData = [values];
264
+ store.hasRelation[key] = relationData;
265
+ pushQueryValue(q, "afterCreate", async (q2) => {
266
+ const { resultAll } = ctx;
267
+ return nestedInsert(
268
+ q2,
269
+ relationData.map(([rowIndex2, data]) => [
270
+ resultAll[rowIndex2],
271
+ data
272
+ ])
273
+ );
274
+ });
275
+ };
276
+ const hasRelationHandleUpdate = (q, ctx, set, key, primaryKey, nestedUpdate) => {
277
+ var _a, _b;
278
+ const value = set[key];
279
+ 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))
280
+ return;
281
+ if (!((_a = q.query.select) == null ? void 0 : _a.includes("*")) && !((_b = q.query.select) == null ? void 0 : _b.includes(primaryKey))) {
282
+ q._select(primaryKey);
283
+ }
284
+ q.query.wrapInTransaction = true;
285
+ ctx.returnTypeAll = true;
286
+ pushQueryValue(q, "afterUpdate", (q2) => {
287
+ return nestedUpdate(
288
+ q2,
289
+ ctx.resultAll,
290
+ value
291
+ );
292
+ });
194
293
  };
195
294
 
196
295
  var __defProp$4 = Object.defineProperty;
@@ -212,7 +311,37 @@ var __spreadValues$4 = (a, b) => {
212
311
  return a;
213
312
  };
214
313
  var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b));
215
- const makeHasOneMethod = (model, relation, relationName, query) => {
314
+ class HasOneVirtualColumn extends VirtualColumn {
315
+ constructor(key, state) {
316
+ super();
317
+ this.key = key;
318
+ this.state = state;
319
+ this.nestedInsert = nestedInsert$2(state);
320
+ this.nestedUpdate = nestedUpdate$2(state);
321
+ }
322
+ create(q, ctx, item, rowIndex) {
323
+ hasRelationHandleCreate(
324
+ q,
325
+ ctx,
326
+ item,
327
+ rowIndex,
328
+ this.key,
329
+ this.state.primaryKey,
330
+ this.nestedInsert
331
+ );
332
+ }
333
+ update(q, ctx, set) {
334
+ hasRelationHandleUpdate(
335
+ q,
336
+ ctx,
337
+ set,
338
+ this.key,
339
+ this.state.primaryKey,
340
+ this.nestedUpdate
341
+ );
342
+ }
343
+ }
344
+ const makeHasOneMethod = (table, relation, relationName, query) => {
216
345
  if (relation.options.required) {
217
346
  query._take();
218
347
  } else {
@@ -220,21 +349,19 @@ const makeHasOneMethod = (model, relation, relationName, query) => {
220
349
  }
221
350
  if ("through" in relation.options) {
222
351
  const { through, source } = relation.options;
223
- const throughRelation = getThroughRelation(model, through);
352
+ const throughRelation = getThroughRelation(table, through);
224
353
  const sourceRelation = getSourceRelation(throughRelation, source);
225
354
  const sourceQuery = sourceRelation.joinQuery(throughRelation.query, sourceRelation.query).as(relationName);
226
355
  const whereExistsCallback = () => sourceQuery;
227
356
  return {
228
357
  returns: "one",
229
358
  method: (params) => {
230
- const throughQuery = model[through](params);
359
+ const throughQuery = table[through](params);
231
360
  return query.whereExists(
232
361
  throughQuery,
233
362
  whereExistsCallback
234
363
  );
235
364
  },
236
- nestedInsert: void 0,
237
- nestedUpdate: void 0,
238
365
  joinQuery(fromQuery, toQuery) {
239
366
  return toQuery.whereExists(
240
367
  throughRelation.joinQuery(fromQuery, throughRelation.query),
@@ -263,6 +390,7 @@ const makeHasOneMethod = (model, relation, relationName, query) => {
263
390
  };
264
391
  }
265
392
  const { primaryKey, foreignKey } = relation.options;
393
+ const state = { query, primaryKey, foreignKey };
266
394
  const fromQuerySelect = [{ selectAs: { [foreignKey]: primaryKey } }];
267
395
  return {
268
396
  returns: "one",
@@ -270,75 +398,7 @@ const makeHasOneMethod = (model, relation, relationName, query) => {
270
398
  const values = { [foreignKey]: params[primaryKey] };
271
399
  return query.where(values)._defaults(values);
272
400
  },
273
- nestedInsert: async (q, data) => {
274
- const connect = data.filter(
275
- (item) => Boolean(item[1].connect || item[1].connectOrCreate)
276
- );
277
- const t = query.transacting(q);
278
- let connected;
279
- if (connect.length) {
280
- connected = await Promise.all(
281
- connect.map(([selfData, item]) => {
282
- const data2 = { [foreignKey]: selfData[primaryKey] };
283
- return "connect" in item ? t.where(item.connect)._updateOrThrow(data2) : t.where(item.connectOrCreate.where)._update(data2);
284
- })
285
- );
286
- } else {
287
- connected = [];
288
- }
289
- let connectedI = 0;
290
- const create = data.filter(
291
- (item) => {
292
- if (item[1].connectOrCreate) {
293
- return !connected[connectedI++];
294
- }
295
- return Boolean(item[1].create);
296
- }
297
- );
298
- if (create.length) {
299
- await t._count()._createMany(
300
- create.map(([selfData, item]) => __spreadValues$4({
301
- [foreignKey]: selfData[primaryKey]
302
- }, "create" in item ? item.create : item.connectOrCreate.create))
303
- );
304
- }
305
- },
306
- nestedUpdate: async (q, data, params) => {
307
- if ((params.set || params.create || params.upsert) && isQueryReturnsAll(q)) {
308
- const key = params.set ? "set" : params.create ? "create" : "upsert";
309
- throw new Error(`\`${key}\` option is not allowed in a batch update`);
310
- }
311
- const t = query.transacting(q);
312
- const ids = data.map((item) => item[primaryKey]);
313
- const currentRelationsQuery = t.where({
314
- [foreignKey]: { in: ids }
315
- });
316
- if (params.create || params.disconnect || params.set) {
317
- await currentRelationsQuery._update({ [foreignKey]: null });
318
- if (params.create) {
319
- await t._count()._create(__spreadProps$2(__spreadValues$4({}, params.create), {
320
- [foreignKey]: data[0][primaryKey]
321
- }));
322
- }
323
- if (params.set) {
324
- await t._where(params.set)._update({ [foreignKey]: data[0][primaryKey] });
325
- }
326
- } else if (params.update) {
327
- await currentRelationsQuery._update(params.update);
328
- } else if (params.delete) {
329
- await currentRelationsQuery._delete();
330
- } else if (params.upsert) {
331
- const { update, create } = params.upsert;
332
- const updatedIds = await currentRelationsQuery._pluck(foreignKey)._update(update);
333
- if (updatedIds.length < ids.length) {
334
- await t.createMany(
335
- ids.filter((id) => !updatedIds.includes(id)).map((id) => __spreadProps$2(__spreadValues$4({}, create), {
336
- [foreignKey]: id
337
- }))
338
- );
339
- }
340
- }
341
- },
401
+ virtualColumn: new HasOneVirtualColumn(relationName, state),
342
402
  joinQuery(fromQuery, toQuery) {
343
403
  return addQueryOn(toQuery, fromQuery, toQuery, foreignKey, primaryKey);
344
404
  },
@@ -355,6 +415,79 @@ const makeHasOneMethod = (model, relation, relationName, query) => {
355
415
  }
356
416
  };
357
417
  };
418
+ const nestedInsert$2 = ({ query, primaryKey, foreignKey }) => {
419
+ return async (q, data) => {
420
+ const connect = data.filter(
421
+ (item) => Boolean(item[1].connect || item[1].connectOrCreate)
422
+ );
423
+ const t = query.transacting(q);
424
+ let connected;
425
+ if (connect.length) {
426
+ connected = await Promise.all(
427
+ connect.map(([selfData, item]) => {
428
+ const data2 = { [foreignKey]: selfData[primaryKey] };
429
+ return "connect" in item ? t.where(item.connect)._updateOrThrow(data2) : t.where(item.connectOrCreate.where)._update(data2);
430
+ })
431
+ );
432
+ } else {
433
+ connected = [];
434
+ }
435
+ let connectedI = 0;
436
+ const create = data.filter(
437
+ (item) => {
438
+ if (item[1].connectOrCreate) {
439
+ return !connected[connectedI++];
440
+ }
441
+ return Boolean(item[1].create);
442
+ }
443
+ );
444
+ if (create.length) {
445
+ await t._count()._createMany(
446
+ create.map(([selfData, item]) => __spreadValues$4({
447
+ [foreignKey]: selfData[primaryKey]
448
+ }, "create" in item ? item.create : item.connectOrCreate.create))
449
+ );
450
+ }
451
+ };
452
+ };
453
+ const nestedUpdate$2 = ({ query, primaryKey, foreignKey }) => {
454
+ return async (q, data, params) => {
455
+ if ((params.set || params.create || params.upsert) && isQueryReturnsAll(q)) {
456
+ const key = params.set ? "set" : params.create ? "create" : "upsert";
457
+ throw new Error(`\`${key}\` option is not allowed in a batch update`);
458
+ }
459
+ const t = query.transacting(q);
460
+ const ids = data.map((item) => item[primaryKey]);
461
+ const currentRelationsQuery = t.where({
462
+ [foreignKey]: { in: ids }
463
+ });
464
+ if (params.create || params.disconnect || params.set) {
465
+ await currentRelationsQuery._update({ [foreignKey]: null });
466
+ if (params.create) {
467
+ await t._count()._create(__spreadProps$2(__spreadValues$4({}, params.create), {
468
+ [foreignKey]: data[0][primaryKey]
469
+ }));
470
+ }
471
+ if (params.set) {
472
+ await t._where(params.set)._update({ [foreignKey]: data[0][primaryKey] });
473
+ }
474
+ } else if (params.update) {
475
+ await currentRelationsQuery._update(params.update);
476
+ } else if (params.delete) {
477
+ await currentRelationsQuery._delete();
478
+ } else if (params.upsert) {
479
+ const { update, create } = params.upsert;
480
+ const updatedIds = await currentRelationsQuery._pluck(foreignKey)._update(update);
481
+ if (updatedIds.length < ids.length) {
482
+ await t.createMany(
483
+ ids.filter((id) => !updatedIds.includes(id)).map((id) => __spreadProps$2(__spreadValues$4({}, create), {
484
+ [foreignKey]: id
485
+ }))
486
+ );
487
+ }
488
+ }
489
+ };
490
+ };
358
491
 
359
492
  var __defProp$3 = Object.defineProperty;
360
493
  var __defProps$1 = Object.defineProperties;
@@ -375,10 +508,40 @@ var __spreadValues$3 = (a, b) => {
375
508
  return a;
376
509
  };
377
510
  var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
378
- const makeHasManyMethod = (model, relation, relationName, query) => {
511
+ class HasManyVirtualColumn extends VirtualColumn {
512
+ constructor(key, state) {
513
+ super();
514
+ this.key = key;
515
+ this.state = state;
516
+ this.nestedInsert = nestedInsert$1(state);
517
+ this.nestedUpdate = nestedUpdate$1(state);
518
+ }
519
+ create(q, ctx, item, rowIndex) {
520
+ hasRelationHandleCreate(
521
+ q,
522
+ ctx,
523
+ item,
524
+ rowIndex,
525
+ this.key,
526
+ this.state.primaryKey,
527
+ this.nestedInsert
528
+ );
529
+ }
530
+ update(q, ctx, set) {
531
+ hasRelationHandleUpdate(
532
+ q,
533
+ ctx,
534
+ set,
535
+ this.key,
536
+ this.state.primaryKey,
537
+ this.nestedUpdate
538
+ );
539
+ }
540
+ }
541
+ const makeHasManyMethod = (table, relation, relationName, query) => {
379
542
  if ("through" in relation.options) {
380
543
  const { through, source } = relation.options;
381
- const throughRelation = getThroughRelation(model, through);
544
+ const throughRelation = getThroughRelation(table, through);
382
545
  const sourceRelation = getSourceRelation(throughRelation, source);
383
546
  const sourceRelationQuery = sourceRelation.query.as(relationName);
384
547
  const sourceQuery = sourceRelation.joinQuery(
@@ -389,14 +552,12 @@ const makeHasManyMethod = (model, relation, relationName, query) => {
389
552
  return {
390
553
  returns: "many",
391
554
  method: (params) => {
392
- const throughQuery = model[through](params);
555
+ const throughQuery = table[through](params);
393
556
  return query.whereExists(
394
557
  throughQuery,
395
558
  whereExistsCallback
396
559
  );
397
560
  },
398
- nestedInsert: void 0,
399
- nestedUpdate: void 0,
400
561
  joinQuery(fromQuery, toQuery) {
401
562
  return toQuery.whereExists(
402
563
  throughRelation.joinQuery(fromQuery, throughRelation.query),
@@ -425,6 +586,7 @@ const makeHasManyMethod = (model, relation, relationName, query) => {
425
586
  };
426
587
  }
427
588
  const { primaryKey, foreignKey } = relation.options;
589
+ const state = { query, primaryKey, foreignKey };
428
590
  const fromQuerySelect = [{ selectAs: { [foreignKey]: primaryKey } }];
429
591
  return {
430
592
  returns: "many",
@@ -432,117 +594,7 @@ const makeHasManyMethod = (model, relation, relationName, query) => {
432
594
  const values = { [foreignKey]: params[primaryKey] };
433
595
  return query.where(values)._defaults(values);
434
596
  },
435
- nestedInsert: async (q, data) => {
436
- const connect = data.filter(
437
- (item) => Boolean(item[1].connect)
438
- );
439
- const t = query.transacting(q);
440
- if (connect.length) {
441
- await Promise.all(
442
- connect.flatMap(
443
- ([selfData, { connect: connect2 }]) => t.or(...connect2)._updateOrThrow({ [foreignKey]: selfData[primaryKey] })
444
- )
445
- );
446
- }
447
- const connectOrCreate = data.filter(
448
- (item) => Boolean(item[1].connectOrCreate)
449
- );
450
- let connected;
451
- if (connectOrCreate.length) {
452
- connected = await Promise.all(
453
- connectOrCreate.flatMap(
454
- ([selfData, { connectOrCreate: connectOrCreate2 }]) => connectOrCreate2.map(
455
- (item) => t.where(item.where)._update({
456
- [foreignKey]: selfData[primaryKey]
457
- })
458
- )
459
- )
460
- );
461
- } else {
462
- connected = [];
463
- }
464
- let connectedI = 0;
465
- const create = data.filter(
466
- (item) => {
467
- if (item[1].connectOrCreate) {
468
- const length = item[1].connectOrCreate.length;
469
- connectedI += length;
470
- for (let i = length; i > 0; i--) {
471
- if (connected[connectedI - i] === 0)
472
- return true;
473
- }
474
- }
475
- return Boolean(item[1].create);
476
- }
477
- );
478
- connectedI = 0;
479
- if (create.length) {
480
- await t._createMany(
481
- create.flatMap(
482
- ([selfData, { create: create2 = [], connectOrCreate: connectOrCreate2 = [] }]) => {
483
- return [
484
- ...create2.map((item) => __spreadValues$3({
485
- [foreignKey]: selfData[primaryKey]
486
- }, item)),
487
- ...connectOrCreate2.filter(() => connected[connectedI++] === 0).map((item) => __spreadValues$3({
488
- [foreignKey]: selfData[primaryKey]
489
- }, item.create))
490
- ];
491
- }
492
- )
493
- );
494
- }
495
- },
496
- nestedUpdate: async (q, data, params) => {
497
- var _a;
498
- if ((params.set || params.create) && isQueryReturnsAll(q)) {
499
- const key = params.set ? "set" : "create";
500
- throw new Error(`\`${key}\` option is not allowed in a batch update`);
501
- }
502
- const t = query.transacting(q);
503
- if (params.create) {
504
- await t._count()._createMany(
505
- params.create.map((create) => __spreadProps$1(__spreadValues$3({}, create), {
506
- [foreignKey]: data[0][primaryKey]
507
- }))
508
- );
509
- delete t.query[toSqlCacheKey];
510
- }
511
- if (params.disconnect || params.set) {
512
- await t.where(
513
- getWhereForNestedUpdate(
514
- data,
515
- params.disconnect,
516
- primaryKey,
517
- foreignKey
518
- )
519
- )._update({ [foreignKey]: null });
520
- if (params.set) {
521
- delete t.query[toSqlCacheKey];
522
- await t.where(
523
- Array.isArray(params.set) ? {
524
- OR: params.set
525
- } : params.set
526
- )._update({ [foreignKey]: data[0][primaryKey] });
527
- }
528
- }
529
- if (params.delete || params.update) {
530
- delete t.query[toSqlCacheKey];
531
- const q2 = t._where(
532
- getWhereForNestedUpdate(
533
- data,
534
- params.delete || ((_a = params.update) == null ? void 0 : _a.where),
535
- primaryKey,
536
- foreignKey
537
- )
538
- );
539
- if (params.delete) {
540
- await q2._delete();
541
- } else if (params.update) {
542
- await q2._update(params.update.data);
543
- }
544
- }
545
- },
597
+ virtualColumn: new HasManyVirtualColumn(relationName, state),
546
598
  joinQuery(fromQuery, toQuery) {
547
599
  return addQueryOn(toQuery, fromQuery, toQuery, foreignKey, primaryKey);
548
600
  },
@@ -572,6 +624,119 @@ const getWhereForNestedUpdate = (data, params, primaryKey, foreignKey) => {
572
624
  }
573
625
  return where;
574
626
  };
627
+ const nestedInsert$1 = ({ query, primaryKey, foreignKey }) => {
628
+ return async (q, data) => {
629
+ const connect = data.filter(
630
+ (item) => Boolean(item[1].connect)
631
+ );
632
+ const t = query.transacting(q);
633
+ if (connect.length) {
634
+ await Promise.all(
635
+ connect.flatMap(
636
+ ([selfData, { connect: connect2 }]) => t.or(...connect2)._updateOrThrow({ [foreignKey]: selfData[primaryKey] })
637
+ )
638
+ );
639
+ }
640
+ const connectOrCreate = data.filter(
641
+ (item) => Boolean(item[1].connectOrCreate)
642
+ );
643
+ let connected;
644
+ if (connectOrCreate.length) {
645
+ connected = await Promise.all(
646
+ connectOrCreate.flatMap(
647
+ ([selfData, { connectOrCreate: connectOrCreate2 }]) => connectOrCreate2.map(
648
+ (item) => t.where(item.where)._update({
649
+ [foreignKey]: selfData[primaryKey]
650
+ })
651
+ )
652
+ )
653
+ );
654
+ } else {
655
+ connected = [];
656
+ }
657
+ let connectedI = 0;
658
+ const create = data.filter(
659
+ (item) => {
660
+ if (item[1].connectOrCreate) {
661
+ const length = item[1].connectOrCreate.length;
662
+ connectedI += length;
663
+ for (let i = length; i > 0; i--) {
664
+ if (connected[connectedI - i] === 0)
665
+ return true;
666
+ }
667
+ }
668
+ return Boolean(item[1].create);
669
+ }
670
+ );
671
+ connectedI = 0;
672
+ if (create.length) {
673
+ await t._createMany(
674
+ create.flatMap(([selfData, { create: create2 = [], connectOrCreate: connectOrCreate2 = [] }]) => {
675
+ return [
676
+ ...create2.map((item) => __spreadValues$3({
677
+ [foreignKey]: selfData[primaryKey]
678
+ }, item)),
679
+ ...connectOrCreate2.filter(() => connected[connectedI++] === 0).map((item) => __spreadValues$3({
680
+ [foreignKey]: selfData[primaryKey]
681
+ }, item.create))
682
+ ];
683
+ })
684
+ );
685
+ }
686
+ };
687
+ };
688
+ const nestedUpdate$1 = ({ query, primaryKey, foreignKey }) => {
689
+ return async (q, data, params) => {
690
+ var _a;
691
+ if ((params.set || params.create) && isQueryReturnsAll(q)) {
692
+ const key = params.set ? "set" : "create";
693
+ throw new Error(`\`${key}\` option is not allowed in a batch update`);
694
+ }
695
+ const t = query.transacting(q);
696
+ if (params.create) {
697
+ await t._count()._createMany(
698
+ params.create.map((create) => __spreadProps$1(__spreadValues$3({}, create), {
699
+ [foreignKey]: data[0][primaryKey]
700
+ }))
701
+ );
702
+ delete t.query[toSqlCacheKey];
703
+ }
704
+ if (params.disconnect || params.set) {
705
+ await t.where(
706
+ getWhereForNestedUpdate(
707
+ data,
708
+ params.disconnect,
709
+ primaryKey,
710
+ foreignKey
711
+ )
712
+ )._update({ [foreignKey]: null });
713
+ if (params.set) {
714
+ delete t.query[toSqlCacheKey];
715
+ await t.where(
716
+ Array.isArray(params.set) ? {
717
+ OR: params.set
718
+ } : params.set
719
+ )._update({ [foreignKey]: data[0][primaryKey] });
720
+ }
721
+ }
722
+ if (params.delete || params.update) {
723
+ delete t.query[toSqlCacheKey];
724
+ const q2 = t._where(
725
+ getWhereForNestedUpdate(
726
+ data,
727
+ params.delete || ((_a = params.update) == null ? void 0 : _a.where),
728
+ primaryKey,
729
+ foreignKey
730
+ )
731
+ );
732
+ if (params.delete) {
733
+ await q2._delete();
734
+ } else if (params.update) {
735
+ await q2._update(params.update.data);
736
+ }
737
+ }
738
+ };
739
+ };
575
740
 
576
741
  var __defProp$2 = Object.defineProperty;
577
742
  var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols;
@@ -589,7 +754,37 @@ var __spreadValues$2 = (a, b) => {
589
754
  }
590
755
  return a;
591
756
  };
592
- const makeHasAndBelongsToManyMethod = (model, qb, relation, query) => {
757
+ class HasAndBelongsToManyVirtualColumn extends VirtualColumn {
758
+ constructor(key, state) {
759
+ super();
760
+ this.key = key;
761
+ this.state = state;
762
+ this.nestedInsert = nestedInsert(state);
763
+ this.nestedUpdate = nestedUpdate(state);
764
+ }
765
+ create(q, ctx, item, rowIndex) {
766
+ hasRelationHandleCreate(
767
+ q,
768
+ ctx,
769
+ item,
770
+ rowIndex,
771
+ this.key,
772
+ this.state.primaryKey,
773
+ this.nestedInsert
774
+ );
775
+ }
776
+ update(q, ctx, set) {
777
+ hasRelationHandleUpdate(
778
+ q,
779
+ ctx,
780
+ set,
781
+ this.key,
782
+ this.state.primaryKey,
783
+ this.nestedUpdate
784
+ );
785
+ }
786
+ }
787
+ const makeHasAndBelongsToManyMethod = (table, qb, relation, relationName, query) => {
593
788
  const {
594
789
  primaryKey: pk,
595
790
  foreignKey: fk,
@@ -600,14 +795,14 @@ const makeHasAndBelongsToManyMethod = (model, qb, relation, query) => {
600
795
  const foreignKeyFull = `${joinTable}.${fk}`;
601
796
  const associationForeignKeyFull = `${joinTable}.${afk}`;
602
797
  const associationPrimaryKeyFull = `${getQueryAs(query)}.${apk}`;
603
- const __model = Object.create(qb.__model);
604
- __model.__model = __model;
605
- __model.table = joinTable;
606
- __model.shape = {
607
- [fk]: model.shape[pk],
798
+ const __table = Object.create(qb.__table);
799
+ __table.__table = __table;
800
+ __table.table = joinTable;
801
+ __table.shape = {
802
+ [fk]: table.shape[pk],
608
803
  [afk]: query.shape[apk]
609
804
  };
610
- const subQuery = Object.create(__model);
805
+ const subQuery = Object.create(__table);
611
806
  subQuery.query = __spreadValues$2({}, subQuery.query);
612
807
  const state = {
613
808
  relatedTableQuery: query,
@@ -615,7 +810,10 @@ const makeHasAndBelongsToManyMethod = (model, qb, relation, query) => {
615
810
  primaryKey: pk,
616
811
  foreignKey: fk,
617
812
  associationPrimaryKey: apk,
618
- associationForeignKey: afk
813
+ associationForeignKey: afk,
814
+ foreignKeyFull,
815
+ associationForeignKeyFull,
816
+ associationPrimaryKeyFull
619
817
  };
620
818
  return {
621
819
  returns: "many",
@@ -627,144 +825,7 @@ const makeHasAndBelongsToManyMethod = (model, qb, relation, query) => {
627
825
  })
628
826
  );
629
827
  },
630
- nestedInsert: async (q, data) => {
631
- const connect = data.filter(
632
- (item) => Boolean(item[1].connect)
633
- );
634
- const t = query.transacting(q);
635
- let connected;
636
- if (connect.length) {
637
- connected = await Promise.all(
638
- connect.flatMap(
639
- ([, { connect: connect2 }]) => connect2.map((item) => t.select(apk)._findBy(item)._take())
640
- )
641
- );
642
- } else {
643
- connected = [];
644
- }
645
- const connectOrCreate = data.filter(
646
- (item) => Boolean(item[1].connectOrCreate)
647
- );
648
- let connectOrCreated;
649
- if (connectOrCreate.length) {
650
- connectOrCreated = await Promise.all(
651
- connectOrCreate.flatMap(
652
- ([, { connectOrCreate: connectOrCreate2 }]) => connectOrCreate2.map(
653
- (item) => t.select(apk)._findBy(item.where)._takeOptional()
654
- )
655
- )
656
- );
657
- } else {
658
- connectOrCreated = [];
659
- }
660
- let connectOrCreateI = 0;
661
- const create = data.filter(
662
- (item) => {
663
- if (item[1].connectOrCreate) {
664
- const length = item[1].connectOrCreate.length;
665
- connectOrCreateI += length;
666
- for (let i = length; i > 0; i--) {
667
- if (!connectOrCreated[connectOrCreateI - i])
668
- return true;
669
- }
670
- }
671
- return Boolean(item[1].create);
672
- }
673
- );
674
- connectOrCreateI = 0;
675
- let created;
676
- if (create.length) {
677
- created = await t.select(apk)._createMany(
678
- create.flatMap(([, { create: create2 = [], connectOrCreate: connectOrCreate2 = [] }]) => [
679
- ...create2,
680
- ...connectOrCreate2.filter(() => !connectOrCreated[connectOrCreateI++]).map((item) => item.create)
681
- ])
682
- );
683
- } else {
684
- created = [];
685
- }
686
- const allKeys = data;
687
- let createI = 0;
688
- let connectI = 0;
689
- connectOrCreateI = 0;
690
- data.forEach(([, data2], index) => {
691
- if (data2.create || data2.connectOrCreate) {
692
- if (data2.create) {
693
- const len = data2.create.length;
694
- allKeys[index][1] = created.slice(createI, createI + len);
695
- createI += len;
696
- }
697
- if (data2.connectOrCreate) {
698
- const arr = [];
699
- allKeys[index][1] = arr;
700
- const len = data2.connectOrCreate.length;
701
- for (let i = 0; i < len; i++) {
702
- const item = connectOrCreated[connectOrCreateI++];
703
- if (item) {
704
- arr.push(item);
705
- } else {
706
- arr.push(created[createI++]);
707
- }
708
- }
709
- }
710
- }
711
- if (data2.connect) {
712
- const len = data2.connect.length;
713
- allKeys[index][1] = connected.slice(connectI, connectI + len);
714
- connectI += len;
715
- }
716
- });
717
- await subQuery.transacting(q)._count()._createMany(
718
- allKeys.flatMap(([selfData, relationKeys]) => {
719
- const selfKey = selfData[pk];
720
- return relationKeys.map((relationData) => ({
721
- [fk]: selfKey,
722
- [afk]: relationData[apk]
723
- }));
724
- })
725
- );
726
- },
727
- nestedUpdate: async (q, data, params) => {
728
- if (params.create) {
729
- const ids = await query.transacting(q)._pluck(apk)._createMany(params.create);
730
- await subQuery.transacting(q)._createMany(
731
- data.flatMap(
732
- (item) => ids.map((id) => ({
733
- [fk]: item[pk],
734
- [afk]: id
735
- }))
736
- )
737
- );
738
- }
739
- if (params.update) {
740
- await query.transacting(q)._whereExists(
741
- subQuery,
742
- (q2) => q2._on(associationForeignKeyFull, associationPrimaryKeyFull)._where({
743
- IN: {
744
- columns: [foreignKeyFull],
745
- values: [data.map((item) => item[pk])]
746
- }
747
- })
748
- )._where(
749
- Array.isArray(params.update.where) ? { OR: params.update.where } : params.update.where
750
- )._update(params.update.data);
751
- }
752
- if (params.disconnect) {
753
- await queryJoinTable(state, q, data, params.disconnect)._delete();
754
- }
755
- if (params.delete) {
756
- const j = queryJoinTable(state, q, data, params.delete);
757
- const ids = await j._pluck(afk)._delete();
758
- await queryRelatedTable(query, q, { [apk]: { in: ids } })._delete();
759
- }
760
- if (params.set) {
761
- const j = queryJoinTable(state, q, data);
762
- await j._delete();
763
- delete j.query[toSqlCacheKey];
764
- const ids = await queryRelatedTable(query, q, params.set)._pluck(apk);
765
- await insertToJoinTable(state, j, data, ids);
766
- }
767
- },
828
+ virtualColumn: new HasAndBelongsToManyVirtualColumn(relationName, state),
768
829
  joinQuery(fromQuery, toQuery) {
769
830
  return toQuery.whereExists(
770
831
  subQuery,
@@ -830,39 +891,201 @@ const insertToJoinTable = (state, joinTableTransaction, data, ids) => {
830
891
  )
831
892
  );
832
893
  };
894
+ const nestedInsert = ({
895
+ relatedTableQuery,
896
+ joinTableQuery,
897
+ primaryKey,
898
+ foreignKey,
899
+ associationPrimaryKey,
900
+ associationForeignKey
901
+ }) => {
902
+ return async (q, data) => {
903
+ const connect = data.filter(
904
+ (item) => Boolean(item[1].connect)
905
+ );
906
+ const t = relatedTableQuery.transacting(q);
907
+ let connected;
908
+ if (connect.length) {
909
+ connected = await Promise.all(
910
+ connect.flatMap(
911
+ ([, { connect: connect2 }]) => connect2.map(
912
+ (item) => t.select(associationPrimaryKey)._findBy(item)._take()
913
+ )
914
+ )
915
+ );
916
+ } else {
917
+ connected = [];
918
+ }
919
+ const connectOrCreate = data.filter(
920
+ (item) => Boolean(item[1].connectOrCreate)
921
+ );
922
+ let connectOrCreated;
923
+ if (connectOrCreate.length) {
924
+ connectOrCreated = await Promise.all(
925
+ connectOrCreate.flatMap(
926
+ ([, { connectOrCreate: connectOrCreate2 }]) => connectOrCreate2.map(
927
+ (item) => t.select(associationPrimaryKey)._findBy(item.where)._takeOptional()
928
+ )
929
+ )
930
+ );
931
+ } else {
932
+ connectOrCreated = [];
933
+ }
934
+ let connectOrCreateI = 0;
935
+ const create = data.filter(
936
+ (item) => {
937
+ if (item[1].connectOrCreate) {
938
+ const length = item[1].connectOrCreate.length;
939
+ connectOrCreateI += length;
940
+ for (let i = length; i > 0; i--) {
941
+ if (!connectOrCreated[connectOrCreateI - i])
942
+ return true;
943
+ }
944
+ }
945
+ return Boolean(item[1].create);
946
+ }
947
+ );
948
+ connectOrCreateI = 0;
949
+ let created;
950
+ if (create.length) {
951
+ created = await t.select(associationPrimaryKey)._createMany(
952
+ create.flatMap(([, { create: create2 = [], connectOrCreate: connectOrCreate2 = [] }]) => [
953
+ ...create2,
954
+ ...connectOrCreate2.filter(() => !connectOrCreated[connectOrCreateI++]).map((item) => item.create)
955
+ ])
956
+ );
957
+ } else {
958
+ created = [];
959
+ }
960
+ const allKeys = data;
961
+ let createI = 0;
962
+ let connectI = 0;
963
+ connectOrCreateI = 0;
964
+ data.forEach(([, data2], index) => {
965
+ if (data2.create || data2.connectOrCreate) {
966
+ if (data2.create) {
967
+ const len = data2.create.length;
968
+ allKeys[index][1] = created.slice(createI, createI + len);
969
+ createI += len;
970
+ }
971
+ if (data2.connectOrCreate) {
972
+ const arr = [];
973
+ allKeys[index][1] = arr;
974
+ const len = data2.connectOrCreate.length;
975
+ for (let i = 0; i < len; i++) {
976
+ const item = connectOrCreated[connectOrCreateI++];
977
+ if (item) {
978
+ arr.push(item);
979
+ } else {
980
+ arr.push(created[createI++]);
981
+ }
982
+ }
983
+ }
984
+ }
985
+ if (data2.connect) {
986
+ const len = data2.connect.length;
987
+ allKeys[index][1] = connected.slice(connectI, connectI + len);
988
+ connectI += len;
989
+ }
990
+ });
991
+ await joinTableQuery.transacting(q)._count()._createMany(
992
+ allKeys.flatMap(([selfData, relationKeys]) => {
993
+ const selfKey = selfData[primaryKey];
994
+ return relationKeys.map((relationData) => ({
995
+ [foreignKey]: selfKey,
996
+ [associationForeignKey]: relationData[associationPrimaryKey]
997
+ }));
998
+ })
999
+ );
1000
+ };
1001
+ };
1002
+ const nestedUpdate = (state) => {
1003
+ return async (q, data, params) => {
1004
+ if (params.create) {
1005
+ const ids = await state.relatedTableQuery.transacting(q)._pluck(state.associationPrimaryKey)._createMany(params.create);
1006
+ await state.joinTableQuery.transacting(q)._createMany(
1007
+ data.flatMap(
1008
+ (item) => ids.map((id) => ({
1009
+ [state.foreignKey]: item[state.primaryKey],
1010
+ [state.associationForeignKey]: id
1011
+ }))
1012
+ )
1013
+ );
1014
+ }
1015
+ if (params.update) {
1016
+ await state.relatedTableQuery.transacting(q)._whereExists(
1017
+ state.joinTableQuery,
1018
+ (q2) => q2._on(
1019
+ state.associationForeignKeyFull,
1020
+ state.associationPrimaryKeyFull
1021
+ )._where({
1022
+ IN: {
1023
+ columns: [state.foreignKeyFull],
1024
+ values: [data.map((item) => item[state.primaryKey])]
1025
+ }
1026
+ })
1027
+ )._where(
1028
+ Array.isArray(params.update.where) ? { OR: params.update.where } : params.update.where
1029
+ )._update(params.update.data);
1030
+ }
1031
+ if (params.disconnect) {
1032
+ await queryJoinTable(state, q, data, params.disconnect)._delete();
1033
+ }
1034
+ if (params.delete) {
1035
+ const j = queryJoinTable(state, q, data, params.delete);
1036
+ const ids = await j._pluck(state.associationForeignKey)._delete();
1037
+ await queryRelatedTable(state.relatedTableQuery, q, {
1038
+ [state.associationPrimaryKey]: { in: ids }
1039
+ })._delete();
1040
+ }
1041
+ if (params.set) {
1042
+ const j = queryJoinTable(state, q, data);
1043
+ await j._delete();
1044
+ delete j.query[toSqlCacheKey];
1045
+ const ids = await queryRelatedTable(
1046
+ state.relatedTableQuery,
1047
+ q,
1048
+ params.set
1049
+ )._pluck(state.associationPrimaryKey);
1050
+ await insertToJoinTable(state, j, data, ids);
1051
+ }
1052
+ };
1053
+ };
833
1054
 
834
- const applyRelations = (qb, models, result) => {
835
- const modelsEntries = Object.entries(models);
1055
+ const applyRelations = (qb, tables, result) => {
1056
+ const tableEntries = Object.entries(tables);
836
1057
  const delayedRelations = /* @__PURE__ */ new Map();
837
- for (const modelName in models) {
838
- const model = models[modelName];
839
- if (!("relations" in model) || typeof model.relations !== "object")
1058
+ for (const name in tables) {
1059
+ const table = tables[name];
1060
+ if (!("relations" in table) || typeof table.relations !== "object")
840
1061
  continue;
841
- const dbModel = result[modelName];
842
- for (const relationName in model.relations) {
843
- const relation = model.relations[relationName];
844
- const otherModelClass = relation.fn();
845
- const otherModel = modelsEntries.find(
846
- (pair) => pair[1] instanceof otherModelClass
1062
+ const dbTable = result[name];
1063
+ for (const relationName in table.relations) {
1064
+ const relation = table.relations[relationName];
1065
+ const otherTableClass = relation.fn();
1066
+ const otherTable = tableEntries.find(
1067
+ (pair) => pair[1] instanceof otherTableClass
847
1068
  );
848
- if (!otherModel) {
849
- throw new Error(`Cannot find model for class ${otherModelClass.name}`);
1069
+ if (!otherTable) {
1070
+ throw new Error(
1071
+ `Cannot find table class for class ${otherTableClass.name}`
1072
+ );
850
1073
  }
851
- const otherModelName = otherModel[0];
852
- const otherDbModel = result[otherModelName];
853
- if (!otherDbModel)
854
- throw new Error(`Cannot find model by name ${otherModelName}`);
1074
+ const otherTableName = otherTable[0];
1075
+ const otherDbTable = result[otherTableName];
1076
+ if (!otherDbTable)
1077
+ throw new Error(`Cannot find table class by name ${otherTableName}`);
855
1078
  const data = {
856
1079
  relationName,
857
1080
  relation,
858
- dbModel,
859
- otherDbModel
1081
+ dbTable,
1082
+ otherDbTable
860
1083
  };
861
1084
  const options = relation.options;
862
1085
  if (typeof options.through === "string" && typeof options.source === "string") {
863
- const throughRelation = getThroughRelation(dbModel, options.through);
1086
+ const throughRelation = getThroughRelation(dbTable, options.through);
864
1087
  if (!throughRelation) {
865
- delayRelation(delayedRelations, dbModel, options.through, data);
1088
+ delayRelation(delayedRelations, dbTable, options.through, data);
866
1089
  continue;
867
1090
  }
868
1091
  const sourceRelation = getSourceRelation(
@@ -872,7 +1095,7 @@ const applyRelations = (qb, models, result) => {
872
1095
  if (!sourceRelation) {
873
1096
  delayRelation(
874
1097
  delayedRelations,
875
- throughRelation.model,
1098
+ throughRelation.table,
876
1099
  options.source,
877
1100
  data
878
1101
  );
@@ -887,92 +1110,99 @@ const applyRelations = (qb, models, result) => {
887
1110
  for (const key in value) {
888
1111
  for (const item of value[key]) {
889
1112
  const { relation } = item;
890
- if (item.dbModel.relations[item.relationName])
1113
+ if (item.dbTable.relations[item.relationName])
891
1114
  continue;
892
- const as = item.dbModel.definedAs;
1115
+ const as = item.dbTable.definedAs;
893
1116
  let message = `Cannot define a \`${item.relationName}\` relation on \`${as}\``;
894
- const model = result[as];
1117
+ const table = result[as];
895
1118
  const { through, source } = relation.options;
896
- const throughRel = model.relations[through];
1119
+ const throughRel = table.relations[through];
897
1120
  if (through && !throughRel) {
898
1121
  message += `: cannot find \`${through}\` relation required by the \`through\` option`;
899
- } else if (source && throughRel && !throughRel.model.relations[source]) {
900
- message += `: cannot find \`${source}\` relation in \`${throughRel.model.definedAs}\` required by the \`source\` option`;
1122
+ } else if (source && throughRel && !throughRel.table.relations[source]) {
1123
+ message += `: cannot find \`${source}\` relation in \`${throughRel.table.definedAs}\` required by the \`source\` option`;
901
1124
  }
902
1125
  throw new Error(message);
903
1126
  }
904
1127
  }
905
1128
  }
906
1129
  };
907
- const delayRelation = (delayedRelations, model, relationName, data) => {
908
- let modelRelations = delayedRelations.get(model);
909
- if (!modelRelations) {
910
- modelRelations = {};
911
- delayedRelations.set(model, modelRelations);
1130
+ const delayRelation = (delayedRelations, table, relationName, data) => {
1131
+ let tableRelations = delayedRelations.get(table);
1132
+ if (!tableRelations) {
1133
+ tableRelations = {};
1134
+ delayedRelations.set(table, tableRelations);
912
1135
  }
913
- if (modelRelations[relationName]) {
914
- modelRelations[relationName].push(data);
1136
+ if (tableRelations[relationName]) {
1137
+ tableRelations[relationName].push(data);
915
1138
  } else {
916
- modelRelations[relationName] = [data];
1139
+ tableRelations[relationName] = [data];
917
1140
  }
918
1141
  };
919
- const applyRelation = (qb, { relationName, relation, dbModel, otherDbModel }, delayedRelations) => {
1142
+ const applyRelation = (qb, { relationName, relation, dbTable, otherDbTable }, delayedRelations) => {
920
1143
  var _a;
921
- const query = (relation.options.scope ? relation.options.scope(otherDbModel) : otherDbModel).as(relationName);
1144
+ const query = (relation.options.scope ? relation.options.scope(otherDbTable) : otherDbTable).as(relationName);
922
1145
  const definedAs = query.definedAs;
923
1146
  if (!definedAs) {
924
1147
  throw new Error(
925
- `Model for table ${query.table} is not attached to db instance`
1148
+ `Table class for table ${query.table} is not attached to db instance`
926
1149
  );
927
1150
  }
928
1151
  const { type } = relation;
929
1152
  let data;
930
1153
  if (type === "belongsTo") {
931
- data = makeBelongsToMethod(relation, query);
1154
+ data = makeBelongsToMethod(relation, relationName, query);
932
1155
  } else if (type === "hasOne") {
933
- data = makeHasOneMethod(dbModel, relation, relationName, query);
1156
+ data = makeHasOneMethod(dbTable, relation, relationName, query);
934
1157
  } else if (type === "hasMany") {
935
- data = makeHasManyMethod(dbModel, relation, relationName, query);
1158
+ data = makeHasManyMethod(dbTable, relation, relationName, query);
936
1159
  } else if (type === "hasAndBelongsToMany") {
937
- data = makeHasAndBelongsToManyMethod(dbModel, qb, relation, query);
1160
+ data = makeHasAndBelongsToManyMethod(
1161
+ dbTable,
1162
+ qb,
1163
+ relation,
1164
+ relationName,
1165
+ query
1166
+ );
938
1167
  } else {
939
1168
  throw new Error(`Unknown relation type ${type}`);
940
1169
  }
941
1170
  if (data.returns === "one") {
942
1171
  query._take();
943
1172
  }
944
- makeRelationQuery(dbModel, definedAs, relationName, data);
945
- dbModel.relations[relationName] = {
1173
+ if (data.virtualColumn) {
1174
+ dbTable.shape[relationName] = data.virtualColumn;
1175
+ }
1176
+ makeRelationQuery(dbTable, definedAs, relationName, data);
1177
+ dbTable.relations[relationName] = {
946
1178
  type,
947
1179
  key: relationName,
948
- model: otherDbModel,
1180
+ table: otherDbTable,
949
1181
  query,
950
- nestedInsert: data.nestedInsert,
951
- nestedUpdate: data.nestedUpdate,
952
1182
  joinQuery: data.joinQuery,
953
1183
  primaryKey: data.primaryKey,
954
1184
  options: relation.options
955
1185
  };
956
- const modelRelations = delayedRelations.get(dbModel);
957
- if (!modelRelations)
1186
+ const tableRelations = delayedRelations.get(dbTable);
1187
+ if (!tableRelations)
958
1188
  return;
959
- (_a = modelRelations[relationName]) == null ? void 0 : _a.forEach((data2) => {
1189
+ (_a = tableRelations[relationName]) == null ? void 0 : _a.forEach((data2) => {
960
1190
  applyRelation(qb, data2, delayedRelations);
961
1191
  });
962
1192
  };
963
- const makeRelationQuery = (model, definedAs, relationName, data) => {
964
- Object.defineProperty(model, relationName, {
1193
+ const makeRelationQuery = (table, definedAs, relationName, data) => {
1194
+ Object.defineProperty(table, relationName, {
965
1195
  get() {
966
1196
  var _a;
967
- const toModel = this.db[definedAs].as(relationName);
1197
+ const toTable = this.db[definedAs].as(relationName);
968
1198
  if (data.returns === "one") {
969
- toModel._take();
1199
+ toTable._take();
970
1200
  }
971
- const query = this.isSubQuery ? toModel : toModel._whereExists(data.reverseJoin(this, toModel), (q) => q);
1201
+ const query = this.isSubQuery ? toTable : toTable._whereExists(data.reverseJoin(this, toTable), (q) => q);
972
1202
  query.query[relationQueryKey] = {
973
1203
  relationName,
974
1204
  sourceQuery: this,
975
- relationQuery: toModel,
1205
+ relationQuery: toTable,
976
1206
  joinQuery: data.joinQuery
977
1207
  };
978
1208
  const setQuery = (_a = data.modifyRelatedQuery) == null ? void 0 : _a.call(data, query);
@@ -995,10 +1225,10 @@ function transaction(fn) {
995
1225
  for (const key in this) {
996
1226
  const value = this[key];
997
1227
  if (value instanceof Db) {
998
- const model = value.transacting(q);
999
- model.__model = model;
1000
- model.db = orm;
1001
- orm[key] = model;
1228
+ const table = value.transacting(q);
1229
+ table.__table = table;
1230
+ table.db = orm;
1231
+ orm[key] = table;
1002
1232
  } else {
1003
1233
  orm[key] = value;
1004
1234
  }
@@ -1038,7 +1268,7 @@ var __objRest = (source, exclude) => {
1038
1268
  }
1039
1269
  return target;
1040
1270
  };
1041
- const orchidORM = (_a, models) => {
1271
+ const orchidORM = (_a, tables) => {
1042
1272
  var _b = _a, {
1043
1273
  log,
1044
1274
  logger,
@@ -1072,31 +1302,31 @@ const orchidORM = (_a, models) => {
1072
1302
  $queryBuilder: qb,
1073
1303
  $close: () => adapter.close()
1074
1304
  };
1075
- const modelInstances = {};
1076
- for (const key in models) {
1305
+ const tableInstances = {};
1306
+ for (const key in tables) {
1077
1307
  if (key[0] === "$") {
1078
- throw new Error(`Model name must not start with $`);
1308
+ throw new Error(`Table class name must not start with $`);
1079
1309
  }
1080
- const model = new models[key]();
1081
- modelInstances[key] = model;
1310
+ const table = new tables[key]();
1311
+ tableInstances[key] = table;
1082
1312
  const options2 = __spreadProps(__spreadValues$1({}, commonOptions), {
1083
- schema: model.schema
1313
+ schema: table.schema
1084
1314
  });
1085
- if (model.noPrimaryKey)
1315
+ if (table.noPrimaryKey)
1086
1316
  options2.noPrimaryKey = "ignore";
1087
- const dbModel = new Db(
1317
+ const dbTable = new Db(
1088
1318
  adapter,
1089
1319
  qb,
1090
- model.table,
1091
- model.columns.shape,
1092
- model.columnTypes,
1320
+ table.table,
1321
+ table.columns.shape,
1322
+ table.columnTypes,
1093
1323
  options2
1094
1324
  );
1095
- dbModel.definedAs = key;
1096
- dbModel.db = result;
1097
- result[key] = dbModel;
1325
+ dbTable.definedAs = key;
1326
+ dbTable.db = result;
1327
+ result[key] = dbTable;
1098
1328
  }
1099
- applyRelations(qb, modelInstances, result);
1329
+ applyRelations(qb, tableInstances, result);
1100
1330
  return result;
1101
1331
  };
1102
1332
 
@@ -1116,26 +1346,26 @@ var __spreadValues = (a, b) => {
1116
1346
  }
1117
1347
  return a;
1118
1348
  };
1119
- const createRepo = (model, methods) => {
1349
+ const createRepo = (table, methods) => {
1120
1350
  const queryMethods = __spreadValues(__spreadValues(__spreadValues(__spreadValues({}, methods.queryMethods), methods.queryOneMethods), methods.queryWithWhereMethods), methods.queryOneWithWhereMethods);
1121
1351
  const plainMethods = methods.methods;
1122
1352
  const repo = (q2) => {
1123
- const proto = Object.create(q2.__model);
1124
- proto.__model = proto;
1353
+ const proto = Object.create(q2.__table);
1354
+ proto.__table = proto;
1125
1355
  const result = Object.create(proto);
1126
1356
  result.query = getClonedQueryData(q2.query);
1127
1357
  if (plainMethods) {
1128
- Object.assign(proto.__model, plainMethods);
1358
+ Object.assign(proto.__table, plainMethods);
1129
1359
  }
1130
1360
  for (const key in queryMethods) {
1131
1361
  const method = queryMethods[key];
1132
- proto.__model[key] = function(...args) {
1362
+ proto.__table[key] = function(...args) {
1133
1363
  return method(this, ...args);
1134
1364
  };
1135
1365
  }
1136
1366
  return result;
1137
1367
  };
1138
- const q = repo(model);
1368
+ const q = repo(table);
1139
1369
  return new Proxy(repo, {
1140
1370
  get(_, key) {
1141
1371
  return q[key];
@@ -1143,5 +1373,5 @@ const createRepo = (model, methods) => {
1143
1373
  });
1144
1374
  };
1145
1375
 
1146
- export { createModel, createRepo, orchidORM };
1376
+ export { createBaseTable, createRepo, orchidORM };
1147
1377
  //# sourceMappingURL=index.esm.js.map