orchid-orm 1.5.29 → 1.5.31

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 (59) hide show
  1. package/dist/index.d.ts +6 -14
  2. package/dist/index.js +26 -21
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +26 -21
  5. package/dist/index.mjs.map +1 -1
  6. package/package.json +12 -22
  7. package/.env.example +0 -1
  8. package/.turbo/turbo-check.log +0 -26
  9. package/.turbo/turbo-test.log +0 -26
  10. package/.turbo/turbo-test:ci.log +0 -26
  11. package/CHANGELOG.md +0 -382
  12. package/coverage/coverage-summary.json +0 -28
  13. package/jest-setup.ts +0 -11
  14. package/rollup.config.js +0 -18
  15. package/src/bin/bin.ts +0 -3
  16. package/src/bin/init.test.ts +0 -810
  17. package/src/bin/init.ts +0 -529
  18. package/src/codegen/appCodeUpdater.test.ts +0 -75
  19. package/src/codegen/appCodeUpdater.ts +0 -53
  20. package/src/codegen/createBaseTableFile.test.ts +0 -53
  21. package/src/codegen/createBaseTableFile.ts +0 -31
  22. package/src/codegen/fileChanges.ts +0 -41
  23. package/src/codegen/testUtils.ts +0 -56
  24. package/src/codegen/tsUtils.ts +0 -180
  25. package/src/codegen/updateMainFile.test.ts +0 -253
  26. package/src/codegen/updateMainFile.ts +0 -210
  27. package/src/codegen/updateTableFile/changeTable.test.ts +0 -804
  28. package/src/codegen/updateTableFile/changeTable.ts +0 -536
  29. package/src/codegen/updateTableFile/createTable.test.ts +0 -139
  30. package/src/codegen/updateTableFile/createTable.ts +0 -51
  31. package/src/codegen/updateTableFile/renameTable.test.ts +0 -124
  32. package/src/codegen/updateTableFile/renameTable.ts +0 -67
  33. package/src/codegen/updateTableFile/updateTableFile.ts +0 -22
  34. package/src/codegen/utils.ts +0 -13
  35. package/src/index.ts +0 -5
  36. package/src/orm.test.ts +0 -92
  37. package/src/orm.ts +0 -98
  38. package/src/relations/belongsTo.test.ts +0 -1122
  39. package/src/relations/belongsTo.ts +0 -352
  40. package/src/relations/hasAndBelongsToMany.test.ts +0 -1335
  41. package/src/relations/hasAndBelongsToMany.ts +0 -472
  42. package/src/relations/hasMany.test.ts +0 -2616
  43. package/src/relations/hasMany.ts +0 -401
  44. package/src/relations/hasOne.test.ts +0 -1701
  45. package/src/relations/hasOne.ts +0 -351
  46. package/src/relations/relations.test.ts +0 -37
  47. package/src/relations/relations.ts +0 -363
  48. package/src/relations/utils.ts +0 -162
  49. package/src/repo.test.ts +0 -200
  50. package/src/repo.ts +0 -119
  51. package/src/table.test.ts +0 -121
  52. package/src/table.ts +0 -184
  53. package/src/test-utils/test-db.ts +0 -32
  54. package/src/test-utils/test-tables.ts +0 -194
  55. package/src/test-utils/test-utils.ts +0 -119
  56. package/src/transaction.test.ts +0 -47
  57. package/src/transaction.ts +0 -27
  58. package/src/utils.ts +0 -9
  59. package/tsconfig.json +0 -14
