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,2616 +0,0 @@
1
- import { db, pgConfig } from '../test-utils/test-db';
2
- import {
3
- assertType,
4
- chatData,
5
- expectSql,
6
- messageData,
7
- userData,
8
- useRelationCallback,
9
- useTestDatabase,
10
- } from '../test-utils/test-utils';
11
- import { RelationQuery } from 'pqb';
12
- import {
13
- Chat,
14
- Message,
15
- BaseTable,
16
- Profile,
17
- User,
18
- } from '../test-utils/test-tables';
19
- import { orchidORM } from '../orm';
20
-
21
- describe('hasMany', () => {
22
- useTestDatabase();
23
-
24
- describe('querying', () => {
25
- it('should have method to query related data', async () => {
26
- const messagesQuery = db.message.all();
27
-
28
- assertType<
29
- typeof db.user.messages,
30
- RelationQuery<
31
- 'messages',
32
- { id: number },
33
- 'authorId',
34
- typeof messagesQuery,
35
- false,
36
- true,
37
- true
38
- >
39
- >();
40
-
41
- const userId = await db.user.get('id').create(userData);
42
- const chatId = await db.chat.get('id').create(chatData);
43
-
44
- await db.message.createMany([
45
- { ...messageData, authorId: userId, chatId },
46
- { ...messageData, authorId: userId, chatId },
47
- ]);
48
-
49
- const user = await db.user.find(userId);
50
- const query = db.user.messages(user);
51
-
52
- expectSql(
53
- query.toSql(),
54
- `
55
- SELECT * FROM "message" AS "messages"
56
- WHERE "messages"."authorId" = $1
57
- `,
58
- [userId],
59
- );
60
-
61
- const messages = await query;
62
-
63
- expect(messages).toMatchObject([messageData, messageData]);
64
- });
65
-
66
- it('should handle chained query', () => {
67
- const query = db.user
68
- .where({ name: 'name' })
69
- .messages.where({ text: 'text' });
70
-
71
- expectSql(
72
- query.toSql(),
73
- `
74
- SELECT * FROM "message" AS "messages"
75
- WHERE EXISTS (
76
- SELECT 1 FROM "user"
77
- WHERE "user"."name" = $1
78
- AND "user"."id" = "messages"."authorId"
79
- LIMIT 1
80
- )
81
- AND "messages"."text" = $2
82
- `,
83
- ['name', 'text'],
84
- );
85
- });
86
-
87
- it('should have create with defaults of provided id', () => {
88
- const user = { id: 1 };
89
- const query = db.user.messages(user).count().create({
90
- chatId: 2,
91
- text: 'text',
92
- });
93
-
94
- expectSql(
95
- query.toSql(),
96
- `
97
- INSERT INTO "message"("authorId", "chatId", "text")
98
- VALUES ($1, $2, $3)
99
- `,
100
- [1, 2, 'text'],
101
- );
102
- });
103
-
104
- describe('create based on a query', () => {
105
- it('should have create based on a query', () => {
106
- const query = db.chat.find(1).messages.create({
107
- text: 'text',
108
- });
109
-
110
- expectSql(
111
- query.toSql(),
112
- `
113
- INSERT INTO "message"("chatId", "text")
114
- SELECT "chat"."id" AS "chatId", $1
115
- FROM "chat"
116
- WHERE "chat"."id" = $2
117
- LIMIT $3
118
- RETURNING *
119
- `,
120
- ['text', 1, 1],
121
- );
122
- });
123
-
124
- it('should throw when the main query returns many records', async () => {
125
- await expect(
126
- async () =>
127
- await db.chat.messages.create({
128
- text: 'text',
129
- }),
130
- ).rejects.toThrow(
131
- 'Cannot create based on a query which returns multiple records',
132
- );
133
- });
134
-
135
- it('should throw when main record is not found', async () => {
136
- await expect(
137
- async () =>
138
- await db.chat.find(1).messages.create({
139
- text: 'text',
140
- }),
141
- ).rejects.toThrow('Record is not found');
142
- });
143
-
144
- it('should not throw when searching with findOptional', async () => {
145
- await db.chat.findOptional(1).messages.takeOptional().create({
146
- text: 'text',
147
- });
148
- });
149
- });
150
-
151
- it('should have chained delete', () => {
152
- const query = db.chat
153
- .where({ title: 'title' })
154
- .messages.where({ text: 'text' })
155
- .delete();
156
-
157
- expectSql(
158
- query.toSql(),
159
- `
160
- DELETE FROM "message" AS "messages"
161
- WHERE EXISTS (
162
- SELECT 1 FROM "chat"
163
- WHERE "chat"."title" = $1
164
- AND "chat"."id" = "messages"."chatId"
165
- LIMIT 1
166
- )
167
- AND "messages"."text" = $2
168
- `,
169
- ['title', 'text'],
170
- );
171
- });
172
-
173
- it('should have proper joinQuery', () => {
174
- expectSql(
175
- db.user.relations.messages
176
- .joinQuery(db.user.as('u'), db.message.as('m'))
177
- .toSql(),
178
- `
179
- SELECT * FROM "message" AS "m"
180
- WHERE "m"."authorId" = "u"."id"
181
- `,
182
- );
183
- });
184
-
185
- it('should be supported in whereExists', () => {
186
- expectSql(
187
- db.user.whereExists('messages').toSql(),
188
- `
189
- SELECT * FROM "user"
190
- WHERE EXISTS (
191
- SELECT 1 FROM "message" AS "messages"
192
- WHERE "messages"."authorId" = "user"."id"
193
- LIMIT 1
194
- )
195
- `,
196
- );
197
-
198
- expectSql(
199
- db.user
200
- .as('u')
201
- .whereExists('messages', (q) => q.where({ text: 'text' }))
202
- .toSql(),
203
- `
204
- SELECT * FROM "user" AS "u"
205
- WHERE EXISTS (
206
- SELECT 1 FROM "message" AS "messages"
207
- WHERE "messages"."authorId" = "u"."id"
208
- AND "messages"."text" = $1
209
- LIMIT 1
210
- )
211
- `,
212
- ['text'],
213
- );
214
- });
215
-
216
- it('should be supported in join', () => {
217
- const query = db.user
218
- .as('u')
219
- .join('messages', (q) => q.where({ text: 'text' }))
220
- .select('name', 'messages.text');
221
-
222
- assertType<Awaited<typeof query>, { name: string; text: string }[]>();
223
-
224
- expectSql(
225
- query.toSql(),
226
- `
227
- SELECT "u"."name", "messages"."text" FROM "user" AS "u"
228
- JOIN "message" AS "messages"
229
- ON "messages"."authorId" = "u"."id"
230
- AND "messages"."text" = $1
231
- `,
232
- ['text'],
233
- );
234
- });
235
-
236
- describe('select', () => {
237
- it('should be selectable', () => {
238
- const query = db.user.as('u').select('id', {
239
- messages: (q) => q.messages.where({ text: 'text' }),
240
- });
241
-
242
- assertType<
243
- Awaited<typeof query>,
244
- { id: number; messages: Message[] }[]
245
- >();
246
-
247
- expectSql(
248
- query.toSql(),
249
- `
250
- SELECT
251
- "u"."id",
252
- (
253
- SELECT COALESCE(json_agg(row_to_json("t".*)), '[]')
254
- FROM (
255
- SELECT * FROM "message" AS "messages"
256
- WHERE "messages"."text" = $1
257
- AND "messages"."authorId" = "u"."id"
258
- ) AS "t"
259
- ) AS "messages"
260
- FROM "user" AS "u"
261
- `,
262
- ['text'],
263
- );
264
- });
265
-
266
- it('should be selectable by relation name', () => {
267
- const query = db.user.select('id', 'messages');
268
-
269
- assertType<
270
- Awaited<typeof query>,
271
- { id: number; messages: Message[] }[]
272
- >();
273
-
274
- expectSql(
275
- query.toSql(),
276
- `
277
- SELECT
278
- "user"."id",
279
- (
280
- SELECT COALESCE(json_agg(row_to_json("t".*)), '[]')
281
- FROM (
282
- SELECT * FROM "message" AS "messages"
283
- WHERE "messages"."authorId" = "user"."id"
284
- ) AS "t"
285
- ) AS "messages"
286
- FROM "user"
287
- `,
288
- );
289
- });
290
- });
291
-
292
- it('should allow to select count', () => {
293
- const query = db.user.as('u').select('id', {
294
- messagesCount: (q) => q.messages.count(),
295
- });
296
-
297
- assertType<
298
- Awaited<typeof query>,
299
- { id: number; messagesCount: number }[]
300
- >();
301
-
302
- expectSql(
303
- query.toSql(),
304
- `
305
- SELECT
306
- "u"."id",
307
- (
308
- SELECT count(*) FROM "message" AS "messages"
309
- WHERE "messages"."authorId" = "u"."id"
310
- ) AS "messagesCount"
311
- FROM "user" AS "u"
312
- `,
313
- );
314
- });
315
-
316
- it('should allow to pluck values', () => {
317
- const query = db.user.as('u').select('id', {
318
- texts: (q) => q.messages.pluck('text'),
319
- });
320
-
321
- assertType<Awaited<typeof query>, { id: number; texts: string[] }[]>();
322
-
323
- expectSql(
324
- query.toSql(),
325
- `
326
- SELECT
327
- "u"."id",
328
- (
329
- SELECT COALESCE(json_agg("c"), '[]')
330
- FROM (
331
- SELECT "messages"."text" AS "c"
332
- FROM "message" AS "messages"
333
- WHERE "messages"."authorId" = "u"."id"
334
- ) AS "t"
335
- ) AS "texts"
336
- FROM "user" AS "u"
337
- `,
338
- );
339
- });
340
-
341
- it('should handle exists sub query', () => {
342
- const query = db.user.as('u').select('id', {
343
- hasMessages: (q) => q.messages.exists(),
344
- });
345
-
346
- assertType<
347
- Awaited<typeof query>,
348
- { id: number; hasMessages: boolean }[]
349
- >();
350
-
351
- expectSql(
352
- query.toSql(),
353
- `
354
- SELECT
355
- "u"."id",
356
- COALESCE((
357
- SELECT true
358
- FROM "message" AS "messages"
359
- WHERE "messages"."authorId" = "u"."id"
360
- ), false) AS "hasMessages"
361
- FROM "user" AS "u"
362
- `,
363
- );
364
- });
365
- });
366
-
367
- describe('create', () => {
368
- const checkUser = (user: User, name: string) => {
369
- expect(user).toEqual({
370
- ...userData,
371
- id: user.id,
372
- name: name,
373
- active: null,
374
- age: null,
375
- data: null,
376
- picture: null,
377
- });
378
- };
379
-
380
- const checkMessages = ({
381
- messages,
382
- userId,
383
- chatId,
384
- text1,
385
- text2,
386
- }: {
387
- messages: Message[];
388
- userId: number;
389
- chatId: number;
390
- text1: string;
391
- text2: string;
392
- }) => {
393
- expect(messages).toMatchObject([
394
- {
395
- id: messages[0].id,
396
- authorId: userId,
397
- text: text1,
398
- chatId,
399
- meta: null,
400
- },
401
- {
402
- id: messages[1].id,
403
- authorId: userId,
404
- text: text2,
405
- chatId,
406
- meta: null,
407
- },
408
- ]);
409
- };
410
-
411
- describe('nested create', () => {
412
- it('should support create', async () => {
413
- const chatId = await db.chat.get('id').create(chatData);
414
-
415
- const user = await db.user.create({
416
- ...userData,
417
- name: 'user 1',
418
- messages: {
419
- create: [
420
- {
421
- ...messageData,
422
- text: 'message 1',
423
- chatId,
424
- },
425
- {
426
- ...messageData,
427
- text: 'message 2',
428
- chatId,
429
- },
430
- ],
431
- },
432
- });
433
-
434
- checkUser(user, 'user 1');
435
-
436
- const messages = await db.message.order('text');
437
- checkMessages({
438
- messages,
439
- userId: user.id,
440
- chatId,
441
- text1: 'message 1',
442
- text2: 'message 2',
443
- });
444
- });
445
-
446
- it('should support create in batch create', async () => {
447
- const chatId = await db.chat.get('id').create(chatData);
448
-
449
- const user = await db.user.createMany([
450
- {
451
- ...userData,
452
- name: 'user 1',
453
- messages: {
454
- create: [
455
- {
456
- ...messageData,
457
- text: 'message 1',
458
- chatId,
459
- },
460
- {
461
- ...messageData,
462
- text: 'message 2',
463
- chatId,
464
- },
465
- ],
466
- },
467
- },
468
- {
469
- ...userData,
470
- name: 'user 2',
471
- messages: {
472
- create: [
473
- {
474
- ...messageData,
475
- text: 'message 3',
476
- chatId,
477
- },
478
- {
479
- ...messageData,
480
- text: 'message 4',
481
- chatId,
482
- },
483
- ],
484
- },
485
- },
486
- ]);
487
-
488
- checkUser(user[0], 'user 1');
489
- checkUser(user[1], 'user 2');
490
-
491
- const messages = await db.message.order('text');
492
- checkMessages({
493
- messages: messages.slice(0, 2),
494
- userId: user[0].id,
495
- chatId,
496
- text1: 'message 1',
497
- text2: 'message 2',
498
- });
499
-
500
- checkMessages({
501
- messages: messages.slice(2, 4),
502
- userId: user[1].id,
503
- chatId,
504
- text1: 'message 3',
505
- text2: 'message 4',
506
- });
507
- });
508
-
509
- it('should ignore empty create list', async () => {
510
- const user = await db.user.create({
511
- ...userData,
512
- name: 'user 1',
513
- messages: {
514
- create: [],
515
- },
516
- });
517
-
518
- checkUser(user, 'user 1');
519
- });
520
-
521
- describe('relation callbacks', () => {
522
- const { beforeCreate, afterCreate, resetMocks } = useRelationCallback(
523
- db.user.relations.messages,
524
- );
525
-
526
- it('should invoke callbacks', async () => {
527
- const chatId = await db.chat.get('id').create(chatData);
528
-
529
- await db.user.create({
530
- ...userData,
531
- messages: {
532
- create: [
533
- { ...messageData, chatId },
534
- { ...messageData, chatId },
535
- ],
536
- },
537
- });
538
-
539
- expect(beforeCreate).toHaveBeenCalledTimes(1);
540
- expect(afterCreate).toHaveBeenCalledTimes(1);
541
- });
542
-
543
- it('should invoke callbacks in a batch create', async () => {
544
- resetMocks();
545
-
546
- const chatId = await db.chat.get('id').create(chatData);
547
-
548
- await db.user.createMany([
549
- {
550
- ...userData,
551
- messages: {
552
- create: [
553
- { ...messageData, chatId },
554
- { ...messageData, chatId },
555
- ],
556
- },
557
- },
558
- {
559
- ...userData,
560
- messages: {
561
- create: [
562
- { ...messageData, chatId },
563
- { ...messageData, chatId },
564
- ],
565
- },
566
- },
567
- ]);
568
-
569
- expect(beforeCreate).toHaveBeenCalledTimes(1);
570
- expect(afterCreate).toHaveBeenCalledTimes(1);
571
- });
572
- });
573
- });
574
-
575
- describe('nested connect', () => {
576
- it('should support connect', async () => {
577
- const chatId = await db.chat.get('id').create(chatData);
578
- await db.message.createMany([
579
- {
580
- ...messageData,
581
- chatId,
582
- user: { create: { ...userData, name: 'tmp' } },
583
- text: 'message 1',
584
- },
585
- {
586
- ...messageData,
587
- chatId,
588
- user: { connect: { name: 'tmp' } },
589
- text: 'message 2',
590
- },
591
- ]);
592
-
593
- const user = await db.user.create({
594
- ...userData,
595
- name: 'user 1',
596
- messages: {
597
- connect: [
598
- {
599
- text: 'message 1',
600
- },
601
- {
602
- text: 'message 2',
603
- },
604
- ],
605
- },
606
- });
607
-
608
- checkUser(user, 'user 1');
609
-
610
- const messages = await db.message.order('text');
611
- checkMessages({
612
- messages,
613
- userId: user.id,
614
- chatId,
615
- text1: 'message 1',
616
- text2: 'message 2',
617
- });
618
- });
619
-
620
- it('should support connect in batch create', async () => {
621
- const chatId = await db.chat.get('id').create(chatData);
622
- await db.message.createMany([
623
- {
624
- ...messageData,
625
- chatId,
626
- user: { create: { ...userData, name: 'tmp' } },
627
- text: 'message 1',
628
- },
629
- {
630
- ...messageData,
631
- chatId,
632
- user: { connect: { name: 'tmp' } },
633
- text: 'message 2',
634
- },
635
- {
636
- ...messageData,
637
- chatId,
638
- user: { connect: { name: 'tmp' } },
639
- text: 'message 3',
640
- },
641
- {
642
- ...messageData,
643
- chatId,
644
- user: { connect: { name: 'tmp' } },
645
- text: 'message 4',
646
- },
647
- ]);
648
-
649
- const user = await db.user.createMany([
650
- {
651
- ...userData,
652
- name: 'user 1',
653
- messages: {
654
- connect: [
655
- {
656
- text: 'message 1',
657
- },
658
- {
659
- text: 'message 2',
660
- },
661
- ],
662
- },
663
- },
664
- {
665
- ...userData,
666
- name: 'user 2',
667
- messages: {
668
- connect: [
669
- {
670
- text: 'message 3',
671
- },
672
- {
673
- text: 'message 4',
674
- },
675
- ],
676
- },
677
- },
678
- ]);
679
-
680
- checkUser(user[0], 'user 1');
681
- checkUser(user[1], 'user 2');
682
-
683
- const messages = await db.message.order('text');
684
- checkMessages({
685
- messages: messages.slice(0, 2),
686
- userId: user[0].id,
687
- chatId,
688
- text1: 'message 1',
689
- text2: 'message 2',
690
- });
691
-
692
- checkMessages({
693
- messages: messages.slice(2, 4),
694
- userId: user[1].id,
695
- chatId,
696
- text1: 'message 3',
697
- text2: 'message 4',
698
- });
699
- });
700
-
701
- it('should ignore empty connect list', async () => {
702
- const user = await db.user.create({
703
- ...userData,
704
- name: 'user 1',
705
- messages: {
706
- connect: [],
707
- },
708
- });
709
-
710
- checkUser(user, 'user 1');
711
- });
712
-
713
- describe('relation callbacks', () => {
714
- const { beforeUpdate, afterUpdate, resetMocks } = useRelationCallback(
715
- db.user.relations.messages,
716
- );
717
-
718
- it('should invoke callbacks', async () => {
719
- const chatId = await db.chat.get('id').create(chatData);
720
- const ids = await db.message.pluck('id').createMany([
721
- { ...messageData, chatId },
722
- { ...messageData, chatId },
723
- ]);
724
-
725
- await db.user.create({
726
- ...userData,
727
- messages: {
728
- connect: [{ id: ids[0] }, { id: ids[1] }],
729
- },
730
- });
731
-
732
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
733
- expect(afterUpdate).toHaveBeenCalledTimes(1);
734
- });
735
-
736
- it('should invoke callbacks in a batch create', async () => {
737
- const chatId = await db.chat.get('id').create(chatData);
738
-
739
- const ids = await db.message.pluck('id').createMany([
740
- { ...messageData, chatId },
741
- { ...messageData, chatId },
742
- { ...messageData, chatId },
743
- { ...messageData, chatId },
744
- ]);
745
-
746
- resetMocks();
747
-
748
- await db.user.createMany([
749
- {
750
- ...userData,
751
- messages: {
752
- connect: [{ id: ids[0] }, { id: ids[1] }],
753
- },
754
- },
755
- {
756
- ...userData,
757
- messages: {
758
- connect: [{ id: ids[2] }, { id: ids[3] }],
759
- },
760
- },
761
- ]);
762
-
763
- expect(beforeUpdate).toHaveBeenCalledTimes(2);
764
- expect(afterUpdate).toHaveBeenCalledTimes(2);
765
- });
766
- });
767
- });
768
-
769
- describe('connectOrCreate', () => {
770
- it('should support connect or create', async () => {
771
- const chatId = await db.chat.get('id').create(chatData);
772
- const messageId = await db.message.get('id').create({
773
- ...messageData,
774
- chatId,
775
- user: { create: { ...userData, name: 'tmp' } },
776
- text: 'message 1',
777
- });
778
-
779
- const user = await db.user.create({
780
- ...userData,
781
- name: 'user 1',
782
- messages: {
783
- connectOrCreate: [
784
- {
785
- where: { text: 'message 1' },
786
- create: { ...messageData, chatId, text: 'message 1' },
787
- },
788
- {
789
- where: { text: 'message 2' },
790
- create: { ...messageData, chatId, text: 'message 2' },
791
- },
792
- ],
793
- },
794
- });
795
-
796
- checkUser(user, 'user 1');
797
-
798
- const messages = await db.message.order('text');
799
- expect(messages[0].id).toBe(messageId);
800
-
801
- checkMessages({
802
- messages,
803
- userId: user.id,
804
- chatId,
805
- text1: 'message 1',
806
- text2: 'message 2',
807
- });
808
- });
809
-
810
- it('should support connect or create in batch create', async () => {
811
- const chatId = await db.chat.get('id').create(chatData);
812
- const [{ id: message1Id }, { id: message4Id }] = await db.message
813
- .select('id')
814
- .createMany([
815
- {
816
- ...messageData,
817
- chatId,
818
- user: { create: { ...userData, name: 'tmp' } },
819
- text: 'message 1',
820
- },
821
- {
822
- ...messageData,
823
- chatId,
824
- user: { create: { ...userData, name: 'tmp' } },
825
- text: 'message 4',
826
- },
827
- ]);
828
-
829
- const users = await db.user.createMany([
830
- {
831
- ...userData,
832
- name: 'user 1',
833
- messages: {
834
- connectOrCreate: [
835
- {
836
- where: { text: 'message 1' },
837
- create: { ...messageData, chatId, text: 'message 1' },
838
- },
839
- {
840
- where: { text: 'message 2' },
841
- create: { ...messageData, chatId, text: 'message 2' },
842
- },
843
- ],
844
- },
845
- },
846
- {
847
- ...userData,
848
- name: 'user 2',
849
- messages: {
850
- connectOrCreate: [
851
- {
852
- where: { text: 'message 3' },
853
- create: { ...messageData, chatId, text: 'message 3' },
854
- },
855
- {
856
- where: { text: 'message 4' },
857
- create: { ...messageData, chatId, text: 'message 4' },
858
- },
859
- ],
860
- },
861
- },
862
- ]);
863
-
864
- checkUser(users[0], 'user 1');
865
- checkUser(users[1], 'user 2');
866
-
867
- const messages = await db.message.order('text');
868
- expect(messages[0].id).toBe(message1Id);
869
- expect(messages[3].id).toBe(message4Id);
870
-
871
- checkMessages({
872
- messages: messages.slice(0, 2),
873
- userId: users[0].id,
874
- chatId,
875
- text1: 'message 1',
876
- text2: 'message 2',
877
- });
878
-
879
- checkMessages({
880
- messages: messages.slice(2, 4),
881
- userId: users[1].id,
882
- chatId,
883
- text1: 'message 3',
884
- text2: 'message 4',
885
- });
886
- });
887
-
888
- it('should ignore empty connectOrCreate list', async () => {
889
- const user = await db.user.create({
890
- ...userData,
891
- name: 'user 1',
892
- messages: {
893
- connectOrCreate: [],
894
- },
895
- });
896
-
897
- checkUser(user, 'user 1');
898
- });
899
-
900
- describe('relation callbacks', () => {
901
- const {
902
- beforeCreate,
903
- afterCreate,
904
- beforeUpdate,
905
- afterUpdate,
906
- resetMocks,
907
- } = useRelationCallback(db.user.relations.messages);
908
-
909
- it('should invoke callbacks when connecting', async () => {
910
- const chatId = await db.chat.get('id').create(chatData);
911
- const ids = await db.message.pluck('id').createMany([
912
- { ...messageData, chatId },
913
- { ...messageData, chatId },
914
- ]);
915
-
916
- await db.user.create({
917
- ...userData,
918
- messages: {
919
- connectOrCreate: [
920
- {
921
- where: { id: ids[0] },
922
- create: messageData,
923
- },
924
- {
925
- where: { id: ids[1] },
926
- create: messageData,
927
- },
928
- ],
929
- },
930
- });
931
-
932
- expect(beforeUpdate).toHaveBeenCalledTimes(2);
933
- expect(afterUpdate).toHaveBeenCalledTimes(2);
934
- });
935
-
936
- it('should invoke callbacks when creating', async () => {
937
- const chatId = await db.chat.get('id').create(chatData);
938
-
939
- resetMocks();
940
-
941
- await db.user.create({
942
- ...userData,
943
- messages: {
944
- connectOrCreate: [
945
- {
946
- where: { id: 0 },
947
- create: { ...messageData, chatId },
948
- },
949
- {
950
- where: { id: 0 },
951
- create: { ...messageData, chatId },
952
- },
953
- ],
954
- },
955
- });
956
-
957
- expect(beforeCreate).toHaveBeenCalledTimes(1);
958
- expect(afterCreate).toHaveBeenCalledTimes(1);
959
- });
960
-
961
- it('should invoke callbacks in a batch create', async () => {
962
- const chatId = await db.chat.get('id').create(chatData);
963
- const ids = await db.message.pluck('id').createMany([
964
- { ...messageData, chatId },
965
- { ...messageData, chatId },
966
- ]);
967
-
968
- resetMocks();
969
-
970
- await db.user.createMany([
971
- {
972
- ...userData,
973
- messages: {
974
- connectOrCreate: [
975
- {
976
- where: { id: ids[0] },
977
- create: { ...messageData, chatId },
978
- },
979
- {
980
- where: { id: 0 },
981
- create: { ...messageData, chatId },
982
- },
983
- ],
984
- },
985
- },
986
- {
987
- ...userData,
988
- messages: {
989
- connectOrCreate: [
990
- {
991
- where: { id: ids[1] },
992
- create: { ...messageData, chatId },
993
- },
994
- {
995
- where: { id: 0 },
996
- create: { ...messageData, chatId },
997
- },
998
- ],
999
- },
1000
- },
1001
- ]);
1002
-
1003
- expect(beforeUpdate).toHaveBeenCalledTimes(4);
1004
- expect(afterUpdate).toHaveBeenCalledTimes(4);
1005
- expect(beforeCreate).toHaveBeenCalledTimes(1);
1006
- expect(afterCreate).toHaveBeenCalledTimes(1);
1007
- });
1008
- });
1009
- });
1010
- });
1011
-
1012
- describe('update', () => {
1013
- describe('disconnect', () => {
1014
- it('should nullify foreignKey', async () => {
1015
- const chatId = await db.chat
1016
- .get('id')
1017
- .create({ ...chatData, title: 'chat 1' });
1018
-
1019
- const userId = await db.user.get('id').create({
1020
- ...userData,
1021
- messages: {
1022
- create: [
1023
- { ...messageData, chatId: chatId, text: 'message 1' },
1024
- { ...messageData, chatId: chatId, text: 'message 2' },
1025
- { ...messageData, chatId: chatId, text: 'message 3' },
1026
- ],
1027
- },
1028
- });
1029
-
1030
- await db.user.find(userId).update({
1031
- messages: {
1032
- disconnect: [{ text: 'message 1' }, { text: 'message 2' }],
1033
- },
1034
- });
1035
-
1036
- const messages = await db.message.order('text');
1037
- expect(messages[0].authorId).toBe(null);
1038
- expect(messages[1].authorId).toBe(null);
1039
- expect(messages[2].authorId).toBe(userId);
1040
- });
1041
-
1042
- it('should nullify foreignKey in batch update', async () => {
1043
- const chatId = await db.chat
1044
- .get('id')
1045
- .create({ ...chatData, title: 'chat 1' });
1046
-
1047
- const userIds = await db.user.pluck('id').createMany([
1048
- {
1049
- ...userData,
1050
- messages: {
1051
- create: [{ ...messageData, chatId: chatId, text: 'message 1' }],
1052
- },
1053
- },
1054
- {
1055
- ...userData,
1056
- messages: {
1057
- create: [
1058
- { ...messageData, chatId: chatId, text: 'message 2' },
1059
- { ...messageData, chatId: chatId, text: 'message 3' },
1060
- ],
1061
- },
1062
- },
1063
- ]);
1064
-
1065
- await db.user.where({ id: { in: userIds } }).update({
1066
- messages: {
1067
- disconnect: [{ text: 'message 1' }, { text: 'message 2' }],
1068
- },
1069
- });
1070
-
1071
- const messages = await db.message.order('text');
1072
- expect(messages[0].authorId).toBe(null);
1073
- expect(messages[1].authorId).toBe(null);
1074
- expect(messages[2].authorId).toBe(userIds[1]);
1075
- });
1076
-
1077
- it('should ignore empty disconnect list', async () => {
1078
- const id = await db.user.get('id').create(userData);
1079
-
1080
- await db.user.find(id).update({
1081
- messages: {
1082
- disconnect: [],
1083
- },
1084
- });
1085
- });
1086
-
1087
- describe('relation callbacks', () => {
1088
- const { beforeUpdate, afterUpdate, resetMocks } = useRelationCallback(
1089
- db.user.relations.messages,
1090
- );
1091
-
1092
- it('should invoke callbacks', async () => {
1093
- const chatId = await db.chat.get('id').create(chatData);
1094
- const userId = await db.user.get('id').create({
1095
- ...userData,
1096
- messages: {
1097
- create: [
1098
- {
1099
- ...messageData,
1100
- chatId,
1101
- text: 'message 1',
1102
- },
1103
- {
1104
- ...messageData,
1105
- chatId,
1106
- text: 'message 2',
1107
- },
1108
- ],
1109
- },
1110
- });
1111
-
1112
- await db.user.find(userId).update({
1113
- messages: {
1114
- disconnect: [{ text: 'message 1' }, { text: 'message 2' }],
1115
- },
1116
- });
1117
-
1118
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
1119
- expect(afterUpdate).toHaveBeenCalledTimes(1);
1120
- });
1121
-
1122
- it('should invoke callbacks in a batch update', async () => {
1123
- resetMocks();
1124
-
1125
- const chatId = await db.chat.get('id').create(chatData);
1126
- const ids = await db.user.pluck('id').createMany([
1127
- {
1128
- ...userData,
1129
- messages: {
1130
- create: [
1131
- {
1132
- ...messageData,
1133
- chatId,
1134
- text: 'message 1',
1135
- },
1136
- {
1137
- ...messageData,
1138
- chatId,
1139
- text: 'message 1',
1140
- },
1141
- ],
1142
- },
1143
- },
1144
- {
1145
- ...userData,
1146
- messages: {
1147
- create: [
1148
- {
1149
- ...messageData,
1150
- chatId,
1151
- text: 'message 3',
1152
- },
1153
- {
1154
- ...messageData,
1155
- chatId,
1156
- text: 'message 4',
1157
- },
1158
- ],
1159
- },
1160
- },
1161
- ]);
1162
-
1163
- await db.user.where({ id: { in: ids } }).update({
1164
- messages: {
1165
- disconnect: [{ text: 'message 1' }, { text: 'message 3' }],
1166
- },
1167
- });
1168
-
1169
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
1170
- expect(afterUpdate).toHaveBeenCalledTimes(1);
1171
- });
1172
- });
1173
- });
1174
-
1175
- describe('set', () => {
1176
- it('should nullify foreignKey of previous related record and set foreignKey to new related record', async () => {
1177
- const chatId = await db.chat.get('id').create(chatData);
1178
- const id = await db.user.get('id').create({
1179
- ...userData,
1180
- messages: {
1181
- create: [
1182
- { ...messageData, chatId, text: 'message 1' },
1183
- { ...messageData, chatId, text: 'message 2' },
1184
- ],
1185
- },
1186
- });
1187
-
1188
- await db.message.create({ ...messageData, chatId, text: 'message 3' });
1189
-
1190
- await db.user.find(id).update({
1191
- messages: {
1192
- set: { text: { in: ['message 2', 'message 3'] } },
1193
- },
1194
- });
1195
-
1196
- const [message1, message2, message3] = await db.message.order({
1197
- text: 'ASC',
1198
- });
1199
-
1200
- expect(message1.authorId).toBe(null);
1201
- expect(message2.authorId).toBe(id);
1202
- expect(message3.authorId).toBe(id);
1203
- });
1204
-
1205
- it('should throw in batch update', async () => {
1206
- const query = db.user.where({ id: { in: [1, 2, 3] } }).update({
1207
- messages: {
1208
- // @ts-expect-error not allows in batch update
1209
- set: { text: { in: ['message 2', 'message 3'] } },
1210
- },
1211
- });
1212
-
1213
- await expect(query).rejects.toThrow();
1214
- });
1215
-
1216
- describe('relation callbacks', () => {
1217
- const { beforeUpdate, afterUpdate } = useRelationCallback(
1218
- db.user.relations.messages,
1219
- );
1220
-
1221
- it('should invoke callbacks', async () => {
1222
- const chatId = await db.chat.get('id').create(chatData);
1223
- const id = await db.user.get('id').create({
1224
- ...userData,
1225
- messages: {
1226
- create: [
1227
- { ...messageData, chatId, text: 'message 1' },
1228
- { ...messageData, chatId, text: 'message 2' },
1229
- ],
1230
- },
1231
- });
1232
-
1233
- await db.message.create({
1234
- ...messageData,
1235
- chatId,
1236
- text: 'message 3',
1237
- });
1238
-
1239
- await db.user.find(id).update({
1240
- messages: {
1241
- set: { text: { in: ['message 2', 'message 3'] } },
1242
- },
1243
- });
1244
-
1245
- expect(beforeUpdate).toHaveBeenCalledTimes(2);
1246
- expect(afterUpdate).toHaveBeenCalledTimes(2);
1247
- });
1248
- });
1249
- });
1250
-
1251
- describe('delete', () => {
1252
- it('should delete related records', async () => {
1253
- const chatId = await db.chat.get('id').create(chatData);
1254
-
1255
- const id = await db.user.get('id').create({
1256
- ...userData,
1257
- messages: {
1258
- create: [
1259
- { ...messageData, chatId, text: 'message 1' },
1260
- { ...messageData, chatId, text: 'message 2' },
1261
- { ...messageData, chatId, text: 'message 3' },
1262
- ],
1263
- },
1264
- });
1265
-
1266
- await db.user.find(id).update({
1267
- messages: {
1268
- delete: {
1269
- text: { in: ['message 1', 'message 2'] },
1270
- },
1271
- },
1272
- });
1273
-
1274
- expect(await db.message.count()).toBe(1);
1275
-
1276
- const messages = await db.user.messages({ id }).select('text');
1277
- expect(messages).toEqual([{ text: 'message 3' }]);
1278
- });
1279
-
1280
- it('should delete related records in batch update', async () => {
1281
- const chatId = await db.chat.get('id').create(chatData);
1282
-
1283
- const userIds = await db.user.pluck('id').createMany([
1284
- {
1285
- ...userData,
1286
- messages: {
1287
- create: [{ ...messageData, chatId, text: 'message 1' }],
1288
- },
1289
- },
1290
- {
1291
- ...userData,
1292
- messages: {
1293
- create: [
1294
- { ...messageData, chatId, text: 'message 2' },
1295
- { ...messageData, chatId, text: 'message 3' },
1296
- ],
1297
- },
1298
- },
1299
- ]);
1300
-
1301
- await db.user.where({ id: { in: userIds } }).update({
1302
- messages: {
1303
- delete: [{ text: 'message 1' }, { text: 'message 2' }],
1304
- },
1305
- });
1306
-
1307
- expect(await db.message.count()).toBe(1);
1308
-
1309
- const messages = await db.user
1310
- .messages({ id: userIds[1] })
1311
- .select('text');
1312
- expect(messages).toEqual([{ text: 'message 3' }]);
1313
- });
1314
-
1315
- it('should ignore empty delete list', async () => {
1316
- const chatId = await db.chat.get('id').create(chatData);
1317
-
1318
- const id = await db.user.get('id').create({
1319
- ...userData,
1320
- messages: {
1321
- create: [{ ...messageData, chatId, text: 'message 1' }],
1322
- },
1323
- });
1324
-
1325
- await db.user.find(id).update({
1326
- messages: {
1327
- delete: [],
1328
- },
1329
- });
1330
-
1331
- const messages = await db.user.messages({ id }).pluck('text');
1332
- expect(messages).toEqual(['message 1']);
1333
- });
1334
-
1335
- describe('relation callbacks', () => {
1336
- const { beforeDelete, afterDelete, resetMocks } = useRelationCallback(
1337
- db.user.relations.messages,
1338
- );
1339
-
1340
- it('should invoke callbacks', async () => {
1341
- const chatId = await db.chat.get('id').create(chatData);
1342
- const id = await db.user.get('id').create({
1343
- ...userData,
1344
- messages: {
1345
- create: [
1346
- { ...messageData, chatId, text: 'message 1' },
1347
- { ...messageData, chatId, text: 'message 2' },
1348
- { ...messageData, chatId, text: 'message 3' },
1349
- ],
1350
- },
1351
- });
1352
-
1353
- await db.user.find(id).update({
1354
- messages: {
1355
- delete: [{ text: 'message 1' }, { text: 'message 2' }],
1356
- },
1357
- });
1358
-
1359
- expect(beforeDelete).toHaveBeenCalledTimes(1);
1360
- expect(afterDelete).toHaveBeenCalledTimes(1);
1361
- });
1362
-
1363
- it('should invoke callbacks in a batch delete', async () => {
1364
- resetMocks();
1365
-
1366
- const chatId = await db.chat.get('id').create(chatData);
1367
- const ids = await db.user.pluck('id').createMany([
1368
- {
1369
- ...userData,
1370
- messages: {
1371
- create: [
1372
- { ...messageData, chatId, text: 'message 1' },
1373
- { ...messageData, chatId, text: 'message 2' },
1374
- { ...messageData, chatId, text: 'message 3' },
1375
- ],
1376
- },
1377
- },
1378
- {
1379
- ...userData,
1380
- messages: {
1381
- create: [
1382
- { ...messageData, chatId, text: 'message 4' },
1383
- { ...messageData, chatId, text: 'message 5' },
1384
- { ...messageData, chatId, text: 'message 6' },
1385
- ],
1386
- },
1387
- },
1388
- ]);
1389
-
1390
- await db.user.where({ id: { in: ids } }).update({
1391
- messages: {
1392
- delete: [
1393
- { text: 'message 1' },
1394
- { text: 'message 2' },
1395
- { text: 'message 4' },
1396
- { text: 'message 5' },
1397
- ],
1398
- },
1399
- });
1400
-
1401
- expect(beforeDelete).toHaveBeenCalledTimes(1);
1402
- expect(afterDelete).toHaveBeenCalledTimes(1);
1403
- });
1404
- });
1405
- });
1406
-
1407
- describe('nested update', () => {
1408
- it('should update related records', async () => {
1409
- const chatId = await db.chat.get('id').create(chatData);
1410
-
1411
- const id = await db.user.get('id').create({
1412
- ...userData,
1413
- messages: {
1414
- create: [
1415
- { ...messageData, chatId, text: 'message 1' },
1416
- { ...messageData, chatId, text: 'message 2' },
1417
- { ...messageData, chatId, text: 'message 3' },
1418
- ],
1419
- },
1420
- });
1421
-
1422
- await db.user.find(id).update({
1423
- messages: {
1424
- update: {
1425
- where: {
1426
- text: { in: ['message 1', 'message 3'] },
1427
- },
1428
- data: {
1429
- text: 'updated',
1430
- },
1431
- },
1432
- },
1433
- });
1434
-
1435
- const messages = await db.user
1436
- .messages({ id })
1437
- .order('id')
1438
- .pluck('text');
1439
- expect(messages).toEqual(['updated', 'message 2', 'updated']);
1440
- });
1441
-
1442
- it('should update related records in batch update', async () => {
1443
- const chatId = await db.chat.get('id').create(chatData);
1444
-
1445
- const userIds = await db.user.pluck('id').createMany([
1446
- {
1447
- ...userData,
1448
- messages: {
1449
- create: [{ ...messageData, chatId, text: 'message 1' }],
1450
- },
1451
- },
1452
- {
1453
- ...userData,
1454
- messages: {
1455
- create: [
1456
- { ...messageData, chatId, text: 'message 2' },
1457
- { ...messageData, chatId, text: 'message 3' },
1458
- ],
1459
- },
1460
- },
1461
- ]);
1462
-
1463
- await db.user.where({ id: { in: userIds } }).update({
1464
- messages: {
1465
- update: {
1466
- where: {
1467
- text: { in: ['message 1', 'message 3'] },
1468
- },
1469
- data: {
1470
- text: 'updated',
1471
- },
1472
- },
1473
- },
1474
- });
1475
-
1476
- const messages = await db.message.order('id').pluck('text');
1477
- expect(messages).toEqual(['updated', 'message 2', 'updated']);
1478
- });
1479
-
1480
- it('should ignore empty update where list', async () => {
1481
- const chatId = await db.chat.get('id').create(chatData);
1482
-
1483
- const id = await db.user.get('id').create({
1484
- ...userData,
1485
- messages: {
1486
- create: [{ ...messageData, chatId, text: 'message 1' }],
1487
- },
1488
- });
1489
-
1490
- await db.user.find(id).update({
1491
- messages: {
1492
- update: {
1493
- where: [],
1494
- data: {
1495
- text: 'updated',
1496
- },
1497
- },
1498
- },
1499
- });
1500
-
1501
- const messages = await db.user.messages({ id }).pluck('text');
1502
- expect(messages).toEqual(['message 1']);
1503
- });
1504
-
1505
- describe('relation callbacks', () => {
1506
- const { beforeUpdate, afterUpdate, resetMocks } = useRelationCallback(
1507
- db.user.relations.messages,
1508
- );
1509
-
1510
- it('should invoke callbacks', async () => {
1511
- const chatId = await db.chat.get('id').create(chatData);
1512
- const id = await db.user.get('id').create({
1513
- ...userData,
1514
- messages: {
1515
- create: [
1516
- { ...messageData, chatId, text: 'message 1' },
1517
- { ...messageData, chatId, text: 'message 2' },
1518
- { ...messageData, chatId, text: 'message 3' },
1519
- ],
1520
- },
1521
- });
1522
-
1523
- await db.user.find(id).update({
1524
- messages: {
1525
- update: {
1526
- where: [{ text: 'message 1' }, { text: 'message 2' }],
1527
- data: {
1528
- text: 'updated',
1529
- },
1530
- },
1531
- },
1532
- });
1533
-
1534
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
1535
- expect(afterUpdate).toHaveBeenCalledTimes(1);
1536
- });
1537
-
1538
- it('should invoke callbacks in a batch update', async () => {
1539
- resetMocks();
1540
-
1541
- const chatId = await db.chat.get('id').create(chatData);
1542
- const ids = await db.user.pluck('id').createMany([
1543
- {
1544
- ...userData,
1545
- messages: {
1546
- create: [
1547
- { ...messageData, chatId, text: 'message 1' },
1548
- { ...messageData, chatId, text: 'message 2' },
1549
- { ...messageData, chatId, text: 'message 3' },
1550
- ],
1551
- },
1552
- },
1553
- {
1554
- ...userData,
1555
- messages: {
1556
- create: [
1557
- { ...messageData, chatId, text: 'message 1' },
1558
- { ...messageData, chatId, text: 'message 2' },
1559
- { ...messageData, chatId, text: 'message 3' },
1560
- ],
1561
- },
1562
- },
1563
- ]);
1564
-
1565
- await db.user.where({ id: { in: ids } }).update({
1566
- messages: {
1567
- update: {
1568
- where: [
1569
- { text: 'message 1' },
1570
- { text: 'message 2' },
1571
- { text: 'message 3' },
1572
- { text: 'message 4' },
1573
- ],
1574
- data: {
1575
- text: 'updated',
1576
- },
1577
- },
1578
- },
1579
- });
1580
-
1581
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
1582
- expect(afterUpdate).toHaveBeenCalledTimes(1);
1583
- });
1584
- });
1585
- });
1586
-
1587
- describe('nested create', () => {
1588
- it('should create new related records', async () => {
1589
- const chatId = await db.chat.get('id').create(chatData);
1590
- const user = await db.user.create({ ...userData, age: 1 });
1591
-
1592
- const updated = await db.user
1593
- .select('age')
1594
- .find(user.id)
1595
- .increment('age')
1596
- .update({
1597
- messages: {
1598
- create: [
1599
- { ...messageData, chatId, text: 'created 1' },
1600
- { ...messageData, chatId, text: 'created 2' },
1601
- ],
1602
- },
1603
- });
1604
-
1605
- expect(updated.age).toBe(2);
1606
-
1607
- const texts = await db.user.messages(user).order('text').pluck('text');
1608
- expect(texts).toEqual(['created 1', 'created 2']);
1609
- });
1610
-
1611
- it('should throw in batch update', async () => {
1612
- const query = db.user.where({ id: { in: [1, 2, 3] } }).update({
1613
- messages: {
1614
- // @ts-expect-error not allows in batch update
1615
- create: [{ ...messageData, chatId: 1, text: 'created 1' }],
1616
- },
1617
- });
1618
-
1619
- await expect(query).rejects.toThrow();
1620
- });
1621
-
1622
- it('should ignore empty create list', async () => {
1623
- const id = await db.user.get('id').create(userData);
1624
-
1625
- await db.user.find(id).update({
1626
- messages: {
1627
- create: [],
1628
- },
1629
- });
1630
-
1631
- const messages = await db.user.messages({ id });
1632
- expect(messages.length).toEqual(0);
1633
- });
1634
-
1635
- describe('relation callbacks', () => {
1636
- const { beforeCreate, afterCreate } = useRelationCallback(
1637
- db.user.relations.messages,
1638
- );
1639
-
1640
- it('should invoke callbacks', async () => {
1641
- const chatId = await db.chat.get('id').create(chatData);
1642
- const id = await db.user.get('id').create({ ...userData, age: 1 });
1643
-
1644
- await db.user.find(id).update({
1645
- messages: {
1646
- create: [
1647
- { ...messageData, chatId, text: 'created 1' },
1648
- { ...messageData, chatId, text: 'created 2' },
1649
- ],
1650
- },
1651
- });
1652
-
1653
- expect(beforeCreate).toHaveBeenCalledTimes(1);
1654
- expect(afterCreate).toHaveBeenCalledTimes(1);
1655
- });
1656
- });
1657
- });
1658
- });
1659
- });
1660
-
1661
- describe('hasMany through', () => {
1662
- it('should resolve recursive situation when both tables depends on each other', () => {
1663
- class Post extends BaseTable {
1664
- table = 'post';
1665
- columns = this.setColumns((t) => ({
1666
- id: t.serial().primaryKey(),
1667
- }));
1668
-
1669
- relations = {
1670
- postTags: this.hasMany(() => PostTag, {
1671
- primaryKey: 'id',
1672
- foreignKey: 'postId',
1673
- }),
1674
-
1675
- tags: this.hasMany(() => Tag, {
1676
- through: 'postTags',
1677
- source: 'tag',
1678
- }),
1679
- };
1680
- }
1681
-
1682
- class Tag extends BaseTable {
1683
- table = 'tag';
1684
- columns = this.setColumns((t) => ({
1685
- id: t.serial().primaryKey(),
1686
- }));
1687
-
1688
- relations = {
1689
- postTags: this.hasMany(() => PostTag, {
1690
- primaryKey: 'id',
1691
- foreignKey: 'postId',
1692
- }),
1693
-
1694
- posts: this.hasMany(() => Post, {
1695
- through: 'postTags',
1696
- source: 'post',
1697
- }),
1698
- };
1699
- }
1700
-
1701
- class PostTag extends BaseTable {
1702
- table = 'postTag';
1703
- columns = this.setColumns((t) => ({
1704
- postId: t.integer().foreignKey(() => Post, 'id'),
1705
- tagId: t.integer().foreignKey(() => Tag, 'id'),
1706
- ...t.primaryKey(['postId', 'tagId']),
1707
- }));
1708
-
1709
- relations = {
1710
- post: this.belongsTo(() => Post, {
1711
- primaryKey: 'id',
1712
- foreignKey: 'postId',
1713
- }),
1714
-
1715
- tag: this.belongsTo(() => Tag, {
1716
- primaryKey: 'id',
1717
- foreignKey: 'tagId',
1718
- }),
1719
- };
1720
- }
1721
-
1722
- const db = orchidORM(
1723
- {
1724
- ...pgConfig,
1725
- log: false,
1726
- },
1727
- {
1728
- post: Post,
1729
- tag: Tag,
1730
- postTag: PostTag,
1731
- },
1732
- );
1733
-
1734
- expect(Object.keys(db.post.relations)).toEqual(['postTags', 'tags']);
1735
- expect(Object.keys(db.tag.relations)).toEqual(['postTags', 'posts']);
1736
- });
1737
-
1738
- it('should throw if through relation is not defined', () => {
1739
- class Post extends BaseTable {
1740
- table = 'post';
1741
- columns = this.setColumns((t) => ({
1742
- id: t.serial().primaryKey(),
1743
- }));
1744
-
1745
- relations = {
1746
- tags: this.hasMany(() => Tag, {
1747
- through: 'postTags',
1748
- source: 'tag',
1749
- }),
1750
- };
1751
- }
1752
-
1753
- class Tag extends BaseTable {
1754
- table = 'tag';
1755
- columns = this.setColumns((t) => ({
1756
- id: t.serial().primaryKey(),
1757
- }));
1758
- }
1759
-
1760
- expect(() => {
1761
- orchidORM(
1762
- {
1763
- ...pgConfig,
1764
- log: false,
1765
- },
1766
- {
1767
- post: Post,
1768
- tag: Tag,
1769
- },
1770
- );
1771
- }).toThrow(
1772
- 'Cannot define a `tags` relation on `post`: cannot find `postTags` relation required by the `through` option',
1773
- );
1774
- });
1775
-
1776
- it('should throw if source relation is not defined', () => {
1777
- class Post extends BaseTable {
1778
- table = 'post';
1779
- columns = this.setColumns((t) => ({
1780
- id: t.serial().primaryKey(),
1781
- }));
1782
-
1783
- relations = {
1784
- postTags: this.hasMany(() => PostTag, {
1785
- primaryKey: 'id',
1786
- foreignKey: 'postId',
1787
- }),
1788
-
1789
- tags: this.hasMany(() => Tag, {
1790
- through: 'postTags',
1791
- source: 'tag',
1792
- }),
1793
- };
1794
- }
1795
-
1796
- class Tag extends BaseTable {
1797
- table = 'tag';
1798
- columns = this.setColumns((t) => ({
1799
- id: t.serial().primaryKey(),
1800
- }));
1801
- }
1802
-
1803
- class PostTag extends BaseTable {
1804
- table = 'postTag';
1805
- columns = this.setColumns((t) => ({
1806
- postId: t.integer().foreignKey(() => Post, 'id'),
1807
- tagId: t.integer().foreignKey(() => Tag, 'id'),
1808
- ...t.primaryKey(['postId', 'tagId']),
1809
- }));
1810
- }
1811
-
1812
- expect(() => {
1813
- orchidORM(
1814
- {
1815
- ...pgConfig,
1816
- log: false,
1817
- },
1818
- {
1819
- post: Post,
1820
- tag: Tag,
1821
- postTag: PostTag,
1822
- },
1823
- );
1824
- }).toThrow(
1825
- 'Cannot define a `tags` relation on `post`: cannot find `tag` relation in `postTag` required by the `source` option',
1826
- );
1827
- });
1828
-
1829
- describe('through hasMany', () => {
1830
- it('should have method to query related data', async () => {
1831
- const chatsQuery = db.chat.all();
1832
-
1833
- assertType<
1834
- typeof db.profile.chats,
1835
- RelationQuery<
1836
- 'chats',
1837
- { userId: number | null },
1838
- never,
1839
- typeof chatsQuery,
1840
- false,
1841
- false,
1842
- true
1843
- >
1844
- >();
1845
-
1846
- const query = db.profile.chats({ userId: 1 });
1847
- expectSql(
1848
- query.toSql(),
1849
- `
1850
- SELECT * FROM "chat" AS "chats"
1851
- WHERE EXISTS (
1852
- SELECT 1 FROM "user"
1853
- WHERE EXISTS (
1854
- SELECT 1 FROM "chatUser"
1855
- WHERE "chatUser"."chatId" = "chats"."id"
1856
- AND "chatUser"."userId" = "user"."id"
1857
- LIMIT 1
1858
- )
1859
- AND "user"."id" = $1
1860
- LIMIT 1
1861
- )
1862
- `,
1863
- [1],
1864
- );
1865
- });
1866
-
1867
- it('should handle chained query', () => {
1868
- const query = db.profile
1869
- .where({ bio: 'bio' })
1870
- .chats.where({ title: 'title' });
1871
-
1872
- expectSql(
1873
- query.toSql(),
1874
- `
1875
- SELECT * FROM "chat" AS "chats"
1876
- WHERE EXISTS (
1877
- SELECT 1 FROM "profile"
1878
- WHERE "profile"."bio" = $1
1879
- AND EXISTS (
1880
- SELECT 1 FROM "user"
1881
- WHERE EXISTS (
1882
- SELECT 1 FROM "chatUser"
1883
- WHERE "chatUser"."chatId" = "chats"."id"
1884
- AND "chatUser"."userId" = "user"."id"
1885
- LIMIT 1
1886
- )
1887
- AND "user"."id" = "profile"."userId"
1888
- LIMIT 1
1889
- )
1890
- LIMIT 1
1891
- )
1892
- AND "chats"."title" = $2
1893
- `,
1894
- ['bio', 'title'],
1895
- );
1896
- });
1897
-
1898
- it('should have disabled create method', () => {
1899
- // @ts-expect-error hasMany with through option should not have chained create
1900
- db.profile.chats.create(chatData);
1901
- });
1902
-
1903
- describe('chained delete', () => {
1904
- it('should have chained delete', () => {
1905
- const query = db.profile
1906
- .where({ bio: 'bio' })
1907
- .chats.where({ title: 'title' })
1908
- .delete();
1909
-
1910
- expectSql(
1911
- query.toSql(),
1912
- `
1913
- DELETE FROM "chat" AS "chats"
1914
- WHERE EXISTS (
1915
- SELECT 1 FROM "profile"
1916
- WHERE "profile"."bio" = $1
1917
- AND EXISTS (
1918
- SELECT 1 FROM "user"
1919
- WHERE EXISTS (
1920
- SELECT 1 FROM "chatUser"
1921
- WHERE "chatUser"."chatId" = "chats"."id"
1922
- AND "chatUser"."userId" = "user"."id"
1923
- LIMIT 1
1924
- )
1925
- AND "user"."id" = "profile"."userId"
1926
- LIMIT 1
1927
- )
1928
- LIMIT 1
1929
- )
1930
- AND "chats"."title" = $2
1931
- `,
1932
- ['bio', 'title'],
1933
- );
1934
- });
1935
- });
1936
-
1937
- it('should have proper joinQuery', () => {
1938
- expectSql(
1939
- db.profile.relations.chats
1940
- .joinQuery(db.profile.as('p'), db.chat.as('c'))
1941
- .toSql(),
1942
- `
1943
- SELECT * FROM "chat" AS "c"
1944
- WHERE EXISTS (
1945
- SELECT 1 FROM "user"
1946
- WHERE EXISTS (
1947
- SELECT 1 FROM "chatUser"
1948
- WHERE "chatUser"."chatId" = "c"."id"
1949
- AND "chatUser"."userId" = "user"."id"
1950
- LIMIT 1
1951
- )
1952
- AND "user"."id" = "p"."userId"
1953
- LIMIT 1
1954
- )
1955
- `,
1956
- );
1957
- });
1958
-
1959
- it('should be supported in whereExists', () => {
1960
- expectSql(
1961
- db.profile.whereExists('chats').toSql(),
1962
- `
1963
- SELECT * FROM "profile"
1964
- WHERE EXISTS (
1965
- SELECT 1 FROM "chat" AS "chats"
1966
- WHERE EXISTS (
1967
- SELECT 1 FROM "user"
1968
- WHERE EXISTS (
1969
- SELECT 1 FROM "chatUser"
1970
- WHERE "chatUser"."chatId" = "chats"."id"
1971
- AND "chatUser"."userId" = "user"."id"
1972
- LIMIT 1
1973
- )
1974
- AND "user"."id" = "profile"."userId"
1975
- LIMIT 1
1976
- )
1977
- LIMIT 1
1978
- )
1979
- `,
1980
- );
1981
-
1982
- expectSql(
1983
- db.profile
1984
- .as('p')
1985
- .whereExists('chats', (q) => q.where({ title: 'title' }))
1986
- .toSql(),
1987
- `
1988
- SELECT * FROM "profile" AS "p"
1989
- WHERE EXISTS (
1990
- SELECT 1 FROM "chat" AS "chats"
1991
- WHERE EXISTS (
1992
- SELECT 1 FROM "user"
1993
- WHERE EXISTS (
1994
- SELECT 1 FROM "chatUser"
1995
- WHERE "chatUser"."chatId" = "chats"."id"
1996
- AND "chatUser"."userId" = "user"."id"
1997
- LIMIT 1
1998
- )
1999
- AND "user"."id" = "p"."userId"
2000
- LIMIT 1
2001
- )
2002
- AND "chats"."title" = $1
2003
- LIMIT 1
2004
- )
2005
- `,
2006
- ['title'],
2007
- );
2008
- });
2009
-
2010
- it('should be supported in join', () => {
2011
- const query = db.profile
2012
- .as('p')
2013
- .join('chats', (q) => q.where({ title: 'title' }))
2014
- .select('bio', 'chats.title');
2015
-
2016
- assertType<
2017
- Awaited<typeof query>,
2018
- { bio: string | null; title: string }[]
2019
- >();
2020
-
2021
- expectSql(
2022
- query.toSql(),
2023
- `
2024
- SELECT "p"."bio", "chats"."title" FROM "profile" AS "p"
2025
- JOIN "chat" AS "chats"
2026
- ON EXISTS (
2027
- SELECT 1 FROM "user"
2028
- WHERE EXISTS (
2029
- SELECT 1 FROM "chatUser"
2030
- WHERE "chatUser"."chatId" = "chats"."id"
2031
- AND "chatUser"."userId" = "user"."id"
2032
- LIMIT 1
2033
- )
2034
- AND "user"."id" = "p"."userId"
2035
- LIMIT 1
2036
- )
2037
- AND "chats"."title" = $1
2038
- `,
2039
- ['title'],
2040
- );
2041
- });
2042
-
2043
- describe('select', () => {
2044
- it('should be selectable', () => {
2045
- const query = db.profile.as('p').select('id', {
2046
- chats: (q) => q.chats.where({ title: 'title' }),
2047
- });
2048
-
2049
- assertType<Awaited<typeof query>, { id: number; chats: Chat[] }[]>();
2050
-
2051
- expectSql(
2052
- query.toSql(),
2053
- `
2054
- SELECT
2055
- "p"."id",
2056
- (
2057
- SELECT COALESCE(json_agg(row_to_json("t".*)), '[]')
2058
- FROM (
2059
- SELECT *
2060
- FROM "chat" AS "chats"
2061
- WHERE "chats"."title" = $1
2062
- AND EXISTS (
2063
- SELECT 1 FROM "user"
2064
- WHERE EXISTS (
2065
- SELECT 1 FROM "chatUser"
2066
- WHERE "chatUser"."chatId" = "chats"."id"
2067
- AND "chatUser"."userId" = "user"."id"
2068
- LIMIT 1
2069
- )
2070
- AND "user"."id" = "p"."userId"
2071
- LIMIT 1
2072
- )
2073
- ) AS "t"
2074
- ) AS "chats"
2075
- FROM "profile" AS "p"
2076
- `,
2077
- ['title'],
2078
- );
2079
- });
2080
-
2081
- it('should be selectable by relation name', () => {
2082
- const query = db.profile.select('id', 'chats');
2083
-
2084
- assertType<Awaited<typeof query>, { id: number; chats: Chat[] }[]>();
2085
-
2086
- expectSql(
2087
- query.toSql(),
2088
- `
2089
- SELECT
2090
- "profile"."id",
2091
- (
2092
- SELECT COALESCE(json_agg(row_to_json("t".*)), '[]')
2093
- FROM (
2094
- SELECT *
2095
- FROM "chat" AS "chats"
2096
- WHERE EXISTS (
2097
- SELECT 1 FROM "user"
2098
- WHERE EXISTS (
2099
- SELECT 1 FROM "chatUser"
2100
- WHERE "chatUser"."chatId" = "chats"."id"
2101
- AND "chatUser"."userId" = "user"."id"
2102
- LIMIT 1
2103
- )
2104
- AND "user"."id" = "profile"."userId"
2105
- LIMIT 1
2106
- )
2107
- ) AS "t"
2108
- ) AS "chats"
2109
- FROM "profile"
2110
- `,
2111
- [],
2112
- );
2113
- });
2114
- });
2115
-
2116
- it('should allow to select count', () => {
2117
- const query = db.profile.as('p').select('id', {
2118
- chatsCount: (q) => q.chats.count(),
2119
- });
2120
-
2121
- assertType<Awaited<typeof query>, { id: number; chatsCount: number }[]>();
2122
-
2123
- expectSql(
2124
- query.toSql(),
2125
- `
2126
- SELECT
2127
- "p"."id",
2128
- (
2129
- SELECT count(*)
2130
- FROM "chat" AS "chats"
2131
- WHERE EXISTS (
2132
- SELECT 1 FROM "user"
2133
- WHERE EXISTS (
2134
- SELECT 1 FROM "chatUser"
2135
- WHERE "chatUser"."chatId" = "chats"."id"
2136
- AND "chatUser"."userId" = "user"."id"
2137
- LIMIT 1
2138
- )
2139
- AND "user"."id" = "p"."userId"
2140
- LIMIT 1
2141
- )
2142
- ) AS "chatsCount"
2143
- FROM "profile" AS "p"
2144
- `,
2145
- );
2146
- });
2147
-
2148
- it('should allow to pluck values', () => {
2149
- const query = db.profile.as('p').select('id', {
2150
- titles: (q) => q.chats.pluck('title'),
2151
- });
2152
-
2153
- assertType<Awaited<typeof query>, { id: number; titles: string[] }[]>();
2154
-
2155
- expectSql(
2156
- query.toSql(),
2157
- `
2158
- SELECT
2159
- "p"."id",
2160
- (
2161
- SELECT COALESCE(json_agg("c"), '[]')
2162
- FROM (
2163
- SELECT "chats"."title" AS "c"
2164
- FROM "chat" AS "chats"
2165
- WHERE EXISTS (
2166
- SELECT 1 FROM "user"
2167
- WHERE EXISTS (
2168
- SELECT 1 FROM "chatUser"
2169
- WHERE "chatUser"."chatId" = "chats"."id"
2170
- AND "chatUser"."userId" = "user"."id"
2171
- LIMIT 1
2172
- )
2173
- AND "user"."id" = "p"."userId"
2174
- LIMIT 1
2175
- )
2176
- ) AS "t"
2177
- ) AS "titles"
2178
- FROM "profile" AS "p"
2179
- `,
2180
- );
2181
- });
2182
-
2183
- it('should handle exists sub query', () => {
2184
- const query = db.profile.as('p').select('id', {
2185
- hasChats: (q) => q.chats.exists(),
2186
- });
2187
-
2188
- assertType<Awaited<typeof query>, { id: number; hasChats: boolean }[]>();
2189
-
2190
- expectSql(
2191
- query.toSql(),
2192
- `
2193
- SELECT
2194
- "p"."id",
2195
- COALESCE((
2196
- SELECT true
2197
- FROM "chat" AS "chats"
2198
- WHERE EXISTS (
2199
- SELECT 1 FROM "user"
2200
- WHERE EXISTS (
2201
- SELECT 1 FROM "chatUser"
2202
- WHERE "chatUser"."chatId" = "chats"."id"
2203
- AND "chatUser"."userId" = "user"."id"
2204
- LIMIT 1
2205
- )
2206
- AND "user"."id" = "p"."userId"
2207
- LIMIT 1
2208
- )
2209
- ), false) AS "hasChats"
2210
- FROM "profile" AS "p"
2211
- `,
2212
- );
2213
- });
2214
- });
2215
-
2216
- describe('through hasOne', () => {
2217
- it('should have method to query related data', () => {
2218
- const profilesQuery = db.profile.all();
2219
-
2220
- assertType<
2221
- typeof db.chat.profiles,
2222
- RelationQuery<
2223
- 'profiles',
2224
- { id: number },
2225
- never,
2226
- typeof profilesQuery,
2227
- false,
2228
- false,
2229
- true
2230
- >
2231
- >();
2232
-
2233
- const query = db.chat.profiles({ id: 1 });
2234
- expectSql(
2235
- query.toSql(),
2236
- `
2237
- SELECT * FROM "profile" AS "profiles"
2238
- WHERE EXISTS (
2239
- SELECT 1 FROM "user" AS "users"
2240
- WHERE "profiles"."userId" = "users"."id"
2241
- AND EXISTS (
2242
- SELECT 1 FROM "chatUser"
2243
- WHERE "chatUser"."userId" = "users"."id"
2244
- AND "chatUser"."chatId" = $1
2245
- LIMIT 1
2246
- )
2247
- LIMIT 1
2248
- )
2249
- `,
2250
- [1],
2251
- );
2252
- });
2253
-
2254
- it('should handle chained query', () => {
2255
- const query = db.chat
2256
- .where({ title: 'title' })
2257
- .profiles.where({ bio: 'bio' });
2258
-
2259
- expectSql(
2260
- query.toSql(),
2261
- `
2262
- SELECT * FROM "profile" AS "profiles"
2263
- WHERE EXISTS (
2264
- SELECT 1 FROM "chat"
2265
- WHERE "chat"."title" = $1
2266
- AND EXISTS (
2267
- SELECT 1 FROM "user" AS "users"
2268
- WHERE "profiles"."userId" = "users"."id"
2269
- AND EXISTS (
2270
- SELECT 1 FROM "chatUser"
2271
- WHERE "chatUser"."userId" = "users"."id"
2272
- AND "chatUser"."chatId" = "chat"."id"
2273
- LIMIT 1
2274
- )
2275
- LIMIT 1
2276
- )
2277
- LIMIT 1
2278
- )
2279
- AND "profiles"."bio" = $2
2280
- `,
2281
- ['title', 'bio'],
2282
- );
2283
- });
2284
-
2285
- it('should have disabled create method', () => {
2286
- // @ts-expect-error hasMany with through option should not have chained create
2287
- db.chat.profiles.create(chatData);
2288
- });
2289
-
2290
- it('should have chained delete', () => {
2291
- const query = db.chat
2292
- .where({ title: 'title' })
2293
- .profiles.where({ bio: 'bio' })
2294
- .delete();
2295
-
2296
- expectSql(
2297
- query.toSql(),
2298
- `
2299
- DELETE FROM "profile" AS "profiles"
2300
- WHERE EXISTS (
2301
- SELECT 1 FROM "chat"
2302
- WHERE "chat"."title" = $1
2303
- AND EXISTS (
2304
- SELECT 1 FROM "user" AS "users"
2305
- WHERE "profiles"."userId" = "users"."id"
2306
- AND EXISTS (
2307
- SELECT 1 FROM "chatUser"
2308
- WHERE "chatUser"."userId" = "users"."id"
2309
- AND "chatUser"."chatId" = "chat"."id"
2310
- LIMIT 1
2311
- )
2312
- LIMIT 1
2313
- )
2314
- LIMIT 1
2315
- )
2316
- AND "profiles"."bio" = $2
2317
- `,
2318
- ['title', 'bio'],
2319
- );
2320
- });
2321
-
2322
- it('should have proper joinQuery', () => {
2323
- expectSql(
2324
- db.chat.relations.profiles
2325
- .joinQuery(db.chat.as('c'), db.profile.as('p'))
2326
- .toSql(),
2327
- `
2328
- SELECT * FROM "profile" AS "p"
2329
- WHERE EXISTS (
2330
- SELECT 1 FROM "user" AS "users"
2331
- WHERE "p"."userId" = "users"."id"
2332
- AND EXISTS (
2333
- SELECT 1 FROM "chatUser"
2334
- WHERE "chatUser"."userId" = "users"."id"
2335
- AND "chatUser"."chatId" = "c"."id"
2336
- LIMIT 1
2337
- )
2338
- LIMIT 1
2339
- )
2340
- `,
2341
- );
2342
- });
2343
-
2344
- it('should be supported in whereExists', () => {
2345
- expectSql(
2346
- db.chat.whereExists('profiles').toSql(),
2347
- `
2348
- SELECT * FROM "chat"
2349
- WHERE EXISTS (
2350
- SELECT 1 FROM "profile" AS "profiles"
2351
- WHERE EXISTS (
2352
- SELECT 1 FROM "user" AS "users"
2353
- WHERE "profiles"."userId" = "users"."id"
2354
- AND EXISTS (
2355
- SELECT 1 FROM "chatUser"
2356
- WHERE "chatUser"."userId" = "users"."id"
2357
- AND "chatUser"."chatId" = "chat"."id"
2358
- LIMIT 1
2359
- )
2360
- LIMIT 1
2361
- )
2362
- LIMIT 1
2363
- )
2364
- `,
2365
- );
2366
-
2367
- expectSql(
2368
- db.chat
2369
- .as('c')
2370
- .whereExists('profiles', (q) => q.where({ bio: 'bio' }))
2371
- .toSql(),
2372
- `
2373
- SELECT * FROM "chat" AS "c"
2374
- WHERE EXISTS (
2375
- SELECT 1 FROM "profile" AS "profiles"
2376
- WHERE EXISTS (
2377
- SELECT 1 FROM "user" AS "users"
2378
- WHERE "profiles"."userId" = "users"."id"
2379
- AND EXISTS (
2380
- SELECT 1 FROM "chatUser"
2381
- WHERE "chatUser"."userId" = "users"."id"
2382
- AND "chatUser"."chatId" = "c"."id"
2383
- LIMIT 1
2384
- )
2385
- LIMIT 1
2386
- )
2387
- AND "profiles"."bio" = $1
2388
- LIMIT 1
2389
- )
2390
- `,
2391
- ['bio'],
2392
- );
2393
- });
2394
-
2395
- it('should be supported in join', () => {
2396
- const query = db.chat
2397
- .as('c')
2398
- .join('profiles', (q) => q.where({ bio: 'bio' }))
2399
- .select('title', 'profiles.bio');
2400
-
2401
- assertType<
2402
- Awaited<typeof query>,
2403
- { title: string; bio: string | null }[]
2404
- >();
2405
-
2406
- expectSql(
2407
- query.toSql(),
2408
- `
2409
- SELECT "c"."title", "profiles"."bio" FROM "chat" AS "c"
2410
- JOIN "profile" AS "profiles"
2411
- ON EXISTS (
2412
- SELECT 1 FROM "user" AS "users"
2413
- WHERE "profiles"."userId" = "users"."id"
2414
- AND EXISTS (
2415
- SELECT 1 FROM "chatUser"
2416
- WHERE "chatUser"."userId" = "users"."id"
2417
- AND "chatUser"."chatId" = "c"."id"
2418
- LIMIT 1
2419
- )
2420
- LIMIT 1
2421
- )
2422
- AND "profiles"."bio" = $1
2423
- `,
2424
- ['bio'],
2425
- );
2426
- });
2427
-
2428
- describe('select', () => {
2429
- it('should be selectable', () => {
2430
- const query = db.chat.as('c').select('id', {
2431
- profiles: (q) => q.profiles.where({ bio: 'bio' }),
2432
- });
2433
-
2434
- assertType<
2435
- Awaited<typeof query>,
2436
- { id: number; profiles: Profile[] }[]
2437
- >();
2438
-
2439
- expectSql(
2440
- query.toSql(),
2441
- `
2442
- SELECT
2443
- "c"."id",
2444
- (
2445
- SELECT COALESCE(json_agg(row_to_json("t".*)), '[]')
2446
- FROM (
2447
- SELECT *
2448
- FROM "profile" AS "profiles"
2449
- WHERE "profiles"."bio" = $1
2450
- AND EXISTS (
2451
- SELECT 1 FROM "user" AS "users"
2452
- WHERE "profiles"."userId" = "users"."id"
2453
- AND EXISTS (
2454
- SELECT 1 FROM "chatUser"
2455
- WHERE "chatUser"."userId" = "users"."id"
2456
- AND "chatUser"."chatId" = "c"."id"
2457
- LIMIT 1
2458
- )
2459
- LIMIT 1
2460
- )
2461
- ) AS "t"
2462
- ) AS "profiles"
2463
- FROM "chat" AS "c"
2464
- `,
2465
- ['bio'],
2466
- );
2467
- });
2468
-
2469
- it('should be selectable by relation name', () => {
2470
- const query = db.chat.select('id', 'profiles');
2471
-
2472
- assertType<
2473
- Awaited<typeof query>,
2474
- { id: number; profiles: Profile[] }[]
2475
- >();
2476
-
2477
- expectSql(
2478
- query.toSql(),
2479
- `
2480
- SELECT
2481
- "chat"."id",
2482
- (
2483
- SELECT COALESCE(json_agg(row_to_json("t".*)), '[]')
2484
- FROM (
2485
- SELECT *
2486
- FROM "profile" AS "profiles"
2487
- WHERE EXISTS (
2488
- SELECT 1 FROM "user" AS "users"
2489
- WHERE "profiles"."userId" = "users"."id"
2490
- AND EXISTS (
2491
- SELECT 1 FROM "chatUser"
2492
- WHERE "chatUser"."userId" = "users"."id"
2493
- AND "chatUser"."chatId" = "chat"."id"
2494
- LIMIT 1
2495
- )
2496
- LIMIT 1
2497
- )
2498
- ) AS "t"
2499
- ) AS "profiles"
2500
- FROM "chat"
2501
- `,
2502
- [],
2503
- );
2504
- });
2505
-
2506
- it('should allow to select count', () => {
2507
- const query = db.chat.as('c').select('id', {
2508
- profilesCount: (q) => q.profiles.count(),
2509
- });
2510
-
2511
- assertType<
2512
- Awaited<typeof query>,
2513
- { id: number; profilesCount: number }[]
2514
- >();
2515
-
2516
- expectSql(
2517
- query.toSql(),
2518
- `
2519
- SELECT
2520
- "c"."id",
2521
- (
2522
- SELECT count(*)
2523
- FROM "profile" AS "profiles"
2524
- WHERE EXISTS (
2525
- SELECT 1 FROM "user" AS "users"
2526
- WHERE "profiles"."userId" = "users"."id"
2527
- AND EXISTS (
2528
- SELECT 1 FROM "chatUser"
2529
- WHERE "chatUser"."userId" = "users"."id"
2530
- AND "chatUser"."chatId" = "c"."id"
2531
- LIMIT 1
2532
- )
2533
- LIMIT 1
2534
- )
2535
- ) AS "profilesCount"
2536
- FROM "chat" AS "c"
2537
- `,
2538
- [],
2539
- );
2540
- });
2541
-
2542
- it('should allow to pluck values', () => {
2543
- const query = db.chat.as('c').select('id', {
2544
- bios: (q) => q.profiles.pluck('bio'),
2545
- });
2546
-
2547
- assertType<
2548
- Awaited<typeof query>,
2549
- { id: number; bios: (string | null)[] }[]
2550
- >();
2551
-
2552
- expectSql(
2553
- query.toSql(),
2554
- `
2555
- SELECT
2556
- "c"."id",
2557
- (
2558
- SELECT COALESCE(json_agg("c"), '[]')
2559
- FROM (
2560
- SELECT "profiles"."bio" AS "c"
2561
- FROM "profile" AS "profiles"
2562
- WHERE EXISTS (
2563
- SELECT 1 FROM "user" AS "users"
2564
- WHERE "profiles"."userId" = "users"."id"
2565
- AND EXISTS (
2566
- SELECT 1 FROM "chatUser"
2567
- WHERE "chatUser"."userId" = "users"."id"
2568
- AND "chatUser"."chatId" = "c"."id"
2569
- LIMIT 1
2570
- )
2571
- LIMIT 1
2572
- )
2573
- ) AS "t"
2574
- ) AS "bios"
2575
- FROM "chat" AS "c"
2576
- `,
2577
- );
2578
- });
2579
-
2580
- it('should handle exists sub query', () => {
2581
- const query = db.chat.as('c').select('id', {
2582
- hasProfiles: (q) => q.profiles.exists(),
2583
- });
2584
-
2585
- assertType<
2586
- Awaited<typeof query>,
2587
- { id: number; hasProfiles: boolean }[]
2588
- >();
2589
-
2590
- expectSql(
2591
- query.toSql(),
2592
- `
2593
- SELECT
2594
- "c"."id",
2595
- COALESCE((
2596
- SELECT true
2597
- FROM "profile" AS "profiles"
2598
- WHERE EXISTS (
2599
- SELECT 1 FROM "user" AS "users"
2600
- WHERE "profiles"."userId" = "users"."id"
2601
- AND EXISTS (
2602
- SELECT 1 FROM "chatUser"
2603
- WHERE "chatUser"."userId" = "users"."id"
2604
- AND "chatUser"."chatId" = "c"."id"
2605
- LIMIT 1
2606
- )
2607
- LIMIT 1
2608
- )
2609
- ), false) AS "hasProfiles"
2610
- FROM "chat" AS "c"
2611
- `,
2612
- );
2613
- });
2614
- });
2615
- });
2616
- });