orchid-orm 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1116 @@
1
+ import { getColumnTypes, isQueryReturnsAll, addQueryOn, getQueryAs, toSqlCacheKey, pushQueryValue, NotFoundError, relationQueryKey, Db, Adapter, columnTypes, getClonedQueryData } from 'pqb';
2
+
3
+ const createModel = (options) => {
4
+ return class Model {
5
+ constructor() {
6
+ this.setColumns = (fn) => {
7
+ const shape = getColumnTypes(options.columnTypes, fn);
8
+ return {
9
+ shape,
10
+ type: void 0
11
+ };
12
+ };
13
+ this.columnTypes = options.columnTypes;
14
+ }
15
+ belongsTo(fn, options2) {
16
+ return {
17
+ type: "belongsTo",
18
+ returns: "one",
19
+ fn,
20
+ options: options2
21
+ };
22
+ }
23
+ hasOne(fn, options2) {
24
+ return {
25
+ type: "hasOne",
26
+ returns: "one",
27
+ fn,
28
+ options: options2
29
+ };
30
+ }
31
+ hasMany(fn, options2) {
32
+ return {
33
+ type: "hasMany",
34
+ returns: "many",
35
+ fn,
36
+ options: options2
37
+ };
38
+ }
39
+ hasAndBelongsToMany(fn, options2) {
40
+ return {
41
+ type: "hasAndBelongsToMany",
42
+ returns: "many",
43
+ fn,
44
+ options: options2
45
+ };
46
+ }
47
+ };
48
+ };
49
+
50
+ const makeBelongsToMethod = (relation, query) => {
51
+ const { primaryKey, foreignKey } = relation.options;
52
+ return {
53
+ returns: "one",
54
+ method: (params) => {
55
+ return query.findBy({ [primaryKey]: params[foreignKey] });
56
+ },
57
+ nestedInsert: async (q, data) => {
58
+ const connectOrCreate = data.filter(
59
+ (item) => Boolean(item.connectOrCreate)
60
+ );
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
+ }
80
+ }
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
+ }
92
+ const connect = data.filter(
93
+ (item) => Boolean(item.connect)
94
+ );
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++]
108
+ );
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);
138
+ }
139
+ }
140
+ if (upsert) {
141
+ if (!state.updateLater) {
142
+ state.updateLater = {};
143
+ state.updateLaterPromises = [];
144
+ }
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
+ }
174
+ }
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
186
+ };
187
+ };
188
+
189
+ const getThroughRelation = (model, through) => {
190
+ return model.relations[through];
191
+ };
192
+ const getSourceRelation = (throughRelation, source) => {
193
+ return throughRelation.model.relations[source];
194
+ };
195
+
196
+ var __defProp$4 = Object.defineProperty;
197
+ var __defProps$2 = Object.defineProperties;
198
+ var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors;
199
+ var __getOwnPropSymbols$4 = Object.getOwnPropertySymbols;
200
+ var __hasOwnProp$4 = Object.prototype.hasOwnProperty;
201
+ var __propIsEnum$4 = Object.prototype.propertyIsEnumerable;
202
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
203
+ var __spreadValues$4 = (a, b) => {
204
+ for (var prop in b || (b = {}))
205
+ if (__hasOwnProp$4.call(b, prop))
206
+ __defNormalProp$4(a, prop, b[prop]);
207
+ if (__getOwnPropSymbols$4)
208
+ for (var prop of __getOwnPropSymbols$4(b)) {
209
+ if (__propIsEnum$4.call(b, prop))
210
+ __defNormalProp$4(a, prop, b[prop]);
211
+ }
212
+ return a;
213
+ };
214
+ var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b));
215
+ const makeHasOneMethod = (model, relation, relationName, query) => {
216
+ if (relation.options.required) {
217
+ query._take();
218
+ } else {
219
+ query._takeOptional();
220
+ }
221
+ if ("through" in relation.options) {
222
+ const { through, source } = relation.options;
223
+ const throughRelation = getThroughRelation(model, through);
224
+ const sourceRelation = getSourceRelation(throughRelation, source);
225
+ const sourceQuery = sourceRelation.joinQuery(throughRelation.query, sourceRelation.query).as(relationName);
226
+ const whereExistsCallback = () => sourceQuery;
227
+ return {
228
+ returns: "one",
229
+ method: (params) => {
230
+ const throughQuery = model[through](params);
231
+ return query.whereExists(
232
+ throughQuery,
233
+ whereExistsCallback
234
+ );
235
+ },
236
+ nestedInsert: void 0,
237
+ nestedUpdate: void 0,
238
+ joinQuery(fromQuery, toQuery) {
239
+ return toQuery.whereExists(
240
+ throughRelation.joinQuery(fromQuery, throughRelation.query),
241
+ () => {
242
+ const as = getQueryAs(toQuery);
243
+ return sourceRelation.joinQuery(
244
+ throughRelation.query,
245
+ sourceRelation.query.as(as)
246
+ );
247
+ }
248
+ );
249
+ },
250
+ reverseJoin(fromQuery, toQuery) {
251
+ return fromQuery.whereExists(
252
+ throughRelation.joinQuery(fromQuery, throughRelation.query),
253
+ () => {
254
+ const as = getQueryAs(toQuery);
255
+ return sourceRelation.joinQuery(
256
+ throughRelation.query,
257
+ sourceRelation.query.as(as)
258
+ );
259
+ }
260
+ );
261
+ },
262
+ primaryKey: sourceRelation.primaryKey
263
+ };
264
+ }
265
+ const { primaryKey, foreignKey } = relation.options;
266
+ const fromQuerySelect = [{ selectAs: { [foreignKey]: primaryKey } }];
267
+ return {
268
+ returns: "one",
269
+ method: (params) => {
270
+ const values = { [foreignKey]: params[primaryKey] };
271
+ return query.where(values)._defaults(values);
272
+ },
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
+ },
342
+ joinQuery(fromQuery, toQuery) {
343
+ return addQueryOn(toQuery, fromQuery, toQuery, foreignKey, primaryKey);
344
+ },
345
+ reverseJoin(fromQuery, toQuery) {
346
+ return addQueryOn(fromQuery, toQuery, fromQuery, primaryKey, foreignKey);
347
+ },
348
+ primaryKey,
349
+ modifyRelatedQuery(relationQuery) {
350
+ return (query2) => {
351
+ const fromQuery = query2.clone();
352
+ fromQuery.query.select = fromQuerySelect;
353
+ relationQuery.query.fromQuery = fromQuery;
354
+ };
355
+ }
356
+ };
357
+ };
358
+
359
+ var __defProp$3 = Object.defineProperty;
360
+ var __defProps$1 = Object.defineProperties;
361
+ var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
362
+ var __getOwnPropSymbols$3 = Object.getOwnPropertySymbols;
363
+ var __hasOwnProp$3 = Object.prototype.hasOwnProperty;
364
+ var __propIsEnum$3 = Object.prototype.propertyIsEnumerable;
365
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
366
+ var __spreadValues$3 = (a, b) => {
367
+ for (var prop in b || (b = {}))
368
+ if (__hasOwnProp$3.call(b, prop))
369
+ __defNormalProp$3(a, prop, b[prop]);
370
+ if (__getOwnPropSymbols$3)
371
+ for (var prop of __getOwnPropSymbols$3(b)) {
372
+ if (__propIsEnum$3.call(b, prop))
373
+ __defNormalProp$3(a, prop, b[prop]);
374
+ }
375
+ return a;
376
+ };
377
+ var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
378
+ const makeHasManyMethod = (model, relation, relationName, query) => {
379
+ if ("through" in relation.options) {
380
+ const { through, source } = relation.options;
381
+ const throughRelation = getThroughRelation(model, through);
382
+ const sourceRelation = getSourceRelation(throughRelation, source);
383
+ const sourceRelationQuery = sourceRelation.query.as(relationName);
384
+ const sourceQuery = sourceRelation.joinQuery(
385
+ throughRelation.query,
386
+ sourceRelationQuery
387
+ );
388
+ const whereExistsCallback = () => sourceQuery;
389
+ return {
390
+ returns: "many",
391
+ method: (params) => {
392
+ const throughQuery = model[through](params);
393
+ return query.whereExists(
394
+ throughQuery,
395
+ whereExistsCallback
396
+ );
397
+ },
398
+ nestedInsert: void 0,
399
+ nestedUpdate: void 0,
400
+ joinQuery(fromQuery, toQuery) {
401
+ return toQuery.whereExists(
402
+ throughRelation.joinQuery(fromQuery, throughRelation.query),
403
+ () => {
404
+ const as = getQueryAs(toQuery);
405
+ return sourceRelation.joinQuery(
406
+ throughRelation.query,
407
+ sourceRelation.query.as(as)
408
+ );
409
+ }
410
+ );
411
+ },
412
+ reverseJoin(fromQuery, toQuery) {
413
+ return fromQuery.whereExists(
414
+ throughRelation.joinQuery(fromQuery, throughRelation.query),
415
+ () => {
416
+ const as = getQueryAs(toQuery);
417
+ return sourceRelation.joinQuery(
418
+ throughRelation.query,
419
+ sourceRelation.query.as(as)
420
+ );
421
+ }
422
+ );
423
+ },
424
+ primaryKey: sourceRelation.primaryKey
425
+ };
426
+ }
427
+ const { primaryKey, foreignKey } = relation.options;
428
+ const fromQuerySelect = [{ selectAs: { [foreignKey]: primaryKey } }];
429
+ return {
430
+ returns: "many",
431
+ method: (params) => {
432
+ const values = { [foreignKey]: params[primaryKey] };
433
+ return query.where(values)._defaults(values);
434
+ },
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 }]) => connect2.map(
444
+ (item) => t.where(item)._updateOrThrow({ [foreignKey]: selfData[primaryKey] })
445
+ )
446
+ )
447
+ );
448
+ }
449
+ const connectOrCreate = data.filter(
450
+ (item) => Boolean(item[1].connectOrCreate)
451
+ );
452
+ let connected;
453
+ if (connectOrCreate.length) {
454
+ connected = await Promise.all(
455
+ connectOrCreate.flatMap(
456
+ ([selfData, { connectOrCreate: connectOrCreate2 }]) => connectOrCreate2.map(
457
+ (item) => t.where(item.where)._update({
458
+ [foreignKey]: selfData[primaryKey]
459
+ })
460
+ )
461
+ )
462
+ );
463
+ } else {
464
+ connected = [];
465
+ }
466
+ let connectedI = 0;
467
+ const create = data.filter(
468
+ (item) => {
469
+ if (item[1].connectOrCreate) {
470
+ const length = item[1].connectOrCreate.length;
471
+ connectedI += length;
472
+ for (let i = length; i > 0; i--) {
473
+ if (connected[connectedI - i] === 0)
474
+ return true;
475
+ }
476
+ }
477
+ return Boolean(item[1].create);
478
+ }
479
+ );
480
+ connectedI = 0;
481
+ if (create.length) {
482
+ await t._createMany(
483
+ create.flatMap(
484
+ ([selfData, { create: create2 = [], connectOrCreate: connectOrCreate2 = [] }]) => {
485
+ return [
486
+ ...create2.map((item) => __spreadValues$3({
487
+ [foreignKey]: selfData[primaryKey]
488
+ }, item)),
489
+ ...connectOrCreate2.filter(() => connected[connectedI++] === 0).map((item) => __spreadValues$3({
490
+ [foreignKey]: selfData[primaryKey]
491
+ }, item.create))
492
+ ];
493
+ }
494
+ )
495
+ );
496
+ }
497
+ },
498
+ nestedUpdate: async (q, data, params) => {
499
+ var _a;
500
+ if ((params.set || params.create) && isQueryReturnsAll(q)) {
501
+ const key = params.set ? "set" : "create";
502
+ throw new Error(`\`${key}\` option is not allowed in a batch update`);
503
+ }
504
+ const t = query.transacting(q);
505
+ if (params.create) {
506
+ await t._count()._createMany(
507
+ params.create.map((create) => __spreadProps$1(__spreadValues$3({}, create), {
508
+ [foreignKey]: data[0][primaryKey]
509
+ }))
510
+ );
511
+ delete t.query[toSqlCacheKey];
512
+ }
513
+ if (params.disconnect || params.set) {
514
+ await t.where(
515
+ getWhereForNestedUpdate(
516
+ data,
517
+ params.disconnect,
518
+ primaryKey,
519
+ foreignKey
520
+ )
521
+ )._update({ [foreignKey]: null });
522
+ if (params.set) {
523
+ delete t.query[toSqlCacheKey];
524
+ await t.where(
525
+ Array.isArray(params.set) ? {
526
+ OR: params.set
527
+ } : params.set
528
+ )._update({ [foreignKey]: data[0][primaryKey] });
529
+ }
530
+ }
531
+ if (params.delete || params.update) {
532
+ delete t.query[toSqlCacheKey];
533
+ const q2 = t._where(
534
+ getWhereForNestedUpdate(
535
+ data,
536
+ params.delete || ((_a = params.update) == null ? void 0 : _a.where),
537
+ primaryKey,
538
+ foreignKey
539
+ )
540
+ );
541
+ if (params.delete) {
542
+ await q2._delete();
543
+ } else if (params.update) {
544
+ await q2._update(params.update.data);
545
+ }
546
+ }
547
+ },
548
+ joinQuery(fromQuery, toQuery) {
549
+ return addQueryOn(toQuery, fromQuery, toQuery, foreignKey, primaryKey);
550
+ },
551
+ reverseJoin(fromQuery, toQuery) {
552
+ return addQueryOn(fromQuery, toQuery, fromQuery, primaryKey, foreignKey);
553
+ },
554
+ primaryKey,
555
+ modifyRelatedQuery(relationQuery) {
556
+ return (query2) => {
557
+ const fromQuery = query2.clone();
558
+ fromQuery.query.select = fromQuerySelect;
559
+ relationQuery.query.fromQuery = fromQuery;
560
+ };
561
+ }
562
+ };
563
+ };
564
+ const getWhereForNestedUpdate = (data, params, primaryKey, foreignKey) => {
565
+ const where = {
566
+ [foreignKey]: { in: data.map((item) => item[primaryKey]) }
567
+ };
568
+ if (params) {
569
+ if (Array.isArray(params)) {
570
+ where.OR = params;
571
+ } else {
572
+ Object.assign(where, params);
573
+ }
574
+ }
575
+ return where;
576
+ };
577
+
578
+ var __defProp$2 = Object.defineProperty;
579
+ var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols;
580
+ var __hasOwnProp$2 = Object.prototype.hasOwnProperty;
581
+ var __propIsEnum$2 = Object.prototype.propertyIsEnumerable;
582
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
583
+ var __spreadValues$2 = (a, b) => {
584
+ for (var prop in b || (b = {}))
585
+ if (__hasOwnProp$2.call(b, prop))
586
+ __defNormalProp$2(a, prop, b[prop]);
587
+ if (__getOwnPropSymbols$2)
588
+ for (var prop of __getOwnPropSymbols$2(b)) {
589
+ if (__propIsEnum$2.call(b, prop))
590
+ __defNormalProp$2(a, prop, b[prop]);
591
+ }
592
+ return a;
593
+ };
594
+ const makeHasAndBelongsToManyMethod = (model, qb, relation, query) => {
595
+ const {
596
+ primaryKey: pk,
597
+ foreignKey: fk,
598
+ associationPrimaryKey: apk,
599
+ associationForeignKey: afk,
600
+ joinTable
601
+ } = relation.options;
602
+ const foreignKeyFull = `${joinTable}.${fk}`;
603
+ const associationForeignKeyFull = `${joinTable}.${afk}`;
604
+ const associationPrimaryKeyFull = `${getQueryAs(query)}.${apk}`;
605
+ const __model = Object.create(qb.__model);
606
+ __model.__model = __model;
607
+ __model.table = joinTable;
608
+ __model.shape = {
609
+ [fk]: model.shape[pk],
610
+ [afk]: query.shape[apk]
611
+ };
612
+ const subQuery = Object.create(__model);
613
+ subQuery.query = __spreadValues$2({}, subQuery.query);
614
+ const state = {
615
+ relatedTableQuery: query,
616
+ joinTableQuery: subQuery,
617
+ primaryKey: pk,
618
+ foreignKey: fk,
619
+ associationPrimaryKey: apk,
620
+ associationForeignKey: afk
621
+ };
622
+ return {
623
+ returns: "many",
624
+ method(params) {
625
+ return query.whereExists(
626
+ subQuery,
627
+ (q) => q.on(associationForeignKeyFull, associationPrimaryKeyFull).where({
628
+ [foreignKeyFull]: params[pk]
629
+ })
630
+ );
631
+ },
632
+ nestedInsert: async (q, data) => {
633
+ const connect = data.filter(
634
+ (item) => Boolean(item[1].connect)
635
+ );
636
+ const t = query.transacting(q);
637
+ let connected;
638
+ if (connect.length) {
639
+ connected = await Promise.all(
640
+ connect.flatMap(
641
+ ([, { connect: connect2 }]) => connect2.map((item) => t.select(apk)._findBy(item)._take())
642
+ )
643
+ );
644
+ } else {
645
+ connected = [];
646
+ }
647
+ const connectOrCreate = data.filter(
648
+ (item) => Boolean(item[1].connectOrCreate)
649
+ );
650
+ let connectOrCreated;
651
+ if (connectOrCreate.length) {
652
+ connectOrCreated = await Promise.all(
653
+ connectOrCreate.flatMap(
654
+ ([, { connectOrCreate: connectOrCreate2 }]) => connectOrCreate2.map(
655
+ (item) => t.select(apk)._findBy(item.where)._takeOptional()
656
+ )
657
+ )
658
+ );
659
+ } else {
660
+ connectOrCreated = [];
661
+ }
662
+ let connectOrCreateI = 0;
663
+ const create = data.filter(
664
+ (item) => {
665
+ if (item[1].connectOrCreate) {
666
+ const length = item[1].connectOrCreate.length;
667
+ connectOrCreateI += length;
668
+ for (let i = length; i > 0; i--) {
669
+ if (!connectOrCreated[connectOrCreateI - i])
670
+ return true;
671
+ }
672
+ }
673
+ return Boolean(item[1].create);
674
+ }
675
+ );
676
+ connectOrCreateI = 0;
677
+ let created;
678
+ if (create.length) {
679
+ created = await t.select(apk)._createMany(
680
+ create.flatMap(([, { create: create2 = [], connectOrCreate: connectOrCreate2 = [] }]) => [
681
+ ...create2,
682
+ ...connectOrCreate2.filter(() => !connectOrCreated[connectOrCreateI++]).map((item) => item.create)
683
+ ])
684
+ );
685
+ } else {
686
+ created = [];
687
+ }
688
+ const allKeys = data;
689
+ let createI = 0;
690
+ let connectI = 0;
691
+ connectOrCreateI = 0;
692
+ data.forEach(([, data2], index) => {
693
+ if (data2.create || data2.connectOrCreate) {
694
+ if (data2.create) {
695
+ const len = data2.create.length;
696
+ allKeys[index][1] = created.slice(createI, createI + len);
697
+ createI += len;
698
+ }
699
+ if (data2.connectOrCreate) {
700
+ const arr = [];
701
+ allKeys[index][1] = arr;
702
+ const len = data2.connectOrCreate.length;
703
+ for (let i = 0; i < len; i++) {
704
+ const item = connectOrCreated[connectOrCreateI++];
705
+ if (item) {
706
+ arr.push(item);
707
+ } else {
708
+ arr.push(created[createI++]);
709
+ }
710
+ }
711
+ }
712
+ }
713
+ if (data2.connect) {
714
+ const len = data2.connect.length;
715
+ allKeys[index][1] = connected.slice(connectI, connectI + len);
716
+ connectI += len;
717
+ }
718
+ });
719
+ await subQuery.transacting(q)._count()._createMany(
720
+ allKeys.flatMap(([selfData, relationKeys]) => {
721
+ const selfKey = selfData[pk];
722
+ return relationKeys.map((relationData) => ({
723
+ [fk]: selfKey,
724
+ [afk]: relationData[apk]
725
+ }));
726
+ })
727
+ );
728
+ },
729
+ nestedUpdate: async (q, data, params) => {
730
+ if (params.create) {
731
+ const ids = await query.transacting(q)._pluck(apk)._createMany(params.create);
732
+ await subQuery.transacting(q)._createMany(
733
+ data.flatMap(
734
+ (item) => ids.map((id) => ({
735
+ [fk]: item[pk],
736
+ [afk]: id
737
+ }))
738
+ )
739
+ );
740
+ }
741
+ if (params.update) {
742
+ await query.transacting(q)._whereExists(
743
+ subQuery,
744
+ (q2) => q2._on(associationForeignKeyFull, associationPrimaryKeyFull)._where({
745
+ IN: {
746
+ columns: [foreignKeyFull],
747
+ values: [data.map((item) => item[pk])]
748
+ }
749
+ })
750
+ )._where(
751
+ Array.isArray(params.update.where) ? { OR: params.update.where } : params.update.where
752
+ )._update(params.update.data);
753
+ }
754
+ if (params.disconnect) {
755
+ await queryJoinTable(state, q, data, params.disconnect)._delete();
756
+ }
757
+ if (params.delete) {
758
+ const j = queryJoinTable(state, q, data, params.delete);
759
+ const ids = await j._pluck(afk)._delete();
760
+ await queryRelatedTable(query, q, { [apk]: { in: ids } })._delete();
761
+ }
762
+ if (params.set) {
763
+ const j = queryJoinTable(state, q, data);
764
+ await j._delete();
765
+ delete j.query[toSqlCacheKey];
766
+ const ids = await queryRelatedTable(query, q, params.set)._pluck(apk);
767
+ await insertToJoinTable(state, j, data, ids);
768
+ }
769
+ },
770
+ joinQuery(fromQuery, toQuery) {
771
+ return toQuery.whereExists(
772
+ subQuery,
773
+ (q) => q._on(associationForeignKeyFull, `${getQueryAs(toQuery)}.${pk}`)._on(foreignKeyFull, `${getQueryAs(fromQuery)}.${pk}`)
774
+ );
775
+ },
776
+ reverseJoin(fromQuery, toQuery) {
777
+ return fromQuery.whereExists(
778
+ subQuery,
779
+ (q) => q._on(associationForeignKeyFull, `${getQueryAs(toQuery)}.${pk}`)._on(foreignKeyFull, `${getQueryAs(fromQuery)}.${pk}`)
780
+ );
781
+ },
782
+ primaryKey: pk,
783
+ modifyRelatedQuery(relationQuery) {
784
+ const ref = {};
785
+ pushQueryValue(
786
+ relationQuery,
787
+ "afterCreate",
788
+ async (q, result) => {
789
+ const fromQuery = ref.query.clone();
790
+ fromQuery.query.select = [{ selectAs: { [fk]: pk } }];
791
+ const createdCount = await subQuery.transacting(q).count()._createFrom(
792
+ fromQuery,
793
+ {
794
+ [afk]: result[apk]
795
+ }
796
+ );
797
+ if (createdCount === 0) {
798
+ throw new NotFoundError();
799
+ }
800
+ }
801
+ );
802
+ return (q) => {
803
+ ref.query = q;
804
+ };
805
+ }
806
+ };
807
+ };
808
+ const queryJoinTable = (state, q, data, conditions) => {
809
+ const t = state.joinTableQuery.transacting(q);
810
+ const where = {
811
+ [state.foreignKey]: { in: data.map((item) => item[state.primaryKey]) }
812
+ };
813
+ if (conditions) {
814
+ where[state.associationForeignKey] = {
815
+ in: state.relatedTableQuery.where(
816
+ Array.isArray(conditions) ? { OR: conditions } : conditions
817
+ )._select(state.associationPrimaryKey)
818
+ };
819
+ }
820
+ return t._where(where);
821
+ };
822
+ const queryRelatedTable = (query, q, conditions) => {
823
+ return query.transacting(q)._where(Array.isArray(conditions) ? { OR: conditions } : conditions);
824
+ };
825
+ const insertToJoinTable = (state, joinTableTransaction, data, ids) => {
826
+ return joinTableTransaction._count()._createMany(
827
+ data.flatMap(
828
+ (item) => ids.map((id) => ({
829
+ [state.foreignKey]: item[state.primaryKey],
830
+ [state.associationForeignKey]: id
831
+ }))
832
+ )
833
+ );
834
+ };
835
+
836
+ const applyRelations = (qb, models, result) => {
837
+ const modelsEntries = Object.entries(models);
838
+ const delayedRelations = /* @__PURE__ */ new Map();
839
+ for (const modelName in models) {
840
+ const model = models[modelName];
841
+ if (!("relations" in model) || typeof model.relations !== "object")
842
+ continue;
843
+ const dbModel = result[modelName];
844
+ for (const relationName in model.relations) {
845
+ const relation = model.relations[relationName];
846
+ const otherModelClass = relation.fn();
847
+ const otherModel = modelsEntries.find(
848
+ (pair) => pair[1] instanceof otherModelClass
849
+ );
850
+ if (!otherModel) {
851
+ throw new Error(`Cannot find model for class ${otherModelClass.name}`);
852
+ }
853
+ const otherModelName = otherModel[0];
854
+ const otherDbModel = result[otherModelName];
855
+ if (!otherDbModel)
856
+ throw new Error(`Cannot find model by name ${otherModelName}`);
857
+ const data = {
858
+ relationName,
859
+ relation,
860
+ dbModel,
861
+ otherDbModel
862
+ };
863
+ const options = relation.options;
864
+ if (typeof options.through === "string" && typeof options.source === "string") {
865
+ const throughRelation = getThroughRelation(dbModel, options.through);
866
+ if (!throughRelation) {
867
+ delayRelation(delayedRelations, dbModel, options.through, data);
868
+ continue;
869
+ }
870
+ const sourceRelation = getSourceRelation(
871
+ throughRelation,
872
+ options.source
873
+ );
874
+ if (!sourceRelation) {
875
+ delayRelation(
876
+ delayedRelations,
877
+ throughRelation.model,
878
+ options.source,
879
+ data
880
+ );
881
+ continue;
882
+ }
883
+ }
884
+ applyRelation(qb, data, delayedRelations);
885
+ }
886
+ }
887
+ };
888
+ const delayRelation = (delayedRelations, model, relationName, data) => {
889
+ let modelRelations = delayedRelations.get(model);
890
+ if (!modelRelations) {
891
+ modelRelations = {};
892
+ delayedRelations.set(model, modelRelations);
893
+ }
894
+ if (modelRelations[relationName]) {
895
+ modelRelations[relationName].push(data);
896
+ } else {
897
+ modelRelations[relationName] = [data];
898
+ }
899
+ };
900
+ const applyRelation = (qb, { relationName, relation, dbModel, otherDbModel }, delayedRelations) => {
901
+ var _a;
902
+ const query = (relation.options.scope ? relation.options.scope(otherDbModel) : otherDbModel).as(relationName);
903
+ const definedAs = query.definedAs;
904
+ if (!definedAs) {
905
+ throw new Error(
906
+ `Model for table ${query.table} is not attached to db instance`
907
+ );
908
+ }
909
+ const { type } = relation;
910
+ let data;
911
+ if (type === "belongsTo") {
912
+ data = makeBelongsToMethod(relation, query);
913
+ } else if (type === "hasOne") {
914
+ data = makeHasOneMethod(dbModel, relation, relationName, query);
915
+ } else if (type === "hasMany") {
916
+ data = makeHasManyMethod(dbModel, relation, relationName, query);
917
+ } else if (type === "hasAndBelongsToMany") {
918
+ data = makeHasAndBelongsToManyMethod(dbModel, qb, relation, query);
919
+ } else {
920
+ throw new Error(`Unknown relation type ${type}`);
921
+ }
922
+ if (data.returns === "one") {
923
+ query._take();
924
+ }
925
+ makeRelationQuery(dbModel, definedAs, relationName, data);
926
+ dbModel.relations[relationName] = {
927
+ type,
928
+ key: relationName,
929
+ model: otherDbModel,
930
+ query,
931
+ nestedInsert: data.nestedInsert,
932
+ nestedUpdate: data.nestedUpdate,
933
+ joinQuery: data.joinQuery,
934
+ primaryKey: data.primaryKey,
935
+ options: relation.options
936
+ };
937
+ const modelRelations = delayedRelations.get(dbModel);
938
+ if (!modelRelations)
939
+ return;
940
+ (_a = modelRelations[relationName]) == null ? void 0 : _a.forEach((data2) => {
941
+ applyRelation(qb, data2, delayedRelations);
942
+ });
943
+ };
944
+ const makeRelationQuery = (model, definedAs, relationName, data) => {
945
+ Object.defineProperty(model, relationName, {
946
+ get() {
947
+ var _a;
948
+ const toModel = this.db[definedAs].as(relationName);
949
+ if (data.returns === "one") {
950
+ toModel._take();
951
+ }
952
+ const query = this.isSubQuery ? toModel : toModel._whereExists(data.reverseJoin(this, toModel), (q) => q);
953
+ query.query[relationQueryKey] = {
954
+ relationName,
955
+ sourceQuery: this,
956
+ relationQuery: toModel,
957
+ joinQuery: data.joinQuery
958
+ };
959
+ const setQuery = (_a = data.modifyRelatedQuery) == null ? void 0 : _a.call(data, query);
960
+ setQuery == null ? void 0 : setQuery(this);
961
+ return new Proxy(data.method, {
962
+ get(_, prop) {
963
+ return query[prop];
964
+ }
965
+ });
966
+ }
967
+ });
968
+ };
969
+
970
+ function transaction(fn) {
971
+ if (fn.length === 0) {
972
+ throw new Error("Argument of $transaction callback should be used");
973
+ }
974
+ return this.$queryBuilder.transaction((q) => {
975
+ const orm = {};
976
+ for (const key in this) {
977
+ const value = this[key];
978
+ if (value instanceof Db) {
979
+ const model = value.transacting(q);
980
+ model.__model = model;
981
+ model.db = orm;
982
+ orm[key] = model;
983
+ } else {
984
+ orm[key] = value;
985
+ }
986
+ }
987
+ return fn(orm);
988
+ });
989
+ }
990
+
991
+ var __defProp$1 = Object.defineProperty;
992
+ var __defProps = Object.defineProperties;
993
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
994
+ var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
995
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
996
+ var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
997
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
998
+ var __spreadValues$1 = (a, b) => {
999
+ for (var prop in b || (b = {}))
1000
+ if (__hasOwnProp$1.call(b, prop))
1001
+ __defNormalProp$1(a, prop, b[prop]);
1002
+ if (__getOwnPropSymbols$1)
1003
+ for (var prop of __getOwnPropSymbols$1(b)) {
1004
+ if (__propIsEnum$1.call(b, prop))
1005
+ __defNormalProp$1(a, prop, b[prop]);
1006
+ }
1007
+ return a;
1008
+ };
1009
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
1010
+ var __objRest = (source, exclude) => {
1011
+ var target = {};
1012
+ for (var prop in source)
1013
+ if (__hasOwnProp$1.call(source, prop) && exclude.indexOf(prop) < 0)
1014
+ target[prop] = source[prop];
1015
+ if (source != null && __getOwnPropSymbols$1)
1016
+ for (var prop of __getOwnPropSymbols$1(source)) {
1017
+ if (exclude.indexOf(prop) < 0 && __propIsEnum$1.call(source, prop))
1018
+ target[prop] = source[prop];
1019
+ }
1020
+ return target;
1021
+ };
1022
+ const orchidORM = (_a, models) => {
1023
+ var _b = _a, {
1024
+ log,
1025
+ logger
1026
+ } = _b, options = __objRest(_b, [
1027
+ "log",
1028
+ "logger"
1029
+ ]);
1030
+ const adapter = "adapter" in options ? options.adapter : new Adapter(options);
1031
+ const commonOptions = { log, logger };
1032
+ const qb = new Db(
1033
+ adapter,
1034
+ void 0,
1035
+ void 0,
1036
+ {},
1037
+ columnTypes,
1038
+ commonOptions
1039
+ );
1040
+ qb.queryBuilder = qb;
1041
+ const result = {
1042
+ $transaction: transaction,
1043
+ $adapter: adapter,
1044
+ $queryBuilder: qb,
1045
+ $close: () => adapter.close()
1046
+ };
1047
+ const modelInstances = {};
1048
+ for (const key in models) {
1049
+ if (key[0] === "$") {
1050
+ throw new Error(`Model name must not start with $`);
1051
+ }
1052
+ const model = new models[key]();
1053
+ modelInstances[key] = model;
1054
+ const dbModel = new Db(
1055
+ adapter,
1056
+ qb,
1057
+ model.table,
1058
+ model.columns.shape,
1059
+ model.columnTypes,
1060
+ __spreadProps(__spreadValues$1({}, commonOptions), {
1061
+ schema: model.schema
1062
+ })
1063
+ );
1064
+ dbModel.definedAs = key;
1065
+ dbModel.db = result;
1066
+ result[key] = dbModel;
1067
+ }
1068
+ applyRelations(qb, modelInstances, result);
1069
+ return result;
1070
+ };
1071
+
1072
+ var __defProp = Object.defineProperty;
1073
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
1074
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
1075
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
1076
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1077
+ var __spreadValues = (a, b) => {
1078
+ for (var prop in b || (b = {}))
1079
+ if (__hasOwnProp.call(b, prop))
1080
+ __defNormalProp(a, prop, b[prop]);
1081
+ if (__getOwnPropSymbols)
1082
+ for (var prop of __getOwnPropSymbols(b)) {
1083
+ if (__propIsEnum.call(b, prop))
1084
+ __defNormalProp(a, prop, b[prop]);
1085
+ }
1086
+ return a;
1087
+ };
1088
+ const createRepo = (model, methods) => {
1089
+ const queryMethods = __spreadValues(__spreadValues(__spreadValues(__spreadValues({}, methods.queryMethods), methods.queryOneMethods), methods.queryWithWhereMethods), methods.queryOneWithWhereMethods);
1090
+ const plainMethods = methods.methods;
1091
+ const repo = (q2) => {
1092
+ const proto = Object.create(q2.__model);
1093
+ proto.__model = proto;
1094
+ const result = Object.create(proto);
1095
+ result.query = getClonedQueryData(q2.query);
1096
+ if (plainMethods) {
1097
+ Object.assign(proto.__model, plainMethods);
1098
+ }
1099
+ for (const key in queryMethods) {
1100
+ const method = queryMethods[key];
1101
+ proto.__model[key] = function(...args) {
1102
+ return method(this, ...args);
1103
+ };
1104
+ }
1105
+ return result;
1106
+ };
1107
+ const q = repo(model);
1108
+ return new Proxy(repo, {
1109
+ get(_, key) {
1110
+ return q[key];
1111
+ }
1112
+ });
1113
+ };
1114
+
1115
+ export { createModel, createRepo, orchidORM };
1116
+ //# sourceMappingURL=index.esm.js.map