@@ -1,1701 +0,0 @@
1
- import { db, pgConfig } from '../test-utils/test-db';
2
- import {
3
- assertType,
4
- chatData,
5
- expectSql,
6
- profileData,
7
- userData,
8
- useRelationCallback,
9
- useTestDatabase,
10
- } from '../test-utils/test-utils';
11
- import { User, Profile, BaseTable } from '../test-utils/test-tables';
12
- import { RelationQuery } from 'pqb';
13
- import { orchidORM } from '../orm';
14
-
15
- describe('hasOne', () => {
16
- useTestDatabase();
17
-
18
- describe('querying', () => {
19
- it('should have method to query related data', async () => {
20
- const profileQuery = db.profile.take();
21
-
22
- assertType<
23
- typeof db.user.profile,
24
- RelationQuery<
25
- 'profile',
26
- { id: number },
27
- 'userId',
28
- typeof profileQuery,
29
- true,
30
- true,
31
- true
32
- >
33
- >();
34
-
35
- const userId = await db.user.get('id').create(userData);
36
-
37
- await db.profile.create({ ...profileData, userId });
38
-
39
- const user = await db.user.find(userId);
40
- const query = db.user.profile(user);
41
-
42
- expectSql(
43
- query.toSql(),
44
- `
45
- SELECT * FROM "profile"
46
- WHERE "profile"."userId" = $1
47
- LIMIT $2
48
- `,
49
- [userId, 1],
50
- );
51
-
52
- const profile = await query;
53
-
54
- expect(profile).toMatchObject(profileData);
55
- });
56
-
57
- it('should handle chained query', () => {
58
- const query = db.user
59
- .where({ name: 'name' })
60
- .profile.where({ bio: 'bio' });
61
-
62
- expectSql(
63
- query.toSql(),
64
- `
65
- SELECT * FROM "profile"
66
- WHERE EXISTS (
67
- SELECT 1 FROM "user"
68
- WHERE "user"."name" = $1
69
- AND "user"."id" = "profile"."userId"
70
- LIMIT 1
71
- )
72
- AND "profile"."bio" = $2
73
- LIMIT $3
74
- `,
75
- ['name', 'bio', 1],
76
- );
77
- });
78
-
79
- it('should have create with defaults of provided id', () => {
80
- const user = { id: 1 };
81
- const now = new Date();
82
-
83
- const query = db.user.profile(user).count().create({
84
- bio: 'bio',
85
- updatedAt: now,
86
- createdAt: now,
87
- });
88
-
89
- expectSql(
90
- query.toSql(),
91
- `
92
- INSERT INTO "profile"("userId", "bio", "updatedAt", "createdAt")
93
- VALUES ($1, $2, $3, $4)
94
- `,
95
- [1, 'bio', now, now],
96
- );
97
- });
98
-
99
- it('can create after calling method', async () => {
100
- const id = await db.user.get('id').create(userData);
101
- const now = new Date();
102
- await db.user.profile({ id }).create({
103
- userId: id,
104
- bio: 'bio',
105
- updatedAt: now,
106
- createdAt: now,
107
- });
108
- });
109
-
110
- describe('chained create', () => {
111
- it('should have create based on find query', () => {
112
- const query = db.user.find(1).profile.create({
113
- bio: 'bio',
114
- });
115
-
116
- expectSql(
117
- query.toSql(),
118
- `
119
- INSERT INTO "profile"("userId", "bio")
120
- SELECT "user"."id" AS "userId", $1
121
- FROM "user"
122
- WHERE "user"."id" = $2
123
- LIMIT $3
124
- RETURNING *
125
- `,
126
- ['bio', 1, 1],
127
- );
128
- });
129
-
130
- it('should throw when the main query returns many records', async () => {
131
- await expect(
132
- async () =>
133
- await db.user.profile.create({
134
- bio: 'bio',
135
- }),
136
- ).rejects.toThrow(
137
- 'Cannot create based on a query which returns multiple records',
138
- );
139
- });
140
-
141
- it('should throw when main record is not found', async () => {
142
- await expect(
143
- async () =>
144
- await db.user.find(1).profile.create({
145
- bio: 'bio',
146
- }),
147
- ).rejects.toThrow('Record is not found');
148
- });
149
-
150
- it('should not throw when searching with findOptional', async () => {
151
- await db.user.findOptional(1).profile.takeOptional().create({
152
- bio: 'bio',
153
- });
154
- });
155
- });
156
-
157
- describe('chained delete', () => {
158
- it('should delete relation records', () => {
159
- const query = db.user
160
- .where({ name: 'name' })
161
- .profile.where({ bio: 'bio' })
162
- .delete();
163
-
164
- expectSql(
165
- query.toSql(),
166
- `
167
- DELETE FROM "profile"
168
- WHERE EXISTS (
169
- SELECT 1 FROM "user"
170
- WHERE "user"."name" = $1
171
- AND "user"."id" = "profile"."userId"
172
- LIMIT 1
173
- )
174
- AND "profile"."bio" = $2
175
- `,
176
- ['name', 'bio'],
177
- );
178
- });
179
- });
180
-
181
- it('should have proper joinQuery', () => {
182
- expectSql(
183
- db.user.relations.profile
184
- .joinQuery(db.user.as('u'), db.profile.as('p'))
185
- .toSql(),
186
- `
187
- SELECT * FROM "profile" AS "p"
188
- WHERE "p"."userId" = "u"."id"
189
- `,
190
- );
191
- });
192
-
193
- it('should be supported in whereExists', () => {
194
- expectSql(
195
- db.user.as('u').whereExists('profile').toSql(),
196
- `
197
- SELECT * FROM "user" AS "u"
198
- WHERE EXISTS (
199
- SELECT 1 FROM "profile"
200
- WHERE "profile"."userId" = "u"."id"
201
- LIMIT 1
202
- )
203
- `,
204
- );
205
-
206
- expectSql(
207
- db.user
208
- .as('u')
209
- .whereExists('profile', (q) => q.where({ bio: 'bio' }))
210
- .toSql(),
211
- `
212
- SELECT * FROM "user" AS "u"
213
- WHERE EXISTS (
214
- SELECT 1 FROM "profile"
215
- WHERE "profile"."userId" = "u"."id"
216
- AND "profile"."bio" = $1
217
- LIMIT 1
218
- )
219
- `,
220
- ['bio'],
221
- );
222
- });
223
-
224
- it('should be supported in join', () => {
225
- const query = db.user
226
- .as('u')
227
- .join('profile', (q) => q.where({ bio: 'bio' }))
228
- .select('name', 'profile.bio');
229
-
230
- assertType<
231
- Awaited<typeof query>,
232
- { name: string; bio: string | null }[]
233
- >();
234
-
235
- expectSql(
236
- query.toSql(),
237
- `
238
- SELECT "u"."name", "profile"."bio" FROM "user" AS "u"
239
- JOIN "profile"
240
- ON "profile"."userId" = "u"."id"
241
- AND "profile"."bio" = $1
242
- `,
243
- ['bio'],
244
- );
245
- });
246
-
247
- describe('select', () => {
248
- it('should be selectable', () => {
249
- const query = db.user.as('u').select('id', {
250
- profile: (q) => q.profile.where({ bio: 'bio' }),
251
- });
252
-
253
- assertType<Awaited<typeof query>, { id: number; profile: Profile }[]>();
254
-
255
- expectSql(
256
- query.toSql(),
257
- `
258
- SELECT
259
- "u"."id",
260
- (
261
- SELECT row_to_json("t".*)
262
- FROM (
263
- SELECT * FROM "profile"
264
- WHERE "profile"."bio" = $1
265
- AND "profile"."userId" = "u"."id"
266
- LIMIT $2
267
- ) AS "t"
268
- ) AS "profile"
269
- FROM "user" AS "u"
270
- `,
271
- ['bio', 1],
272
- );
273
- });
274
-
275
- it('should be selectable by relation name', () => {
276
- const query = db.user.select('id', 'profile');
277
-
278
- assertType<Awaited<typeof query>, { id: number; profile: Profile }[]>();
279
-
280
- expectSql(
281
- query.toSql(),
282
- `
283
- SELECT
284
- "user"."id",
285
- (
286
- SELECT row_to_json("t".*)
287
- FROM (
288
- SELECT * FROM "profile"
289
- WHERE "profile"."userId" = "user"."id"
290
- LIMIT $1
291
- ) AS "t"
292
- ) AS "profile"
293
- FROM "user"
294
- `,
295
- [1],
296
- );
297
- });
298
-
299
- it('should handle exists sub query', () => {
300
- const query = db.user.as('u').select('id', {
301
- hasProfile: (q) => q.profile.exists(),
302
- });
303
-
304
- assertType<
305
- Awaited<typeof query>,
306
- { id: number; hasProfile: boolean }[]
307
- >();
308
-
309
- expectSql(
310
- query.toSql(),
311
- `
312
- SELECT
313
- "u"."id",
314
- COALESCE((
315
- SELECT true
316
- FROM "profile"
317
- WHERE "profile"."userId" = "u"."id"
318
- ), false) AS "hasProfile"
319
- FROM "user" AS "u"
320
- `,
321
- );
322
- });
323
- });
324
-
325
- describe('create', () => {
326
- const checkUserAndProfile = ({
327
- user,
328
- profile,
329
- name,
330
- bio,
331
- }: {
332
- user: User;
333
- profile: Profile;
334
- name: string;
335
- bio: string;
336
- }) => {
337
- expect(user).toEqual({
338
- ...userData,
339
- id: user.id,
340
- name,
341
- active: null,
342
- age: null,
343
- data: null,
344
- picture: null,
345
- });
346
-
347
- expect(profile).toMatchObject({
348
- id: profile.id,
349
- bio,
350
- userId: user.id,
351
- });
352
- };
353
-
354
- describe('nested create', () => {
355
- it('should support create', async () => {
356
- const query = db.user.create({
357
- ...userData,
358
- name: 'user',
359
- profile: {
360
- create: {
361
- ...profileData,
362
- bio: 'profile',
363
- },
364
- },
365
- });
366
-
367
- const user = await query;
368
- const profile = await db.profile.findBy({ userId: user.id });
369
-
370
- checkUserAndProfile({ user, profile, name: 'user', bio: 'profile' });
371
- });
372
-
373
- it('should support create many', async () => {
374
- const query = db.user.createMany([
375
- {
376
- ...userData,
377
- name: 'user 1',
378
- profile: {
379
- create: {
380
- ...profileData,
381
- bio: 'profile 1',
382
- },
383
- },
384
- },
385
- {
386
- ...userData,
387
- name: 'user 2',
388
- profile: {
389
- create: {
390
- ...profileData,
391
- bio: 'profile 2',
392
- },
393
- },
394
- },
395
- ]);
396
-
397
- const users = await query;
398
- const profiles = await db.profile
399
- .where({
400
- userId: { in: users.map((user) => user.id) },
401
- })
402
- .order('id');
403
-
404
- checkUserAndProfile({
405
- user: users[0],
406
- profile: profiles[0],
407
- name: 'user 1',
408
- bio: 'profile 1',
409
- });
410
-
411
- checkUserAndProfile({
412
- user: users[1],
413
- profile: profiles[1],
414
- name: 'user 2',
415
- bio: 'profile 2',
416
- });
417
- });
418
-
419
- describe('relation callbacks', () => {
420
- const { beforeCreate, afterCreate, resetMocks } = useRelationCallback(
421
- db.user.relations.profile,
422
- );
423
-
424
- it('should invoke callbacks', async () => {
425
- await db.user.create({
426
- ...userData,
427
- profile: {
428
- create: profileData,
429
- },
430
- });
431
-
432
- expect(beforeCreate).toHaveBeenCalledTimes(1);
433
- expect(afterCreate).toHaveBeenCalledTimes(1);
434
- });
435
-
436
- it('should invoke callbacks in a batch create', async () => {
437
- resetMocks();
438
-
439
- await db.user.createMany([
440
- {
441
- ...userData,
442
- profile: {
443
- create: profileData,
444
- },
445
- },
446
- {
447
- ...userData,
448
- profile: {
449
- create: profileData,
450
- },
451
- },
452
- ]);
453
-
454
- expect(beforeCreate).toHaveBeenCalledTimes(1);
455
- expect(afterCreate).toHaveBeenCalledTimes(1);
456
- });
457
- });
458
- });
459
-
460
- describe('nested connect', () => {
461
- it('should support connect', async () => {
462
- await db.profile.create({
463
- ...profileData,
464
- bio: 'profile',
465
- user: {
466
- create: {
467
- ...userData,
468
- name: 'tmp',
469
- },
470
- },
471
- });
472
-
473
- const query = db.user.create({
474
- ...userData,
475
- name: 'user',
476
- profile: {
477
- connect: { bio: 'profile' },
478
- },
479
- });
480
-
481
- const user = await query;
482
- const profile = await db.user.profile(user);
483
-
484
- checkUserAndProfile({ user, profile, name: 'user', bio: 'profile' });
485
- });
486
-
487
- it('should support connect many', async () => {
488
- await db.profile.createMany([
489
- {
490
- ...profileData,
491
- bio: 'profile 1',
492
- user: {
493
- create: {
494
- ...userData,
495
- name: 'tmp',
496
- },
497
- },
498
- },
499
- {
500
- ...profileData,
501
- bio: 'profile 2',
502
- user: {
503
- connect: { name: 'tmp' },
504
- },
505
- },
506
- ]);
507
-
508
- const query = db.user.createMany([
509
- {
510
- ...userData,
511
- name: 'user 1',
512
- profile: {
513
- connect: { bio: 'profile 1' },
514
- },
515
- },
516
- {
517
- ...userData,
518
- name: 'user 2',
519
- profile: {
520
- connect: { bio: 'profile 2' },
521
- },
522
- },
523
- ]);
524
-
525
- const users = await query;
526
- const profiles = await db.profile
527
- .where({
528
- userId: { in: users.map((user) => user.id) },
529
- })
530
- .order('id');
531
-
532
- checkUserAndProfile({
533
- user: users[0],
534
- profile: profiles[0],
535
- name: 'user 1',
536
- bio: 'profile 1',
537
- });
538
-
539
- checkUserAndProfile({
540
- user: users[1],
541
- profile: profiles[1],
542
- name: 'user 2',
543
- bio: 'profile 2',
544
- });
545
- });
546
-
547
- describe('relation callbacks', () => {
548
- const { beforeUpdate, afterUpdate, resetMocks } = useRelationCallback(
549
- db.user.relations.profile,
550
- );
551
-
552
- it('should invoke callbacks', async () => {
553
- const profileId = await db.profile.get('id').create(profileData);
554
-
555
- await db.user.create({
556
- ...userData,
557
- profile: {
558
- connect: { id: profileId },
559
- },
560
- });
561
-
562
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
563
- expect(afterUpdate).toHaveBeenCalledTimes(1);
564
- });
565
-
566
- it('should invoke callbacks in a batch create', async () => {
567
- resetMocks();
568
-
569
- const ids = await db.profile
570
- .pluck('id')
571
- .createMany([profileData, profileData]);
572
-
573
- await db.user.createMany([
574
- {
575
- ...userData,
576
- profile: {
577
- connect: { id: ids[0] },
578
- },
579
- },
580
- {
581
- ...userData,
582
- profile: {
583
- connect: { id: ids[1] },
584
- },
585
- },
586
- ]);
587
-
588
- expect(beforeUpdate).toHaveBeenCalledTimes(2);
589
- expect(afterUpdate).toHaveBeenCalledTimes(2);
590
- });
591
- });
592
- });
593
-
594
- describe('connect or create', () => {
595
- it('should support connect or create', async () => {
596
- const profileId = await db.profile.get('id').create({
597
- ...profileData,
598
- bio: 'profile 1',
599
- user: {
600
- create: {
601
- ...userData,
602
- name: 'tmp',
603
- },
604
- },
605
- });
606
-
607
- const user1 = await db.user.create({
608
- ...userData,
609
- name: 'user 1',
610
- profile: {
611
- connectOrCreate: {
612
- where: { bio: 'profile 1' },
613
- create: { ...profileData, bio: 'profile 1' },
614
- },
615
- },
616
- });
617
-
618
- const user2 = await db.user.create({
619
- ...userData,
620
- name: 'user 2',
621
- profile: {
622
- connectOrCreate: {
623
- where: { bio: 'profile 2' },
624
- create: { ...profileData, bio: 'profile 2' },
625
- },
626
- },
627
- });
628
-
629
- const profile1 = await db.user.profile(user1);
630
- expect(profile1.id).toBe(profileId);
631
- checkUserAndProfile({
632
- user: user1,
633
- profile: profile1,
634
- name: 'user 1',
635
- bio: 'profile 1',
636
- });
637
-
638
- const profile2 = await db.user.profile(user2);
639
- checkUserAndProfile({
640
- user: user2,
641
- profile: profile2,
642
- name: 'user 2',
643
- bio: 'profile 2',
644
- });
645
- });
646
-
647
- it('should support connect or create many', async () => {
648
- const profileId = await db.profile.get('id').create({
649
- ...profileData,
650
- bio: 'profile 1',
651
- user: {
652
- create: {
653
- ...userData,
654
- name: 'tmp',
655
- },
656
- },
657
- });
658
-
659
- const [user1, user2] = await db.user.createMany([
660
- {
661
- ...userData,
662
- name: 'user 1',
663
- profile: {
664
- connectOrCreate: {
665
- where: { bio: 'profile 1' },
666
- create: { ...profileData, bio: 'profile 1' },
667
- },
668
- },
669
- },
670
- {
671
- ...userData,
672
- name: 'user 2',
673
- profile: {
674
- connectOrCreate: {
675
- where: { bio: 'profile 2' },
676
- create: { ...profileData, bio: 'profile 2' },
677
- },
678
- },
679
- },
680
- ]);
681
-
682
- const profile1 = await db.user.profile(user1);
683
- expect(profile1.id).toBe(profileId);
684
- checkUserAndProfile({
685
- user: user1,
686
- profile: profile1,
687
- name: 'user 1',
688
- bio: 'profile 1',
689
- });
690
-
691
- const profile2 = await db.user.profile(user2);
692
- checkUserAndProfile({
693
- user: user2,
694
- profile: profile2,
695
- name: 'user 2',
696
- bio: 'profile 2',
697
- });
698
- });
699
- });
700
-
701
- describe('relation callbacks', () => {
702
- const {
703
- beforeUpdate,
704
- afterUpdate,
705
- beforeCreate,
706
- afterCreate,
707
- resetMocks,
708
- } = useRelationCallback(db.user.relations.profile);
709
-
710
- it('should invoke callbacks when connecting', async () => {
711
- const id = await db.profile.get('id').create(profileData);
712
-
713
- await db.user.create({
714
- ...userData,
715
- profile: {
716
- connectOrCreate: {
717
- where: { id },
718
- create: profileData,
719
- },
720
- },
721
- });
722
-
723
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
724
- expect(afterUpdate).toHaveBeenCalledTimes(1);
725
- });
726
-
727
- it('should invoke callbacks when creating', async () => {
728
- await db.user.create({
729
- ...userData,
730
- profile: {
731
- connectOrCreate: {
732
- where: { id: 0 },
733
- create: profileData,
734
- },
735
- },
736
- });
737
-
738
- expect(beforeCreate).toHaveBeenCalledTimes(1);
739
- expect(afterCreate).toHaveBeenCalledTimes(1);
740
- });
741
-
742
- it('should invoke callbacks in a batch create', async () => {
743
- resetMocks();
744
-
745
- const id = await db.profile.get('id').create(profileData);
746
-
747
- await db.user.createMany([
748
- {
749
- ...userData,
750
- profile: {
751
- connectOrCreate: {
752
- where: { id: 0 },
753
- create: profileData,
754
- },
755
- },
756
- },
757
- {
758
- ...userData,
759
- profile: {
760
- connectOrCreate: {
761
- where: { id },
762
- create: profileData,
763
- },
764
- },
765
- },
766
- ]);
767
-
768
- expect(beforeUpdate).toHaveBeenCalledTimes(2);
769
- expect(afterUpdate).toHaveBeenCalledTimes(2);
770
- expect(beforeCreate).toHaveBeenCalledTimes(1);
771
- expect(afterCreate).toHaveBeenCalledTimes(1);
772
- });
773
- });
774
- });
775
-
776
- describe('update', () => {
777
- describe('disconnect', () => {
778
- it('should nullify foreignKey', async () => {
779
- const user = await db.user
780
- .selectAll()
781
- .create({ ...userData, profile: { create: profileData } });
782
- const { id: profileId } = await db.user.profile(user);
783
-
784
- const id = await db.user
785
- .get('id')
786
- .where(user)
787
- .update({
788
- profile: {
789
- disconnect: true,
790
- },
791
- });
792
-
793
- expect(id).toBe(user.id);
794
-
795
- const profile = await db.profile.find(profileId);
796
- expect(profile.userId).toBe(null);
797
- });
798
-
799
- it('should nullify foreignKey in batch update', async () => {
800
- const userIds = await db.user.pluck('id').createMany([
801
- { ...userData, profile: { create: profileData } },
802
- { ...userData, profile: { create: profileData } },
803
- ]);
804
-
805
- const profileIds = await db.profile.pluck('id').where({
806
- userId: { in: userIds },
807
- });
808
-
809
- await db.user.where({ id: { in: userIds } }).update({
810
- profile: {
811
- disconnect: true,
812
- },
813
- });
814
-
815
- const updatedUserIds = await db.profile
816
- .pluck('userId')
817
- .where({ id: { in: profileIds } });
818
- expect(updatedUserIds).toEqual([null, null]);
819
- });
820
-
821
- describe('relation callbacks', () => {
822
- const { beforeUpdate, afterUpdate, resetMocks } = useRelationCallback(
823
- db.user.relations.profile,
824
- );
825
-
826
- it('should invoke callbacks', async () => {
827
- const id = await db.user.get('id').create({
828
- ...userData,
829
- profile: { create: profileData },
830
- });
831
-
832
- await db.user.find(id).update({
833
- profile: {
834
- disconnect: true,
835
- },
836
- });
837
-
838
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
839
- expect(afterUpdate).toHaveBeenCalledTimes(1);
840
- });
841
-
842
- it('should invoke callbacks in a batch update', async () => {
843
- resetMocks();
844
-
845
- const ids = await db.user.pluck('id').createMany([
846
- {
847
- ...userData,
848
- profile: { create: profileData },
849
- },
850
- {
851
- ...userData,
852
- profile: { create: profileData },
853
- },
854
- ]);
855
-
856
- await db.user.where({ id: { in: ids } }).update({
857
- profile: {
858
- disconnect: true,
859
- },
860
- });
861
-
862
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
863
- expect(afterUpdate).toHaveBeenCalledTimes(1);
864
- });
865
- });
866
- });
867
-
868
- describe('set', () => {
869
- it('should nullify foreignKey of previous related record and set foreignKey to new related record', async () => {
870
- const id = await db.user.get('id').create(userData);
871
-
872
- const [{ id: profile1Id }, { id: profile2Id }] = await db.profile
873
- .select('id')
874
- .createMany([{ ...profileData, userId: id }, { ...profileData }]);
875
-
876
- await db.user.find(id).update({
877
- profile: {
878
- set: { id: profile2Id },
879
- },
880
- });
881
-
882
- const profile1 = await db.profile.find(profile1Id);
883
- expect(profile1.userId).toBe(null);
884
-
885
- const profile2 = await db.profile.find(profile2Id);
886
- expect(profile2.userId).toBe(id);
887
- });
888
-
889
- it('should throw in batch update', async () => {
890
- const query = db.user.where({ id: { in: [1, 2, 3] } }).update({
891
- profile: {
892
- // @ts-expect-error not allows in batch update
893
- set: { id: 1 },
894
- },
895
- });
896
-
897
- await expect(query).rejects.toThrow();
898
- });
899
-
900
- describe('relation callbacks', () => {
901
- const { beforeUpdate, afterUpdate } = useRelationCallback(
902
- db.user.relations.profile,
903
- );
904
-
905
- it('should invoke callbacks', async () => {
906
- const userId = await db.user
907
- .get('id')
908
- .create({ ...userData, profile: { create: profileData } });
909
- const profileId = await db.profile.get('id').create(profileData);
910
-
911
- await db.user.find(userId).update({
912
- profile: {
913
- set: { id: profileId },
914
- },
915
- });
916
-
917
- expect(beforeUpdate).toHaveBeenCalledTimes(2);
918
- expect(afterUpdate).toHaveBeenCalledTimes(2);
919
- });
920
- });
921
- });
922
-
923
- describe('delete', () => {
924
- it('should delete related record', async () => {
925
- const id = await db.user
926
- .get('id')
927
- .create({ ...userData, profile: { create: profileData } });
928
-
929
- const { id: profileId } = await db.user
930
- .profile({ id })
931
- .select('id')
932
- .take();
933
-
934
- await db.user.find(id).update({
935
- profile: {
936
- delete: true,
937
- },
938
- });
939
-
940
- const profile = await db.profile.findByOptional({ id: profileId });
941
- expect(profile).toBe(undefined);
942
- });
943
-
944
- it('should delete related record in batch update', async () => {
945
- const userIds = await db.user.pluck('id').createMany([
946
- { ...userData, profile: { create: profileData } },
947
- { ...userData, profile: { create: profileData } },
948
- ]);
949
-
950
- await db.user.where({ id: { in: userIds } }).update({
951
- profile: {
952
- delete: true,
953
- },
954
- });
955
-
956
- const count = await db.profile.count();
957
- expect(count).toBe(0);
958
- });
959
-
960
- describe('relation callbacks', () => {
961
- const { beforeDelete, afterDelete, resetMocks } = useRelationCallback(
962
- db.user.relations.profile,
963
- );
964
-
965
- it('should invoke callbacks', async () => {
966
- const id = await db.user
967
- .get('id')
968
- .create({ ...userData, profile: { create: profileData } });
969
-
970
- await db.user.find(id).update({
971
- profile: {
972
- delete: true,
973
- },
974
- });
975
-
976
- expect(beforeDelete).toHaveBeenCalledTimes(1);
977
- expect(afterDelete).toHaveBeenCalledTimes(1);
978
- });
979
-
980
- it('should invoke callbacks in a batch update', async () => {
981
- resetMocks();
982
-
983
- const ids = await db.user.pluck('id').createMany([
984
- { ...userData, profile: { create: profileData } },
985
- { ...userData, profile: { create: profileData } },
986
- ]);
987
-
988
- await db.user.where({ id: { in: ids } }).update({
989
- profile: {
990
- delete: true,
991
- },
992
- });
993
-
994
- expect(beforeDelete).toHaveBeenCalledTimes(1);
995
- expect(afterDelete).toHaveBeenCalledTimes(1);
996
- });
997
- });
998
- });
999
-
1000
- describe('nested update', () => {
1001
- it('should update related record', async () => {
1002
- const id = await db.user
1003
- .get('id')
1004
- .create({ ...userData, profile: { create: profileData } });
1005
-
1006
- await db.user.find(id).update({
1007
- profile: {
1008
- update: {
1009
- bio: 'updated',
1010
- },
1011
- },
1012
- });
1013
-
1014
- const profile = await db.user.profile({ id }).take();
1015
- expect(profile.bio).toBe('updated');
1016
- });
1017
-
1018
- it('should update related record in batch update', async () => {
1019
- const userIds = await db.user.pluck('id').createMany([
1020
- { ...userData, profile: { create: profileData } },
1021
- { ...userData, profile: { create: profileData } },
1022
- ]);
1023
-
1024
- await db.user.where({ id: { in: userIds } }).update({
1025
- profile: {
1026
- update: {
1027
- bio: 'updated',
1028
- },
1029
- },
1030
- });
1031
-
1032
- const bios = await db.profile.pluck('bio');
1033
- expect(bios).toEqual(['updated', 'updated']);
1034
- });
1035
-
1036
- describe('relation callbacks', () => {
1037
- const { beforeUpdate, afterUpdate, resetMocks } = useRelationCallback(
1038
- db.user.relations.profile,
1039
- );
1040
-
1041
- it('should invoke callbacks', async () => {
1042
- const id = await db.user
1043
- .get('id')
1044
- .create({ ...userData, profile: { create: profileData } });
1045
-
1046
- await db.user.find(id).update({
1047
- profile: {
1048
- update: {
1049
- bio: 'updated',
1050
- },
1051
- },
1052
- });
1053
-
1054
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
1055
- expect(afterUpdate).toHaveBeenCalledTimes(1);
1056
- });
1057
-
1058
- it('should invoke callbacks in a batch update', async () => {
1059
- resetMocks();
1060
-
1061
- const ids = await db.user.pluck('id').createMany([
1062
- { ...userData, profile: { create: profileData } },
1063
- { ...userData, profile: { create: profileData } },
1064
- ]);
1065
-
1066
- await db.user.where({ id: { in: ids } }).update({
1067
- profile: {
1068
- update: {
1069
- bio: 'updated',
1070
- },
1071
- },
1072
- });
1073
-
1074
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
1075
- expect(afterUpdate).toHaveBeenCalledTimes(1);
1076
- });
1077
- });
1078
- });
1079
-
1080
- describe('nested upsert', () => {
1081
- it('should update related record if it exists', async () => {
1082
- const user = await db.user.create({
1083
- ...userData,
1084
- profile: { create: profileData },
1085
- });
1086
-
1087
- await db.user.find(user.id).update({
1088
- profile: {
1089
- upsert: {
1090
- update: {
1091
- bio: 'updated',
1092
- },
1093
- create: profileData,
1094
- },
1095
- },
1096
- });
1097
-
1098
- const profile = await db.user.profile(user);
1099
- expect(profile.bio).toBe('updated');
1100
- });
1101
-
1102
- it('should create related record if it does not exists', async () => {
1103
- const user = await db.user.create(userData);
1104
-
1105
- await db.user.find(user.id).update({
1106
- profile: {
1107
- upsert: {
1108
- update: {
1109
- bio: 'updated',
1110
- },
1111
- create: {
1112
- ...profileData,
1113
- bio: 'created',
1114
- },
1115
- },
1116
- },
1117
- });
1118
-
1119
- const profile = await db.user.profile(user);
1120
- expect(profile.bio).toBe('created');
1121
- });
1122
-
1123
- it('should throw in batch update', async () => {
1124
- const query = db.user.where({ id: { in: [1, 2, 3] } }).update({
1125
- profile: {
1126
- // @ts-expect-error not allows in batch update
1127
- upsert: {
1128
- update: {
1129
- bio: 'updated',
1130
- },
1131
- create: {
1132
- ...profileData,
1133
- bio: 'created',
1134
- },
1135
- },
1136
- },
1137
- });
1138
-
1139
- await expect(query).rejects.toThrow();
1140
- });
1141
-
1142
- describe('relation callbacks', () => {
1143
- const {
1144
- beforeUpdate,
1145
- afterUpdate,
1146
- beforeCreate,
1147
- afterCreate,
1148
- resetMocks,
1149
- } = useRelationCallback(db.user.relations.profile);
1150
-
1151
- it('should invoke callbacks when connecting', async () => {
1152
- const userId = await db.user
1153
- .get('id')
1154
- .create({ ...userData, profile: { create: profileData } });
1155
-
1156
- await db.user.find(userId).update({
1157
- profile: {
1158
- upsert: {
1159
- update: {
1160
- bio: 'updated',
1161
- },
1162
- create: profileData,
1163
- },
1164
- },
1165
- });
1166
-
1167
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
1168
- expect(afterUpdate).toHaveBeenCalledTimes(1);
1169
- });
1170
-
1171
- it('should invoke callbacks when creating', async () => {
1172
- resetMocks();
1173
-
1174
- const userId = await db.user.get('id').create(userData);
1175
-
1176
- await db.user.find(userId).update({
1177
- profile: {
1178
- upsert: {
1179
- update: {
1180
- bio: 'updated',
1181
- },
1182
- create: profileData,
1183
- },
1184
- },
1185
- });
1186
-
1187
- expect(beforeCreate).toHaveBeenCalledTimes(1);
1188
- expect(afterCreate).toHaveBeenCalledTimes(1);
1189
- });
1190
- });
1191
- });
1192
-
1193
- describe('nested create', () => {
1194
- it('should create new related record', async () => {
1195
- const userId = await db.user
1196
- .get('id')
1197
- .create({ ...userData, profile: { create: profileData } });
1198
-
1199
- const previousProfileId = await db.user
1200
- .profile({ id: userId })
1201
- .get('id');
1202
-
1203
- const updated = await db.user
1204
- .selectAll()
1205
- .find(userId)
1206
- .update({
1207
- profile: {
1208
- create: { ...profileData, bio: 'created' },
1209
- },
1210
- });
1211
-
1212
- const previousProfile = await db.profile.find(previousProfileId);
1213
- expect(previousProfile.userId).toBe(null);
1214
-
1215
- const profile = await db.user.profile(updated);
1216
- expect(profile.bio).toBe('created');
1217
- });
1218
-
1219
- it('should throw in batch update', async () => {
1220
- const query = db.user.where({ id: { in: [1, 2, 3] } }).update({
1221
- profile: {
1222
- // @ts-expect-error not allows in batch update
1223
- create: {
1224
- ...profileData,
1225
- bio: 'created',
1226
- },
1227
- },
1228
- });
1229
-
1230
- await expect(query).rejects.toThrow();
1231
- });
1232
-
1233
- describe('relation callbacks', () => {
1234
- const {
1235
- beforeUpdate,
1236
- afterUpdate,
1237
- beforeCreate,
1238
- afterCreate,
1239
- resetMocks,
1240
- } = useRelationCallback(db.user.relations.profile);
1241
-
1242
- it('should invoke callbacks to disconnect previous and create new', async () => {
1243
- const id = await db.user
1244
- .get('id')
1245
- .create({ ...userData, profile: { create: profileData } });
1246
-
1247
- resetMocks();
1248
-
1249
- await db.user.find(id).update({
1250
- profile: {
1251
- create: profileData,
1252
- },
1253
- });
1254
-
1255
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
1256
- expect(afterUpdate).toHaveBeenCalledTimes(1);
1257
- expect(beforeCreate).toHaveBeenCalledTimes(1);
1258
- expect(afterCreate).toHaveBeenCalledTimes(1);
1259
- });
1260
- });
1261
- });
1262
- });
1263
- });
1264
- });
1265
-
1266
- describe('hasOne through', () => {
1267
- it('should resolve recursive situation when both tables depends on each other', () => {
1268
- class Post extends BaseTable {
1269
- table = 'post';
1270
- columns = this.setColumns((t) => ({
1271
- id: t.serial().primaryKey(),
1272
- }));
1273
-
1274
- relations = {
1275
- postTag: this.hasOne(() => PostTag, {
1276
- primaryKey: 'id',
1277
- foreignKey: 'postId',
1278
- }),
1279
-
1280
- tag: this.hasOne(() => Tag, {
1281
- through: 'postTag',
1282
- source: 'tag',
1283
- }),
1284
- };
1285
- }
1286
-
1287
- class Tag extends BaseTable {
1288
- table = 'tag';
1289
- columns = this.setColumns((t) => ({
1290
- id: t.serial().primaryKey(),
1291
- }));
1292
-
1293
- relations = {
1294
- postTag: this.hasOne(() => PostTag, {
1295
- primaryKey: 'id',
1296
- foreignKey: 'postId',
1297
- }),
1298
-
1299
- post: this.hasOne(() => Post, {
1300
- through: 'postTag',
1301
- source: 'post',
1302
- }),
1303
- };
1304
- }
1305
-
1306
- class PostTag extends BaseTable {
1307
- table = 'postTag';
1308
- columns = this.setColumns((t) => ({
1309
- postId: t.integer().foreignKey(() => Post, 'id'),
1310
- tagId: t.integer().foreignKey(() => Tag, 'id'),
1311
- ...t.primaryKey(['postId', 'tagId']),
1312
- }));
1313
-
1314
- relations = {
1315
- post: this.belongsTo(() => Post, {
1316
- primaryKey: 'id',
1317
- foreignKey: 'postId',
1318
- }),
1319
-
1320
- tag: this.belongsTo(() => Tag, {
1321
- primaryKey: 'id',
1322
- foreignKey: 'tagId',
1323
- }),
1324
- };
1325
- }
1326
-
1327
- const db = orchidORM(
1328
- {
1329
- ...pgConfig,
1330
- log: false,
1331
- },
1332
- {
1333
- post: Post,
1334
- tag: Tag,
1335
- postTag: PostTag,
1336
- },
1337
- );
1338
-
1339
- expect(Object.keys(db.post.relations)).toEqual(['postTag', 'tag']);
1340
- expect(Object.keys(db.tag.relations)).toEqual(['postTag', 'post']);
1341
- });
1342
-
1343
- it('should throw if through relation is not defined', () => {
1344
- class Post extends BaseTable {
1345
- table = 'post';
1346
- columns = this.setColumns((t) => ({
1347
- id: t.serial().primaryKey(),
1348
- }));
1349
-
1350
- relations = {
1351
- tag: this.hasOne(() => Tag, {
1352
- through: 'postTag',
1353
- source: 'tag',
1354
- }),
1355
- };
1356
- }
1357
-
1358
- class Tag extends BaseTable {
1359
- table = 'tag';
1360
- columns = this.setColumns((t) => ({
1361
- id: t.serial().primaryKey(),
1362
- }));
1363
- }
1364
-
1365
- expect(() => {
1366
- orchidORM(
1367
- {
1368
- ...pgConfig,
1369
- log: false,
1370
- },
1371
- {
1372
- post: Post,
1373
- tag: Tag,
1374
- },
1375
- );
1376
- }).toThrow(
1377
- 'Cannot define a `tag` relation on `post`: cannot find `postTag` relation required by the `through` option',
1378
- );
1379
- });
1380
-
1381
- it('should throw if source relation is not defined', () => {
1382
- class Post extends BaseTable {
1383
- table = 'post';
1384
- columns = this.setColumns((t) => ({
1385
- id: t.serial().primaryKey(),
1386
- }));
1387
-
1388
- relations = {
1389
- postTag: this.hasOne(() => PostTag, {
1390
- primaryKey: 'id',
1391
- foreignKey: 'postId',
1392
- }),
1393
-
1394
- tag: this.hasOne(() => Tag, {
1395
- through: 'postTag',
1396
- source: 'tag',
1397
- }),
1398
- };
1399
- }
1400
-
1401
- class Tag extends BaseTable {
1402
- table = 'tag';
1403
- columns = this.setColumns((t) => ({
1404
- id: t.serial().primaryKey(),
1405
- }));
1406
- }
1407
-
1408
- class PostTag extends BaseTable {
1409
- table = 'postTag';
1410
- columns = this.setColumns((t) => ({
1411
- postId: t.integer().foreignKey(() => Post, 'id'),
1412
- tagId: t.integer().foreignKey(() => Tag, 'id'),
1413
- ...t.primaryKey(['postId', 'tagId']),
1414
- }));
1415
- }
1416
-
1417
- expect(() => {
1418
- orchidORM(
1419
- {
1420
- ...pgConfig,
1421
- log: false,
1422
- },
1423
- {
1424
- post: Post,
1425
- tag: Tag,
1426
- postTag: PostTag,
1427
- },
1428
- );
1429
- }).toThrow(
1430
- 'Cannot define a `tag` relation on `post`: cannot find `tag` relation in `postTag` required by the `source` option',
1431
- );
1432
- });
1433
-
1434
- it('should have method to query related data', async () => {
1435
- const profileQuery = db.profile.take();
1436
-
1437
- assertType<
1438
- typeof db.message.profile,
1439
- RelationQuery<
1440
- 'profile',
1441
- { authorId: number | null },
1442
- never,
1443
- typeof profileQuery,
1444
- true,
1445
- false,
1446
- true
1447
- >
1448
- >();
1449
-
1450
- const query = db.message.profile({ authorId: 1 });
1451
- expectSql(
1452
- query.toSql(),
1453
- `
1454
- SELECT * FROM "profile"
1455
- WHERE EXISTS (
1456
- SELECT 1 FROM "user"
1457
- WHERE "profile"."userId" = "user"."id"
1458
- AND "user"."id" = $1
1459
- LIMIT 1
1460
- )
1461
- LIMIT $2
1462
- `,
1463
- [1, 1],
1464
- );
1465
- });
1466
-
1467
- it('should handle chained query', () => {
1468
- const query = db.message
1469
- .where({ text: 'text' })
1470
- .profile.where({ bio: 'bio' });
1471
-
1472
- expectSql(
1473
- query.toSql(),
1474
- `
1475
- SELECT * FROM "profile"
1476
- WHERE EXISTS (
1477
- SELECT 1 FROM "message"
1478
- WHERE "message"."text" = $1
1479
- AND EXISTS (
1480
- SELECT 1 FROM "user"
1481
- WHERE "profile"."userId" = "user"."id"
1482
- AND "user"."id" = "message"."authorId"
1483
- LIMIT 1
1484
- )
1485
- LIMIT 1
1486
- )
1487
- AND "profile"."bio" = $2
1488
- LIMIT $3
1489
- `,
1490
- ['text', 'bio', 1],
1491
- );
1492
- });
1493
-
1494
- it('should have disabled create method', () => {
1495
- // @ts-expect-error hasOne with through option should not have chained create
1496
- db.message.profile.create(chatData);
1497
- });
1498
-
1499
- it('should have chained delete method', () => {
1500
- const query = db.message
1501
- .where({ text: 'text' })
1502
- .profile.where({ bio: 'bio' })
1503
- .delete();
1504
-
1505
- expectSql(
1506
- query.toSql(),
1507
- `
1508
- DELETE FROM "profile"
1509
- WHERE EXISTS (
1510
- SELECT 1 FROM "message"
1511
- WHERE "message"."text" = $1
1512
- AND EXISTS (
1513
- SELECT 1 FROM "user"
1514
- WHERE "profile"."userId" = "user"."id"
1515
- AND "user"."id" = "message"."authorId"
1516
- LIMIT 1
1517
- )
1518
- LIMIT 1
1519
- )
1520
- AND "profile"."bio" = $2
1521
- `,
1522
- ['text', 'bio'],
1523
- );
1524
- });
1525
-
1526
- it('should have proper joinQuery', () => {
1527
- expectSql(
1528
- db.message.relations.profile
1529
- .joinQuery(db.message.as('m'), db.profile.as('p'))
1530
- .toSql(),
1531
- `
1532
- SELECT * FROM "profile" AS "p"
1533
- WHERE EXISTS (
1534
- SELECT 1 FROM "user"
1535
- WHERE "p"."userId" = "user"."id"
1536
- AND "user"."id" = "m"."authorId"
1537
- LIMIT 1
1538
- )
1539
- `,
1540
- );
1541
- });
1542
-
1543
- it('should be supported in whereExists', () => {
1544
- expectSql(
1545
- db.message.whereExists('profile').toSql(),
1546
- `
1547
- SELECT * FROM "message"
1548
- WHERE EXISTS (
1549
- SELECT 1 FROM "profile"
1550
- WHERE EXISTS (
1551
- SELECT 1 FROM "user"
1552
- WHERE "profile"."userId" = "user"."id"
1553
- AND "user"."id" = "message"."authorId"
1554
- LIMIT 1
1555
- )
1556
- LIMIT 1
1557
- )
1558
- `,
1559
- );
1560
-
1561
- expectSql(
1562
- db.message
1563
- .as('m')
1564
- .whereExists('profile', (q) => q.where({ bio: 'bio' }))
1565
- .toSql(),
1566
- `
1567
- SELECT * FROM "message" AS "m"
1568
- WHERE EXISTS (
1569
- SELECT 1 FROM "profile"
1570
- WHERE EXISTS (
1571
- SELECT 1 FROM "user"
1572
- WHERE "profile"."userId" = "user"."id"
1573
- AND "user"."id" = "m"."authorId"
1574
- LIMIT 1
1575
- )
1576
- AND "profile"."bio" = $1
1577
- LIMIT 1
1578
- )
1579
- `,
1580
- ['bio'],
1581
- );
1582
- });
1583
-
1584
- it('should be supported in join', () => {
1585
- const query = db.message
1586
- .as('m')
1587
- .join('profile', (q) => q.where({ bio: 'bio' }))
1588
- .select('text', 'profile.bio');
1589
-
1590
- assertType<Awaited<typeof query>, { text: string; bio: string | null }[]>();
1591
-
1592
- expectSql(
1593
- query.toSql(),
1594
- `
1595
- SELECT "m"."text", "profile"."bio" FROM "message" AS "m"
1596
- JOIN "profile"
1597
- ON EXISTS (
1598
- SELECT 1 FROM "user"
1599
- WHERE "profile"."userId" = "user"."id"
1600
- AND "user"."id" = "m"."authorId"
1601
- LIMIT 1
1602
- )
1603
- AND "profile"."bio" = $1
1604
- `,
1605
- ['bio'],
1606
- );
1607
- });
1608
-
1609
- describe('select', () => {
1610
- it('should be selectable', () => {
1611
- const query = db.message.as('m').select('id', {
1612
- profile: (q) => q.profile.where({ bio: 'bio' }),
1613
- });
1614
-
1615
- assertType<Awaited<typeof query>, { id: number; profile: Profile }[]>();
1616
-
1617
- expectSql(
1618
- query.toSql(),
1619
- `
1620
- SELECT
1621
- "m"."id",
1622
- (
1623
- SELECT row_to_json("t".*)
1624
- FROM (
1625
- SELECT * FROM "profile"
1626
- WHERE "profile"."bio" = $1
1627
- AND EXISTS (
1628
- SELECT 1 FROM "user"
1629
- WHERE "profile"."userId" = "user"."id"
1630
- AND "user"."id" = "m"."authorId"
1631
- LIMIT 1
1632
- )
1633
- LIMIT $2
1634
- ) AS "t"
1635
- ) AS "profile"
1636
- FROM "message" AS "m"
1637
- `,
1638
- ['bio', 1],
1639
- );
1640
- });
1641
-
1642
- it('should be selectable by relation name', () => {
1643
- const query = db.message.select('id', 'profile');
1644
-
1645
- assertType<Awaited<typeof query>, { id: number; profile: Profile }[]>();
1646
-
1647
- expectSql(
1648
- query.toSql(),
1649
- `
1650
- SELECT
1651
- "message"."id",
1652
- (
1653
- SELECT row_to_json("t".*)
1654
- FROM (
1655
- SELECT * FROM "profile"
1656
- WHERE EXISTS (
1657
- SELECT 1 FROM "user"
1658
- WHERE "profile"."userId" = "user"."id"
1659
- AND "user"."id" = "message"."authorId"
1660
- LIMIT 1
1661
- )
1662
- LIMIT $1
1663
- ) AS "t"
1664
- ) AS "profile"
1665
- FROM "message"
1666
- `,
1667
- [1],
1668
- );
1669
- });
1670
-
1671
- it('should handle exists sub query', () => {
1672
- const query = db.message.as('m').select('id', {
1673
- hasProfile: (q) => q.profile.exists(),
1674
- });
1675
-
1676
- assertType<
1677
- Awaited<typeof query>,
1678
- { id: number; hasProfile: boolean }[]
1679
- >();
1680
-
1681
- expectSql(
1682
- query.toSql(),
1683
- `
1684
- SELECT
1685
- "m"."id",
1686
- COALESCE((
1687
- SELECT true
1688
- FROM "profile"
1689
- WHERE EXISTS (
1690
- SELECT 1 FROM "user"
1691
- WHERE "profile"."userId" = "user"."id"
1692
- AND "user"."id" = "m"."authorId"
1693
- LIMIT 1
1694
- )
1695
- ), false) AS "hasProfile"
1696
- FROM "message" AS "m"
1697
- `,
1698
- );
1699
- });
1700
- });
1701
- });