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