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,1335 +0,0 @@
1
- import { db } from '../test-utils/test-db';
2
- import {
3
- chatData,
4
- expectSql,
5
- userData,
6
- useTestDatabase,
7
- now,
8
- assertType,
9
- useRelationCallback,
10
- } from '../test-utils/test-utils';
11
- import { RelationQuery, Sql, TransactionAdapter } from 'pqb';
12
- import { Chat, User } from '../test-utils/test-tables';
13
-
14
- describe('hasAndBelongsToMany', () => {
15
- useTestDatabase();
16
-
17
- describe('querying', () => {
18
- it('should have method to query related data', async () => {
19
- const chatsQuery = db.chat.all();
20
-
21
- assertType<
22
- typeof db.user.chats,
23
- RelationQuery<
24
- 'chats',
25
- { id: number },
26
- never,
27
- typeof chatsQuery,
28
- false,
29
- true,
30
- true
31
- >
32
- >();
33
-
34
- const userId = await db.user.get('id').create({
35
- ...userData,
36
- chats: {
37
- create: [chatData, chatData],
38
- },
39
- });
40
-
41
- const user = await db.user.find(userId);
42
- const query = db.user.chats(user);
43
-
44
- expectSql(
45
- query.toSql(),
46
- `
47
- SELECT * FROM "chat" AS "chats"
48
- WHERE EXISTS (
49
- SELECT 1 FROM "chatUser"
50
- WHERE "chatUser"."chatId" = "chats"."id"
51
- AND "chatUser"."userId" = $1
52
- LIMIT 1
53
- )
54
- `,
55
- [userId],
56
- );
57
-
58
- const messages = await query;
59
-
60
- expect(messages).toMatchObject([chatData, chatData]);
61
- });
62
-
63
- it('should handle chained query', () => {
64
- const query = db.user
65
- .where({ name: 'name' })
66
- .chats.where({ title: 'title' });
67
-
68
- expectSql(
69
- query.toSql(),
70
- `
71
- SELECT * FROM "chat" AS "chats"
72
- WHERE EXISTS (
73
- SELECT 1 FROM "user"
74
- WHERE "user"."name" = $1
75
- AND EXISTS (
76
- SELECT 1 FROM "chatUser"
77
- WHERE "chatUser"."chatId" = "chats"."id"
78
- AND "chatUser"."userId" = "user"."id"
79
- LIMIT 1
80
- )
81
- LIMIT 1
82
- )
83
- AND "chats"."title" = $2
84
- `,
85
- ['name', 'title'],
86
- );
87
- });
88
-
89
- describe('create based on a query', () => {
90
- it('should have create based on find query', async () => {
91
- const user = await db.user.create(userData);
92
-
93
- const chat = await db.user.find(user.id).chats.create({
94
- title: 'title',
95
- });
96
-
97
- expect(chat.title).toBe('title');
98
- const ids = await db.user.chats(user).pluck('id');
99
- expect(ids).toEqual([chat.id]);
100
- });
101
-
102
- it('should throw not found when not found even when searching with findOptional', async () => {
103
- const query = db.user.findOptional(1).chats.create({
104
- title: 'title',
105
- });
106
-
107
- await expect(() => query).rejects.toThrow('Record is not found');
108
- });
109
-
110
- it('should throw when the main query returns many records', async () => {
111
- await expect(() =>
112
- db.user.chats.create({
113
- title: 'title',
114
- }),
115
- ).rejects.toThrow(
116
- 'Cannot create based on a query which returns multiple records',
117
- );
118
- });
119
- });
120
-
121
- it('should have chained delete method', () => {
122
- const query = db.user
123
- .where({ name: 'name' })
124
- .chats.where({ title: 'title' })
125
- .delete();
126
-
127
- expectSql(
128
- query.toSql(),
129
- `
130
- DELETE FROM "chat" AS "chats"
131
- WHERE EXISTS (
132
- SELECT 1 FROM "user"
133
- WHERE "user"."name" = $1
134
- AND EXISTS (
135
- SELECT 1 FROM "chatUser"
136
- WHERE "chatUser"."chatId" = "chats"."id"
137
- AND "chatUser"."userId" = "user"."id"
138
- LIMIT 1
139
- )
140
- LIMIT 1
141
- )
142
- AND "chats"."title" = $2
143
- `,
144
- ['name', 'title'],
145
- );
146
- });
147
-
148
- it('should have proper joinQuery', () => {
149
- expectSql(
150
- db.user.relations.chats
151
- .joinQuery(db.user.as('u'), db.chat.as('c'))
152
- .toSql(),
153
- `
154
- SELECT * FROM "chat" AS "c"
155
- WHERE EXISTS (
156
- SELECT 1 FROM "chatUser"
157
- WHERE "chatUser"."chatId" = "c"."id"
158
- AND "chatUser"."userId" = "u"."id"
159
- LIMIT 1
160
- )
161
- `,
162
- );
163
- });
164
-
165
- it('should be supported in whereExists', () => {
166
- expectSql(
167
- db.user.whereExists('chats').toSql(),
168
- `
169
- SELECT * FROM "user"
170
- WHERE EXISTS (
171
- SELECT 1 FROM "chat" AS "chats"
172
- WHERE EXISTS (
173
- SELECT 1 FROM "chatUser"
174
- WHERE "chatUser"."chatId" = "chats"."id"
175
- AND "chatUser"."userId" = "user"."id"
176
- LIMIT 1
177
- )
178
- LIMIT 1
179
- )
180
- `,
181
- );
182
-
183
- expectSql(
184
- db.user
185
- .as('u')
186
- .whereExists('chats', (q) => q.where({ title: 'title' }))
187
- .toSql(),
188
- `
189
- SELECT * FROM "user" AS "u"
190
- WHERE EXISTS (
191
- SELECT 1 FROM "chat" AS "chats"
192
- WHERE
193
- EXISTS (
194
- SELECT 1 FROM "chatUser"
195
- WHERE "chatUser"."chatId" = "chats"."id"
196
- AND "chatUser"."userId" = "u"."id"
197
- LIMIT 1
198
- )
199
- AND "chats"."title" = $1
200
- LIMIT 1
201
- )
202
- `,
203
- ['title'],
204
- );
205
- });
206
-
207
- it('should be supported in join', () => {
208
- const query = db.user
209
- .as('u')
210
- .join('chats', (q) => q.where({ title: 'title' }))
211
- .select('name', 'chats.title');
212
-
213
- assertType<Awaited<typeof query>, { name: string; title: string }[]>();
214
-
215
- expectSql(
216
- query.toSql(),
217
- `
218
- SELECT "u"."name", "chats"."title" FROM "user" AS "u"
219
- JOIN "chat" AS "chats"
220
- ON EXISTS (
221
- SELECT 1 FROM "chatUser"
222
- WHERE "chatUser"."chatId" = "chats"."id"
223
- AND "chatUser"."userId" = "u"."id"
224
- LIMIT 1
225
- )
226
- AND "chats"."title" = $1
227
- `,
228
- ['title'],
229
- );
230
- });
231
-
232
- describe('select', () => {
233
- it('should be selectable', () => {
234
- const query = db.user.as('u').select('id', {
235
- chats: (q) => q.chats.select('id', 'title').where({ title: 'title' }),
236
- });
237
-
238
- assertType<
239
- Awaited<typeof query>,
240
- { id: number; chats: { id: number; title: string }[] }[]
241
- >();
242
-
243
- expectSql(
244
- query.toSql(),
245
- `
246
- SELECT
247
- "u"."id",
248
- (
249
- SELECT COALESCE(json_agg(row_to_json("t".*)), '[]')
250
- FROM (
251
- SELECT "chats"."id", "chats"."title" FROM "chat" AS "chats"
252
- WHERE "chats"."title" = $1
253
- AND EXISTS (
254
- SELECT 1 FROM "chatUser"
255
- WHERE "chatUser"."chatId" = "chats"."id"
256
- AND "chatUser"."userId" = "u"."id"
257
- LIMIT 1
258
- )
259
- ) AS "t"
260
- ) AS "chats"
261
- FROM "user" AS "u"
262
- `,
263
- ['title'],
264
- );
265
- });
266
-
267
- it('should be selectable by relation name', () => {
268
- const query = db.user.select('id', 'chats');
269
-
270
- assertType<Awaited<typeof query>, { id: number; chats: Chat[] }[]>();
271
-
272
- expectSql(
273
- query.toSql(),
274
- `
275
- SELECT
276
- "user"."id",
277
- (
278
- SELECT COALESCE(json_agg(row_to_json("t".*)), '[]')
279
- FROM (
280
- SELECT * FROM "chat" AS "chats"
281
- WHERE EXISTS (
282
- SELECT 1 FROM "chatUser"
283
- WHERE "chatUser"."chatId" = "chats"."id"
284
- AND "chatUser"."userId" = "user"."id"
285
- LIMIT 1
286
- )
287
- ) AS "t"
288
- ) AS "chats"
289
- FROM "user"
290
- `,
291
- );
292
- });
293
- });
294
-
295
- it('should allow to select count', () => {
296
- const query = db.user.as('u').select('id', {
297
- chatsCount: (q) => q.chats.count(),
298
- });
299
-
300
- assertType<Awaited<typeof query>, { id: number; chatsCount: number }[]>();
301
-
302
- expectSql(
303
- query.toSql(),
304
- `
305
- SELECT
306
- "u"."id",
307
- (
308
- SELECT count(*) FROM "chat" AS "chats"
309
- WHERE EXISTS (
310
- SELECT 1 FROM "chatUser"
311
- WHERE "chatUser"."chatId" = "chats"."id"
312
- AND "chatUser"."userId" = "u"."id"
313
- LIMIT 1
314
- )
315
- ) AS "chatsCount"
316
- FROM "user" AS "u"
317
- `,
318
- );
319
- });
320
-
321
- it('should allow to pluck values', () => {
322
- const query = db.user.as('u').select('id', {
323
- titles: (q) => q.chats.pluck('title'),
324
- });
325
-
326
- assertType<Awaited<typeof query>, { id: number; titles: string[] }[]>();
327
-
328
- expectSql(
329
- query.toSql(),
330
- `
331
- SELECT
332
- "u"."id",
333
- (
334
- SELECT COALESCE(json_agg("c"), '[]')
335
- FROM (
336
- SELECT "chats"."title" AS "c"
337
- FROM "chat" AS "chats"
338
- WHERE EXISTS (
339
- SELECT 1 FROM "chatUser"
340
- WHERE "chatUser"."chatId" = "chats"."id"
341
- AND "chatUser"."userId" = "u"."id"
342
- LIMIT 1
343
- )
344
- ) AS "t"
345
- ) AS "titles"
346
- FROM "user" AS "u"
347
- `,
348
- );
349
- });
350
-
351
- it('should handle exists sub query', () => {
352
- const query = db.user.as('u').select('id', {
353
- hasChats: (q) => q.chats.exists(),
354
- });
355
-
356
- assertType<Awaited<typeof query>, { id: number; hasChats: boolean }[]>();
357
-
358
- expectSql(
359
- query.toSql(),
360
- `
361
- SELECT
362
- "u"."id",
363
- COALESCE((
364
- SELECT true
365
- FROM "chat" AS "chats"
366
- WHERE EXISTS (
367
- SELECT 1 FROM "chatUser"
368
- WHERE "chatUser"."chatId" = "chats"."id"
369
- AND "chatUser"."userId" = "u"."id"
370
- LIMIT 1
371
- )
372
- ), false) AS "hasChats"
373
- FROM "user" AS "u"
374
- `,
375
- );
376
- });
377
- });
378
-
379
- describe('create', () => {
380
- afterEach(() => {
381
- jest.clearAllMocks();
382
- });
383
-
384
- const checkUserAndChats = ({
385
- user,
386
- chats,
387
- name,
388
- title1,
389
- title2,
390
- }: {
391
- user: User;
392
- chats: Chat[];
393
- name: string;
394
- title1: string;
395
- title2: string;
396
- }) => {
397
- expect(user).toEqual({
398
- ...userData,
399
- active: null,
400
- age: null,
401
- data: null,
402
- picture: null,
403
- id: user.id,
404
- name,
405
- });
406
-
407
- expect(chats[0]).toEqual({
408
- ...chatData,
409
- id: chats[0].id,
410
- title: title1,
411
- });
412
-
413
- expect(chats[1]).toEqual({
414
- ...chatData,
415
- id: chats[1].id,
416
- title: title2,
417
- });
418
- };
419
-
420
- describe('nested create', () => {
421
- it('should support create', async () => {
422
- const query = db.user.select('id').create({
423
- ...userData,
424
- name: 'user 1',
425
- chats: {
426
- create: [
427
- {
428
- ...chatData,
429
- title: 'chat 1',
430
- },
431
- {
432
- ...chatData,
433
- title: 'chat 2',
434
- },
435
- ],
436
- },
437
- });
438
-
439
- const querySpy = jest.spyOn(TransactionAdapter.prototype, 'query');
440
- const arraysSpy = jest.spyOn(TransactionAdapter.prototype, 'arrays');
441
-
442
- const user = await query;
443
- const chatIds = await db.user.chats(user).order('id').pluck('id');
444
-
445
- const [createUserSql, createChatsSql] = querySpy.mock.calls.map(
446
- (item) => item[0],
447
- );
448
- const createChatUserSql = arraysSpy.mock.calls[0][0];
449
-
450
- expectSql(
451
- createUserSql as Sql,
452
- `
453
- INSERT INTO "user"("name", "password", "updatedAt", "createdAt")
454
- VALUES ($1, $2, $3, $4)
455
- RETURNING "user"."id"
456
- `,
457
- ['user 1', 'password', now, now],
458
- );
459
-
460
- expectSql(
461
- createChatsSql as Sql,
462
- `
463
- INSERT INTO "chat"("title", "updatedAt", "createdAt")
464
- VALUES ($1, $2, $3), ($4, $5, $6)
465
- RETURNING "chat"."id"
466
- `,
467
- ['chat 1', now, now, 'chat 2', now, now],
468
- );
469
-
470
- expectSql(
471
- createChatUserSql as Sql,
472
- `
473
- INSERT INTO "chatUser"("userId", "chatId")
474
- VALUES ($1, $2), ($3, $4)
475
- `,
476
- [user.id, chatIds[0], user.id, chatIds[1]],
477
- );
478
- });
479
-
480
- it('should support create many', async () => {
481
- const query = db.user.select('id').createMany([
482
- {
483
- ...userData,
484
- name: 'user 1',
485
- chats: {
486
- create: [
487
- {
488
- ...chatData,
489
- title: 'chat 1',
490
- },
491
- {
492
- ...chatData,
493
- title: 'chat 2',
494
- },
495
- ],
496
- },
497
- },
498
- {
499
- ...userData,
500
- name: 'user 2',
501
- chats: {
502
- create: [
503
- {
504
- ...chatData,
505
- title: 'chat 3',
506
- },
507
- {
508
- ...chatData,
509
- title: 'chat 4',
510
- },
511
- ],
512
- },
513
- },
514
- ]);
515
-
516
- const querySpy = jest.spyOn(TransactionAdapter.prototype, 'query');
517
- const arraysSpy = jest.spyOn(TransactionAdapter.prototype, 'arrays');
518
-
519
- const users = await query;
520
- const chatIds = await db.user.join('chats').pluck('chats.id');
521
-
522
- const [createUserSql, createChatsSql] = querySpy.mock.calls.map(
523
- (item) => item[0],
524
- );
525
- const createChatUserSql = arraysSpy.mock.calls[0][0];
526
-
527
- expectSql(
528
- createUserSql as Sql,
529
- `
530
- INSERT INTO "user"("name", "password", "updatedAt", "createdAt")
531
- VALUES ($1, $2, $3, $4), ($5, $6, $7, $8)
532
- RETURNING "user"."id"
533
- `,
534
- ['user 1', 'password', now, now, 'user 2', 'password', now, now],
535
- );
536
-
537
- expectSql(
538
- createChatsSql as Sql,
539
- `
540
- INSERT INTO "chat"("title", "updatedAt", "createdAt")
541
- VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9), ($10, $11, $12)
542
- RETURNING "chat"."id"
543
- `,
544
- [
545
- 'chat 1',
546
- now,
547
- now,
548
- 'chat 2',
549
- now,
550
- now,
551
- 'chat 3',
552
- now,
553
- now,
554
- 'chat 4',
555
- now,
556
- now,
557
- ],
558
- );
559
-
560
- expectSql(
561
- createChatUserSql as Sql,
562
- `
563
- INSERT INTO "chatUser"("userId", "chatId")
564
- VALUES ($1, $2), ($3, $4), ($5, $6), ($7, $8)
565
- `,
566
- [
567
- users[0].id,
568
- chatIds[0],
569
- users[0].id,
570
- chatIds[1],
571
- users[1].id,
572
- chatIds[2],
573
- users[1].id,
574
- chatIds[3],
575
- ],
576
- );
577
- });
578
-
579
- it('should ignore empty create list', async () => {
580
- await db.user.create({
581
- ...userData,
582
- chats: {
583
- create: [],
584
- },
585
- });
586
- });
587
-
588
- describe('relation callbacks', () => {
589
- const { beforeCreate, afterCreate, resetMocks } = useRelationCallback(
590
- db.user.relations.chats,
591
- );
592
-
593
- const data = {
594
- ...userData,
595
- chats: {
596
- create: [chatData, chatData],
597
- },
598
- };
599
-
600
- it('should invoke callbacks', async () => {
601
- await db.user.create(data);
602
-
603
- expect(beforeCreate).toHaveBeenCalledTimes(1);
604
- expect(afterCreate).toHaveBeenCalledTimes(1);
605
- });
606
-
607
- it('should invoke callbacks in a batch create', async () => {
608
- resetMocks();
609
-
610
- await db.user.createMany([data, data]);
611
-
612
- expect(beforeCreate).toHaveBeenCalledTimes(1);
613
- expect(afterCreate).toHaveBeenCalledTimes(1);
614
- });
615
- });
616
- });
617
-
618
- describe('nested connect', () => {
619
- it('should support connect', async () => {
620
- await db.chat.createMany([
621
- { ...chatData, title: 'chat 1' },
622
- { ...chatData, title: 'chat 2' },
623
- ]);
624
-
625
- const query = db.user.select('id').create({
626
- ...userData,
627
- name: 'user 1',
628
- chats: {
629
- connect: [
630
- {
631
- title: 'chat 1',
632
- },
633
- {
634
- title: 'chat 2',
635
- },
636
- ],
637
- },
638
- });
639
-
640
- const querySpy = jest.spyOn(TransactionAdapter.prototype, 'query');
641
- const arraysSpy = jest.spyOn(TransactionAdapter.prototype, 'arrays');
642
-
643
- const user = await query;
644
- const chatIds = await db.user.chats(user).order('id').pluck('id');
645
-
646
- const [createUserSql, ...findChatsSql] = querySpy.mock.calls.map(
647
- (item) => item[0],
648
- );
649
- const createChatUserSql = arraysSpy.mock.calls[0][0];
650
-
651
- expectSql(
652
- createUserSql as Sql,
653
- `
654
- INSERT INTO "user"("name", "password", "updatedAt", "createdAt")
655
- VALUES ($1, $2, $3, $4)
656
- RETURNING "user"."id"
657
- `,
658
- ['user 1', 'password', now, now],
659
- );
660
-
661
- expect(findChatsSql.length).toBe(2);
662
- findChatsSql.forEach((sql, i) => {
663
- expectSql(
664
- sql as Sql,
665
- `
666
- SELECT "chats"."id" FROM "chat" AS "chats"
667
- WHERE "chats"."title" = $1
668
- LIMIT $2
669
- `,
670
- [`chat ${i + 1}`, 1],
671
- );
672
- });
673
-
674
- expectSql(
675
- createChatUserSql as Sql,
676
- `
677
- INSERT INTO "chatUser"("userId", "chatId")
678
- VALUES ($1, $2), ($3, $4)
679
- `,
680
- [user.id, chatIds[0], user.id, chatIds[1]],
681
- );
682
- });
683
-
684
- it('should support connect many', async () => {
685
- await db.chat.createMany([
686
- { ...chatData, title: 'chat 1' },
687
- { ...chatData, title: 'chat 2' },
688
- { ...chatData, title: 'chat 3' },
689
- { ...chatData, title: 'chat 4' },
690
- ]);
691
-
692
- const query = db.user.select('id').createMany([
693
- {
694
- ...userData,
695
- name: 'user 1',
696
- chats: {
697
- connect: [
698
- {
699
- title: 'chat 1',
700
- },
701
- {
702
- title: 'chat 2',
703
- },
704
- ],
705
- },
706
- },
707
- {
708
- ...userData,
709
- name: 'user 2',
710
- chats: {
711
- connect: [
712
- {
713
- title: 'chat 3',
714
- },
715
- {
716
- title: 'chat 4',
717
- },
718
- ],
719
- },
720
- },
721
- ]);
722
-
723
- const querySpy = jest.spyOn(TransactionAdapter.prototype, 'query');
724
- const arraysSpy = jest.spyOn(TransactionAdapter.prototype, 'arrays');
725
-
726
- const users = await query;
727
- const chatIds = await db.user.join('chats').pluck('chats.id');
728
-
729
- const [createUserSql, ...findChatsSql] = querySpy.mock.calls.map(
730
- (item) => item[0],
731
- );
732
- const createChatUserSql = arraysSpy.mock.calls[0][0];
733
-
734
- expectSql(
735
- createUserSql as Sql,
736
- `
737
- INSERT INTO "user"("name", "password", "updatedAt", "createdAt")
738
- VALUES ($1, $2, $3, $4), ($5, $6, $7, $8)
739
- RETURNING "user"."id"
740
- `,
741
- ['user 1', 'password', now, now, 'user 2', 'password', now, now],
742
- );
743
-
744
- expect(findChatsSql.length).toBe(4);
745
- findChatsSql.forEach((sql, i) => {
746
- expectSql(
747
- sql as Sql,
748
- `
749
- SELECT "chats"."id" FROM "chat" AS "chats"
750
- WHERE "chats"."title" = $1
751
- LIMIT $2
752
- `,
753
- [`chat ${i + 1}`, 1],
754
- );
755
- });
756
-
757
- expectSql(
758
- createChatUserSql as Sql,
759
- `
760
- INSERT INTO "chatUser"("userId", "chatId")
761
- VALUES ($1, $2), ($3, $4), ($5, $6), ($7, $8)
762
- `,
763
- [
764
- users[0].id,
765
- chatIds[0],
766
- users[0].id,
767
- chatIds[1],
768
- users[1].id,
769
- chatIds[2],
770
- users[1].id,
771
- chatIds[3],
772
- ],
773
- );
774
- });
775
-
776
- it('should ignore empty connect list', async () => {
777
- await db.user.create({
778
- ...userData,
779
- chats: {
780
- connect: [],
781
- },
782
- });
783
- });
784
- });
785
-
786
- describe('connectOrCreate', () => {
787
- it('should support connect or create', async () => {
788
- const chatId = await db.chat.get('id').create({
789
- ...chatData,
790
- title: 'chat 1',
791
- });
792
-
793
- const query = db.user.create({
794
- ...userData,
795
- name: 'user 1',
796
- chats: {
797
- connectOrCreate: [
798
- {
799
- where: { title: 'chat 1' },
800
- create: { ...chatData, title: 'chat 1' },
801
- },
802
- {
803
- where: { title: 'chat 2' },
804
- create: { ...chatData, title: 'chat 2' },
805
- },
806
- ],
807
- },
808
- });
809
-
810
- const user = await query;
811
- const chats = await db.user.chats(user).order('title');
812
-
813
- expect(chats[0].id).toBe(chatId);
814
-
815
- checkUserAndChats({
816
- user,
817
- chats,
818
- name: 'user 1',
819
- title1: 'chat 1',
820
- title2: 'chat 2',
821
- });
822
- });
823
-
824
- it('should support connect or create many', async () => {
825
- const [{ id: chat1Id }, { id: chat4Id }] = await db.chat
826
- .select('id')
827
- .createMany([
828
- {
829
- ...chatData,
830
- title: 'chat 1',
831
- },
832
- {
833
- ...chatData,
834
- title: 'chat 4',
835
- },
836
- ]);
837
-
838
- const query = db.user.createMany([
839
- {
840
- ...userData,
841
- name: 'user 1',
842
- chats: {
843
- connectOrCreate: [
844
- {
845
- where: { title: 'chat 1' },
846
- create: { ...chatData, title: 'chat 1' },
847
- },
848
- {
849
- where: { title: 'chat 2' },
850
- create: { ...chatData, title: 'chat 2' },
851
- },
852
- ],
853
- },
854
- },
855
- {
856
- ...userData,
857
- name: 'user 2',
858
- chats: {
859
- connectOrCreate: [
860
- {
861
- where: { title: 'chat 3' },
862
- create: { ...chatData, title: 'chat 3' },
863
- },
864
- {
865
- where: { title: 'chat 4' },
866
- create: { ...chatData, title: 'chat 4' },
867
- },
868
- ],
869
- },
870
- },
871
- ]);
872
-
873
- const users = await query;
874
- const chats = await db.chat.order('title');
875
-
876
- expect(chats[0].id).toBe(chat1Id);
877
- expect(chats[3].id).toBe(chat4Id);
878
-
879
- checkUserAndChats({
880
- user: users[0],
881
- chats: chats.slice(0, 2),
882
- name: 'user 1',
883
- title1: 'chat 1',
884
- title2: 'chat 2',
885
- });
886
-
887
- checkUserAndChats({
888
- user: users[1],
889
- chats: chats.slice(2, 4),
890
- name: 'user 2',
891
- title1: 'chat 3',
892
- title2: 'chat 4',
893
- });
894
- });
895
-
896
- it('should ignore empty connectOrCreate list', async () => {
897
- await db.user.create({
898
- ...userData,
899
- chats: {
900
- connectOrCreate: [],
901
- },
902
- });
903
- });
904
-
905
- describe('relation callbacks', () => {
906
- const { beforeCreate, afterCreate, resetMocks } = useRelationCallback(
907
- db.user.relations.chats,
908
- );
909
-
910
- const data = {
911
- ...userData,
912
- chats: {
913
- connectOrCreate: [
914
- {
915
- where: { title: 'one' },
916
- create: chatData,
917
- },
918
- {
919
- where: { title: 'two' },
920
- create: chatData,
921
- },
922
- ],
923
- },
924
- };
925
-
926
- it('should invoke callbacks', async () => {
927
- await db.user.create(data);
928
-
929
- expect(beforeCreate).toHaveBeenCalledTimes(1);
930
- expect(afterCreate).toHaveBeenCalledTimes(1);
931
- });
932
-
933
- it('should invoke callbacks in a batch create', async () => {
934
- resetMocks();
935
-
936
- await db.user.createMany([data, data]);
937
-
938
- expect(beforeCreate).toHaveBeenCalledTimes(1);
939
- expect(afterCreate).toHaveBeenCalledTimes(1);
940
- });
941
- });
942
- });
943
- });
944
-
945
- describe('update', () => {
946
- describe('disconnect', () => {
947
- it('should delete join table rows', async () => {
948
- const userId = await db.user.get('id').create({
949
- ...userData,
950
- name: 'user',
951
- chats: {
952
- create: [
953
- { ...chatData, title: 'chat 1' },
954
- { ...chatData, title: 'chat 2' },
955
- { ...chatData, title: 'chat 3' },
956
- ],
957
- },
958
- });
959
-
960
- await db.user.where({ id: userId }).update({
961
- chats: {
962
- disconnect: [{ title: 'chat 1' }, { title: 'chat 2' }],
963
- },
964
- });
965
-
966
- const chats = await db.user.chats({ id: userId });
967
- expect(chats.length).toBe(1);
968
- expect(chats[0].title).toEqual('chat 3');
969
- });
970
-
971
- it('should ignore empty list', async () => {
972
- const id = await db.user.get('id').create({
973
- ...userData,
974
- chats: {
975
- create: [{ ...chatData, title: 'chat 1' }],
976
- },
977
- });
978
-
979
- await db.user.find(id).update({
980
- chats: {
981
- disconnect: [],
982
- },
983
- });
984
-
985
- const chats = await db.user.chats({ id }).pluck('title');
986
- expect(chats).toEqual(['chat 1']);
987
- });
988
- });
989
-
990
- describe('set', () => {
991
- it('should delete previous join records and create join records for matching related records', async () => {
992
- const id = await db.user.get('id').create({
993
- ...userData,
994
- chats: {
995
- create: [
996
- { ...chatData, title: 'chat 1' },
997
- { ...chatData, title: 'chat 2' },
998
- ],
999
- },
1000
- });
1001
-
1002
- await db.chat.create({
1003
- ...chatData,
1004
- title: 'chat 3',
1005
- });
1006
-
1007
- await db.user.where({ id }).update({
1008
- chats: {
1009
- set: [{ title: 'chat 2' }, { title: 'chat 3' }],
1010
- },
1011
- });
1012
-
1013
- const chats = await db.user
1014
- .chats({ id })
1015
- .select('title')
1016
- .order('title');
1017
- expect(chats).toEqual([{ title: 'chat 2' }, { title: 'chat 3' }]);
1018
- });
1019
- });
1020
-
1021
- describe('delete', () => {
1022
- it('should delete related records', async () => {
1023
- const id = await db.user.get('id').create({
1024
- ...userData,
1025
- chats: {
1026
- create: [
1027
- { ...chatData, title: 'chat 1' },
1028
- { ...chatData, title: 'chat 2' },
1029
- { ...chatData, title: 'chat 3' },
1030
- ],
1031
- },
1032
- });
1033
-
1034
- await db.user.create({
1035
- ...userData,
1036
- chats: {
1037
- create: [{ ...chatData, title: 'chat 4' }],
1038
- },
1039
- });
1040
-
1041
- await db.user.find(id).update({
1042
- chats: {
1043
- delete: [{ title: 'chat 1' }, { title: 'chat 2' }],
1044
- },
1045
- });
1046
-
1047
- expect(await db.chat.count()).toBe(2);
1048
-
1049
- const chats = await db.user.chats({ id }).select('title');
1050
- expect(chats).toEqual([{ title: 'chat 3' }]);
1051
- });
1052
-
1053
- it('should ignore empty list', async () => {
1054
- const id = await db.user.get('id').create({
1055
- ...userData,
1056
- chats: {
1057
- create: [{ ...chatData, title: 'chat 1' }],
1058
- },
1059
- });
1060
-
1061
- await db.user.find(id).update({
1062
- chats: {
1063
- delete: [],
1064
- },
1065
- });
1066
-
1067
- const chats = await db.user.chats({ id }).pluck('title');
1068
- expect(chats).toEqual(['chat 1']);
1069
- });
1070
-
1071
- describe('relation callbacks', () => {
1072
- const { beforeDelete, afterDelete, resetMocks } = useRelationCallback(
1073
- db.user.relations.chats,
1074
- );
1075
-
1076
- const data = {
1077
- chats: {
1078
- delete: [{ title: 'chat 1' }, { title: 'chat 2' }],
1079
- },
1080
- };
1081
-
1082
- it('should invoke callbacks', async () => {
1083
- const id = await db.user.get('id').create({
1084
- ...userData,
1085
- chats: {
1086
- create: [
1087
- { ...chatData, title: 'chat 1' },
1088
- { ...chatData, title: 'chat 2' },
1089
- ],
1090
- },
1091
- });
1092
-
1093
- await db.user.find(id).update(data);
1094
-
1095
- expect(beforeDelete).toHaveBeenCalledTimes(1);
1096
- expect(afterDelete).toHaveBeenCalledTimes(1);
1097
- });
1098
-
1099
- it('should invoke callbacks in a batch update', async () => {
1100
- resetMocks();
1101
-
1102
- const ids = await db.user.pluck('id').createMany([
1103
- {
1104
- ...userData,
1105
- chats: {
1106
- create: [
1107
- { ...chatData, title: 'chat 1' },
1108
- { ...chatData, title: 'chat 3' },
1109
- ],
1110
- },
1111
- },
1112
- {
1113
- ...userData,
1114
- chats: {
1115
- create: [
1116
- { ...chatData, title: 'chat 2' },
1117
- { ...chatData, title: 'chat 4' },
1118
- ],
1119
- },
1120
- },
1121
- ]);
1122
-
1123
- await db.user.where({ id: { in: ids } }).update(data);
1124
-
1125
- expect(beforeDelete).toHaveBeenCalledTimes(1);
1126
- expect(afterDelete).toHaveBeenCalledTimes(1);
1127
- });
1128
- });
1129
- });
1130
-
1131
- describe('nested update', () => {
1132
- it('should update related records', async () => {
1133
- const id = await db.user.get('id').create({
1134
- ...userData,
1135
- chats: {
1136
- create: [
1137
- { ...chatData, title: 'chat 1' },
1138
- { ...chatData, title: 'chat 2' },
1139
- { ...chatData, title: 'chat 3' },
1140
- ],
1141
- },
1142
- });
1143
-
1144
- await db.user.create({
1145
- ...userData,
1146
- chats: {
1147
- create: [{ ...chatData, title: 'chat 4' }],
1148
- },
1149
- });
1150
-
1151
- await db.user.find(id).update({
1152
- chats: {
1153
- update: {
1154
- where: {
1155
- title: { in: ['chat 2', 'chat 3', 'chat 4'] },
1156
- },
1157
- data: {
1158
- title: 'updated',
1159
- },
1160
- },
1161
- },
1162
- });
1163
-
1164
- const titles = await db.chat.order('id').pluck('title');
1165
- expect(titles).toEqual(['chat 1', 'updated', 'updated', 'chat 4']);
1166
- });
1167
-
1168
- it('should ignore update with empty where list', async () => {
1169
- const id = await db.user.get('id').create({
1170
- ...userData,
1171
- chats: {
1172
- create: [{ ...chatData, title: 'chat 1' }],
1173
- },
1174
- });
1175
-
1176
- await db.user.find(id).update({
1177
- chats: {
1178
- update: {
1179
- where: [],
1180
- data: {
1181
- title: 'updated',
1182
- },
1183
- },
1184
- },
1185
- });
1186
-
1187
- const chats = await db.user.chats({ id }).pluck('title');
1188
- expect(chats).toEqual(['chat 1']);
1189
- });
1190
-
1191
- describe('relation callbacks', () => {
1192
- const { beforeUpdate, afterUpdate, resetMocks } = useRelationCallback(
1193
- db.user.relations.chats,
1194
- );
1195
-
1196
- const data = {
1197
- chats: {
1198
- update: {
1199
- where: [{ title: 'chat 1' }, { title: 'chat 2' }],
1200
- data: { title: 'new title' },
1201
- },
1202
- },
1203
- };
1204
-
1205
- it('should invoke callbacks', async () => {
1206
- const id = await db.user.get('id').create({
1207
- ...userData,
1208
- chats: {
1209
- create: [{ ...chatData, title: 'chat 1' }],
1210
- },
1211
- });
1212
-
1213
- await db.user.find(id).update(data);
1214
-
1215
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
1216
- expect(afterUpdate).toHaveBeenCalledTimes(1);
1217
- });
1218
-
1219
- it('should invoke callbacks in a batch update', async () => {
1220
- const id = await db.user.get('id').createMany([
1221
- {
1222
- ...userData,
1223
- chats: {
1224
- create: [{ ...chatData, title: 'chat 1' }],
1225
- },
1226
- },
1227
- {
1228
- ...userData,
1229
- chats: {
1230
- create: [{ ...chatData, title: 'chat 2' }],
1231
- },
1232
- },
1233
- ]);
1234
-
1235
- resetMocks();
1236
-
1237
- await db.user.find(id).update(data);
1238
-
1239
- expect(beforeUpdate).toHaveBeenCalledTimes(1);
1240
- expect(afterUpdate).toHaveBeenCalledTimes(1);
1241
- });
1242
- });
1243
- });
1244
-
1245
- describe('nested create', () => {
1246
- it('should create many records and connect all found updating with them', async () => {
1247
- const userIds = await db.user
1248
- .pluck('id')
1249
- .createMany([userData, userData]);
1250
-
1251
- await db.user.where({ id: { in: userIds } }).update({
1252
- chats: {
1253
- create: [
1254
- {
1255
- ...chatData,
1256
- title: 'created 1',
1257
- },
1258
- {
1259
- ...chatData,
1260
- title: 'created 2',
1261
- },
1262
- ],
1263
- },
1264
- });
1265
-
1266
- const firstUserChats = await db.user
1267
- .chats({ id: userIds[0] })
1268
- .order('title');
1269
- expect(firstUserChats.map((chat) => chat.title)).toEqual([
1270
- 'created 1',
1271
- 'created 2',
1272
- ]);
1273
-
1274
- const secondUserChats = await db.user
1275
- .chats({ id: userIds[1] })
1276
- .order('title');
1277
- expect(secondUserChats.map((chat) => chat.title)).toEqual([
1278
- 'created 1',
1279
- 'created 2',
1280
- ]);
1281
-
1282
- expect(firstUserChats.map((chat) => chat.id)).toEqual(
1283
- secondUserChats.map((chat) => chat.id),
1284
- );
1285
- });
1286
-
1287
- it('should ignore empty list', async () => {
1288
- const id = await db.user.get('id').create(userData);
1289
-
1290
- await db.user.find(id).update({
1291
- chats: {
1292
- create: [],
1293
- },
1294
- });
1295
-
1296
- const chats = await db.user.chats({ id });
1297
- expect(chats).toEqual([]);
1298
- });
1299
-
1300
- describe('relation callbacks', () => {
1301
- const { beforeCreate, afterCreate, resetMocks } = useRelationCallback(
1302
- db.user.relations.chats,
1303
- );
1304
-
1305
- const data = {
1306
- chats: {
1307
- create: [chatData, chatData],
1308
- },
1309
- };
1310
-
1311
- it('should invoke callbacks', async () => {
1312
- const id = await db.user.get('id').create(userData);
1313
-
1314
- await db.user.find(id).update(data);
1315
-
1316
- expect(beforeCreate).toHaveBeenCalledTimes(1);
1317
- expect(afterCreate).toHaveBeenCalledTimes(1);
1318
- });
1319
-
1320
- it('should invoke callbacks in a batch update', async () => {
1321
- const ids = await db.user
1322
- .pluck('id')
1323
- .createMany([userData, userData]);
1324
-
1325
- resetMocks();
1326
-
1327
- await db.user.where({ id: { in: ids } }).update(data);
1328
-
1329
- expect(beforeCreate).toHaveBeenCalledTimes(1);
1330
- expect(afterCreate).toHaveBeenCalledTimes(1);
1331
- });
1332
- });
1333
- });
1334
- });
1335
- });