@payloadcms/drizzle 4.0.0-canary.32 → 4.0.0-canary.34

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 (53) hide show
  1. package/dist/find/buildPolymorphicJoinQuery.d.ts +38 -0
  2. package/dist/find/buildPolymorphicJoinQuery.d.ts.map +1 -0
  3. package/dist/find/buildPolymorphicJoinQuery.js +135 -0
  4. package/dist/find/buildPolymorphicJoinQuery.js.map +1 -0
  5. package/dist/find/buildPolymorphicJoinQuery.spec.js +384 -0
  6. package/dist/find/buildPolymorphicJoinQuery.spec.js.map +1 -0
  7. package/dist/find/buildPolymorphicJoinWhere.d.ts +20 -0
  8. package/dist/find/buildPolymorphicJoinWhere.d.ts.map +1 -0
  9. package/dist/find/buildPolymorphicJoinWhere.js +301 -0
  10. package/dist/find/buildPolymorphicJoinWhere.js.map +1 -0
  11. package/dist/find/buildPolymorphicJoinWhere.spec.js +805 -0
  12. package/dist/find/buildPolymorphicJoinWhere.spec.js.map +1 -0
  13. package/dist/find/createPolymorphicJoinWherePlan.d.ts +37 -0
  14. package/dist/find/createPolymorphicJoinWherePlan.d.ts.map +1 -0
  15. package/dist/find/createPolymorphicJoinWherePlan.js +191 -0
  16. package/dist/find/createPolymorphicJoinWherePlan.js.map +1 -0
  17. package/dist/find/createPolymorphicJoinWherePlan.spec.js +778 -0
  18. package/dist/find/createPolymorphicJoinWherePlan.spec.js.map +1 -0
  19. package/dist/find/traverseFields.d.ts.map +1 -1
  20. package/dist/find/traverseFields.js +19 -191
  21. package/dist/find/traverseFields.js.map +1 -1
  22. package/dist/postgres/createJSONQuery/index.js +3 -3
  23. package/dist/postgres/createJSONQuery/index.js.map +1 -1
  24. package/dist/queries/getTableColumnFromPath.d.ts.map +1 -1
  25. package/dist/queries/getTableColumnFromPath.js +9 -0
  26. package/dist/queries/getTableColumnFromPath.js.map +1 -1
  27. package/dist/queries/parseParams.d.ts.map +1 -1
  28. package/dist/queries/parseParams.js +59 -2
  29. package/dist/queries/parseParams.js.map +1 -1
  30. package/dist/sqlite/createJSONQuery/convertPathToJSONTraversal.js +3 -2
  31. package/dist/sqlite/createJSONQuery/convertPathToJSONTraversal.js.map +1 -1
  32. package/dist/sqlite/createJSONQuery/index.d.ts.map +1 -1
  33. package/dist/sqlite/createJSONQuery/index.js +6 -5
  34. package/dist/sqlite/createJSONQuery/index.js.map +1 -1
  35. package/dist/transform/write/traverseFields.d.ts.map +1 -1
  36. package/dist/transform/write/traverseFields.js +5 -14
  37. package/dist/transform/write/traverseFields.js.map +1 -1
  38. package/dist/updateOne.d.ts.map +1 -1
  39. package/dist/updateOne.js +41 -1
  40. package/dist/updateOne.js.map +1 -1
  41. package/dist/updateOne.spec.js +84 -0
  42. package/dist/updateOne.spec.js.map +1 -0
  43. package/dist/upsertRow/conditionalUpdate.spec.js +61 -0
  44. package/dist/upsertRow/conditionalUpdate.spec.js.map +1 -0
  45. package/dist/upsertRow/index.d.ts +1 -1
  46. package/dist/upsertRow/index.d.ts.map +1 -1
  47. package/dist/upsertRow/index.js +25 -5
  48. package/dist/upsertRow/index.js.map +1 -1
  49. package/dist/utilities/parseJSONPathSegment.d.ts +9 -0
  50. package/dist/utilities/parseJSONPathSegment.d.ts.map +1 -0
  51. package/dist/utilities/parseJSONPathSegment.js +17 -0
  52. package/dist/utilities/parseJSONPathSegment.js.map +1 -0
  53. package/package.json +3 -3
@@ -0,0 +1,778 @@
1
+ import { getTableName } from 'drizzle-orm';
2
+ import { pgEnum, pgTable, serial } from 'drizzle-orm/pg-core';
3
+ import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
4
+ import { flattenAllFields } from 'payload';
5
+ import toSnakeCase from 'to-snake-case';
6
+ import { describe, expect, it } from 'vitest';
7
+ import { createPolymorphicJoinWherePlan } from './createPolymorphicJoinWherePlan.js';
8
+ const articlesTable = sqliteTable('join_articles', {
9
+ id: integer('id').primaryKey(),
10
+ details_status: text('details_status_flat'),
11
+ score: integer('score'),
12
+ status: text('status'),
13
+ title: text('title'),
14
+ variantSelect: text('variant_select'),
15
+ variantValue: text('variant_value')
16
+ });
17
+ const notesTable = sqliteTable('join_notes', {
18
+ id: integer('id').primaryKey(),
19
+ details_status: text('details_status_flat'),
20
+ status: text('status'),
21
+ title: text('title'),
22
+ variantSelect: integer('variant_select'),
23
+ variantTags: text('variant_tags'),
24
+ variantValue: integer('variant_value')
25
+ });
26
+ const articleSelectEnum = pgEnum('join_plan_article_select', [
27
+ 'available',
28
+ 'reviewed'
29
+ ]);
30
+ const articleRadioEnum = pgEnum('join_plan_article_radio', [
31
+ 'draft',
32
+ 'published'
33
+ ]);
34
+ const noteSelectEnum = pgEnum('join_plan_note_select', [
35
+ 'available',
36
+ 'reviewed'
37
+ ]);
38
+ const noteRadioEnum = pgEnum('join_plan_note_radio', [
39
+ 'draft',
40
+ 'published'
41
+ ]);
42
+ const postgresArticlesTable = pgTable('join_plan_articles', {
43
+ id: serial('id').primaryKey(),
44
+ variantRadio: articleRadioEnum('variant_radio'),
45
+ variantSelect: articleSelectEnum('variant_select')
46
+ });
47
+ const postgresNotesTable = pgTable('join_plan_notes', {
48
+ id: serial('id').primaryKey(),
49
+ variantRadio: noteRadioEnum('variant_radio'),
50
+ variantSelect: noteSelectEnum('variant_select')
51
+ });
52
+ const articleFields = [
53
+ {
54
+ name: 'title',
55
+ type: 'text'
56
+ },
57
+ {
58
+ name: 'score',
59
+ type: 'number'
60
+ },
61
+ {
62
+ name: 'details',
63
+ type: 'group',
64
+ fields: [
65
+ {
66
+ name: 'status',
67
+ type: 'text'
68
+ },
69
+ {
70
+ hasMany: true,
71
+ name: 'tags',
72
+ options: [
73
+ 'available'
74
+ ],
75
+ type: 'select'
76
+ }
77
+ ]
78
+ },
79
+ {
80
+ name: 'details_status',
81
+ type: 'text'
82
+ },
83
+ {
84
+ name: 'status',
85
+ type: 'text'
86
+ },
87
+ {
88
+ hasMany: true,
89
+ name: 'variantTags',
90
+ options: [
91
+ 'available'
92
+ ],
93
+ type: 'select'
94
+ },
95
+ {
96
+ name: 'variantSelect',
97
+ options: [
98
+ 'available'
99
+ ],
100
+ type: 'select'
101
+ },
102
+ {
103
+ name: 'variantValue',
104
+ type: 'text'
105
+ },
106
+ {
107
+ localized: true,
108
+ name: 'localizedTitle',
109
+ type: 'text'
110
+ },
111
+ {
112
+ name: 'entries',
113
+ type: 'array',
114
+ fields: [
115
+ {
116
+ hasMany: true,
117
+ name: 'tags',
118
+ options: [
119
+ 'available'
120
+ ],
121
+ type: 'select'
122
+ }
123
+ ]
124
+ },
125
+ {
126
+ name: 'content',
127
+ type: 'blocks',
128
+ blocks: [
129
+ {
130
+ slug: 'hero',
131
+ fields: [
132
+ {
133
+ hasMany: true,
134
+ name: 'tags',
135
+ options: [
136
+ 'available'
137
+ ],
138
+ type: 'select'
139
+ }
140
+ ]
141
+ }
142
+ ]
143
+ }
144
+ ];
145
+ const noteFields = [
146
+ {
147
+ name: 'title',
148
+ type: 'text'
149
+ },
150
+ {
151
+ name: 'details',
152
+ type: 'group',
153
+ fields: [
154
+ {
155
+ name: 'status',
156
+ type: 'text'
157
+ },
158
+ {
159
+ hasMany: true,
160
+ name: 'tags',
161
+ options: [
162
+ 'available'
163
+ ],
164
+ type: 'select'
165
+ }
166
+ ]
167
+ },
168
+ {
169
+ name: 'details_status',
170
+ type: 'text'
171
+ },
172
+ {
173
+ name: 'status',
174
+ type: 'text'
175
+ },
176
+ {
177
+ name: 'variantTags',
178
+ options: [
179
+ 'available'
180
+ ],
181
+ type: 'select'
182
+ },
183
+ {
184
+ name: 'variantSelect',
185
+ options: [
186
+ 'available'
187
+ ],
188
+ type: 'select'
189
+ },
190
+ {
191
+ name: 'variantValue',
192
+ type: 'number'
193
+ }
194
+ ];
195
+ const articleEnumFields = [
196
+ {
197
+ name: 'variantSelect',
198
+ options: [
199
+ 'available',
200
+ {
201
+ label: 'Reviewed',
202
+ value: 'reviewed'
203
+ }
204
+ ],
205
+ type: 'select'
206
+ },
207
+ {
208
+ name: 'variantRadio',
209
+ options: [
210
+ 'draft',
211
+ 'published'
212
+ ],
213
+ type: 'radio'
214
+ }
215
+ ];
216
+ const noteEnumFields = [
217
+ {
218
+ name: 'variantSelect',
219
+ options: [
220
+ {
221
+ label: 'Available',
222
+ value: 'available'
223
+ },
224
+ 'reviewed'
225
+ ],
226
+ type: 'select'
227
+ },
228
+ {
229
+ name: 'variantRadio',
230
+ options: [
231
+ {
232
+ label: 'Draft',
233
+ value: 'draft'
234
+ },
235
+ {
236
+ label: 'Published',
237
+ value: 'published'
238
+ }
239
+ ],
240
+ type: 'radio'
241
+ }
242
+ ];
243
+ const createAdapter = (fixtures)=>{
244
+ const collections = {};
245
+ const tableNameMap = new Map();
246
+ const tables = {};
247
+ for (const [slug, fixture] of Object.entries(fixtures)){
248
+ const tableName = getTableName(fixture.table);
249
+ collections[slug] = {
250
+ config: {
251
+ fields: fixture.fields,
252
+ flattenedFields: flattenAllFields({
253
+ fields: fixture.fields
254
+ })
255
+ }
256
+ };
257
+ tableNameMap.set(toSnakeCase(slug), tableName);
258
+ tables[tableName] = fixture.table;
259
+ }
260
+ return {
261
+ idType: 'serial',
262
+ payload: {
263
+ collections
264
+ },
265
+ tableNameMap,
266
+ tables
267
+ };
268
+ };
269
+ const adapter = createAdapter({
270
+ articles: {
271
+ fields: articleFields,
272
+ table: articlesTable
273
+ },
274
+ notes: {
275
+ fields: noteFields,
276
+ table: notesTable
277
+ }
278
+ });
279
+ const createPlan = (where, collections = [
280
+ 'articles',
281
+ 'notes'
282
+ ])=>createPolymorphicJoinWherePlan({
283
+ adapter,
284
+ collections,
285
+ where
286
+ });
287
+ describe('createPolymorphicJoinWherePlan', ()=>{
288
+ it('creates one scalar plan per unique field in nested boolean clauses', ()=>{
289
+ const plan = createPlan({
290
+ AND: [
291
+ {
292
+ title: {
293
+ equals: 'available'
294
+ }
295
+ },
296
+ {
297
+ 'details.status': {
298
+ equals: 'reviewed'
299
+ }
300
+ },
301
+ {
302
+ OR: [
303
+ {
304
+ score: {
305
+ greater_than: 1
306
+ }
307
+ },
308
+ {
309
+ title: {
310
+ not_equals: 'restricted'
311
+ }
312
+ }
313
+ ]
314
+ }
315
+ ]
316
+ });
317
+ expect([
318
+ ...plan.keys()
319
+ ]).toEqual([
320
+ 'title',
321
+ 'details.status',
322
+ 'score'
323
+ ]);
324
+ expect(plan.get('title')).toMatchObject({
325
+ columnPath: 'title',
326
+ schemaPath: 'title',
327
+ type: 'scalar'
328
+ });
329
+ expect([
330
+ ...plan.get('title').fieldsByCollection.keys()
331
+ ]).toEqual([
332
+ 'articles',
333
+ 'notes'
334
+ ]);
335
+ expect(plan.get('details.status')).toMatchObject({
336
+ columnPath: 'details_status',
337
+ type: 'scalar'
338
+ });
339
+ expect([
340
+ ...plan.get('score').fieldsByCollection.keys()
341
+ ]).toEqual([
342
+ 'articles'
343
+ ]);
344
+ });
345
+ it('creates scalar plans for id and relationTo without configured fields', ()=>{
346
+ const plan = createPlan({
347
+ id: {
348
+ in: [
349
+ 1,
350
+ 2
351
+ ]
352
+ },
353
+ relationTo: {
354
+ equals: 'articles'
355
+ }
356
+ });
357
+ expect(plan.get('id')).toMatchObject({
358
+ columnPath: 'id',
359
+ type: 'scalar'
360
+ });
361
+ expect([
362
+ ...plan.get('id').fieldsByCollection.keys()
363
+ ]).toEqual([
364
+ 'articles',
365
+ 'notes'
366
+ ]);
367
+ expect(plan.get('relationTo')).toMatchObject({
368
+ columnPath: 'relationTo',
369
+ type: 'scalar'
370
+ });
371
+ expect(plan.get('relationTo').fieldsByCollection.size).toBe(0);
372
+ });
373
+ it('uses a synthetic UUID field context for an id path without a configured id field', ()=>{
374
+ const uuidTable = sqliteTable('uuid_articles', {
375
+ id: text('id').primaryKey()
376
+ });
377
+ const uuidAdapter = createAdapter({
378
+ articles: {
379
+ fields: [],
380
+ table: uuidTable
381
+ }
382
+ });
383
+ uuidAdapter.idType = 'uuid';
384
+ const idPlan = createPolymorphicJoinWherePlan({
385
+ adapter: uuidAdapter,
386
+ collections: [
387
+ 'articles'
388
+ ],
389
+ where: {
390
+ id: {
391
+ equals: '01991f04-1780-7000-8000-000000000001'
392
+ }
393
+ }
394
+ }).get('id');
395
+ expect(idPlan.fieldsByCollection.get('articles')).toMatchObject({
396
+ field: {
397
+ name: 'id',
398
+ type: 'text'
399
+ },
400
+ isUUID: true,
401
+ type: 'scalar'
402
+ });
403
+ });
404
+ it('keeps a scalar path valid when it is absent from one target collection', ()=>{
405
+ const scorePlan = createPlan({
406
+ score: {
407
+ equals: 5
408
+ }
409
+ }).get('score');
410
+ expect(scorePlan.type).toBe('scalar');
411
+ expect([
412
+ ...scorePlan.fieldsByCollection.keys()
413
+ ]).toEqual([
414
+ 'articles'
415
+ ]);
416
+ });
417
+ it('creates a hasManySelect plan when the field uses separate value rows', ()=>{
418
+ const tagsPlan = createPlan({
419
+ 'details.tags': {
420
+ contains: 'available'
421
+ }
422
+ }).get('details.tags');
423
+ expect(tagsPlan).toMatchObject({
424
+ columnPath: 'details_tags',
425
+ schemaPath: 'details.tags',
426
+ type: 'hasManySelect'
427
+ });
428
+ expect([
429
+ ...tagsPlan.fieldsByCollection.values()
430
+ ]).toEqual([
431
+ expect.objectContaining({
432
+ field: expect.objectContaining({
433
+ name: 'tags'
434
+ }),
435
+ type: 'hasManySelect'
436
+ }),
437
+ expect.objectContaining({
438
+ field: expect.objectContaining({
439
+ name: 'tags'
440
+ }),
441
+ type: 'hasManySelect'
442
+ })
443
+ ]);
444
+ });
445
+ it('accepts matching select fields even when their database column types differ', ()=>{
446
+ const selectPlan = createPlan({
447
+ variantSelect: {
448
+ equals: 'available'
449
+ }
450
+ }).get('variantSelect');
451
+ expect(selectPlan.type).toBe('scalar');
452
+ expect([
453
+ ...selectPlan.fieldsByCollection.keys()
454
+ ]).toEqual([
455
+ 'articles',
456
+ 'notes'
457
+ ]);
458
+ });
459
+ it('accepts text and textarea fields that use the same query value coercion', ()=>{
460
+ const fieldsWithTextarea = noteFields.map((field)=>field.name === 'title' ? {
461
+ ...field,
462
+ type: 'textarea'
463
+ } : field);
464
+ const compatibleAdapter = createAdapter({
465
+ articles: {
466
+ fields: articleFields,
467
+ table: articlesTable
468
+ },
469
+ notes: {
470
+ fields: fieldsWithTextarea,
471
+ table: notesTable
472
+ }
473
+ });
474
+ const titlePlan = createPolymorphicJoinWherePlan({
475
+ adapter: compatibleAdapter,
476
+ collections: [
477
+ 'articles',
478
+ 'notes'
479
+ ],
480
+ where: {
481
+ title: {
482
+ equals: 'available'
483
+ }
484
+ }
485
+ }).get('title');
486
+ expect(titlePlan.type).toBe('scalar');
487
+ });
488
+ it.each([
489
+ [
490
+ 'select',
491
+ 'variantSelect',
492
+ 'available'
493
+ ],
494
+ [
495
+ 'radio',
496
+ 'variantRadio',
497
+ 'draft'
498
+ ]
499
+ ])('accepts PostgreSQL %s fields with separate enum types and matching option values', (_fieldType, schemaPath, value)=>{
500
+ const postgresAdapter = createAdapter({
501
+ articles: {
502
+ fields: articleEnumFields,
503
+ table: postgresArticlesTable
504
+ },
505
+ notes: {
506
+ fields: noteEnumFields,
507
+ table: postgresNotesTable
508
+ }
509
+ });
510
+ const fieldPlan = createPolymorphicJoinWherePlan({
511
+ adapter: postgresAdapter,
512
+ collections: [
513
+ 'articles',
514
+ 'notes'
515
+ ],
516
+ where: {
517
+ [schemaPath]: {
518
+ equals: value
519
+ }
520
+ }
521
+ }).get(schemaPath);
522
+ expect(fieldPlan.type).toBe('scalar');
523
+ expect([
524
+ ...fieldPlan.fieldsByCollection.keys()
525
+ ]).toEqual([
526
+ 'articles',
527
+ 'notes'
528
+ ]);
529
+ });
530
+ it.each([
531
+ [
532
+ 'select',
533
+ 'variantSelect',
534
+ [
535
+ 'available',
536
+ 'restricted'
537
+ ]
538
+ ],
539
+ [
540
+ 'select',
541
+ 'variantSelect',
542
+ [
543
+ 'reviewed',
544
+ 'available'
545
+ ]
546
+ ],
547
+ [
548
+ 'radio',
549
+ 'variantRadio',
550
+ [
551
+ 'draft',
552
+ 'restricted'
553
+ ]
554
+ ],
555
+ [
556
+ 'radio',
557
+ 'variantRadio',
558
+ [
559
+ 'published',
560
+ 'draft'
561
+ ]
562
+ ]
563
+ ])('rejects PostgreSQL %s fields whose option values differ or use a different order', (fieldType, schemaPath, options)=>{
564
+ const noteFieldsWithDifferentOptions = noteEnumFields.map((field)=>field.name === schemaPath ? {
565
+ ...field,
566
+ options: [
567
+ ...options
568
+ ],
569
+ type: fieldType
570
+ } : field);
571
+ const postgresAdapter = createAdapter({
572
+ articles: {
573
+ fields: articleEnumFields,
574
+ table: postgresArticlesTable
575
+ },
576
+ notes: {
577
+ fields: noteFieldsWithDifferentOptions,
578
+ table: postgresNotesTable
579
+ }
580
+ });
581
+ const fieldPlan = createPolymorphicJoinWherePlan({
582
+ adapter: postgresAdapter,
583
+ collections: [
584
+ 'articles',
585
+ 'notes'
586
+ ],
587
+ where: {
588
+ [schemaPath]: {
589
+ equals: options[0]
590
+ }
591
+ }
592
+ }).get(schemaPath);
593
+ expect(fieldPlan.type).toBe('invalid');
594
+ });
595
+ it.each([
596
+ [
597
+ 'a field that is absent from every collection',
598
+ {
599
+ unknown: {
600
+ equals: 'value'
601
+ }
602
+ },
603
+ 'unknown'
604
+ ],
605
+ [
606
+ 'incompatible scalar field types',
607
+ {
608
+ variantValue: {
609
+ equals: 'value'
610
+ }
611
+ },
612
+ 'variantValue'
613
+ ],
614
+ [
615
+ 'a has-many select mixed with a scalar select',
616
+ {
617
+ variantTags: {
618
+ contains: 'available'
619
+ }
620
+ },
621
+ 'variantTags'
622
+ ],
623
+ [
624
+ 'a localized field',
625
+ {
626
+ localizedTitle: {
627
+ equals: 'value'
628
+ }
629
+ },
630
+ 'localizedTitle'
631
+ ],
632
+ [
633
+ 'a field stored in array rows',
634
+ {
635
+ 'entries.tags': {
636
+ equals: 'value'
637
+ }
638
+ },
639
+ 'entries.tags'
640
+ ],
641
+ [
642
+ 'a field stored in block rows',
643
+ {
644
+ 'content.hero.tags': {
645
+ equals: 'value'
646
+ }
647
+ },
648
+ 'content.hero.tags'
649
+ ]
650
+ ])('marks %s as invalid', (_description, where, schemaPath)=>{
651
+ expect(createPlan(where).get(schemaPath)).toMatchObject({
652
+ type: 'invalid'
653
+ });
654
+ });
655
+ it('marks both schema paths as invalid when they resolve to the same flattened column path', ()=>{
656
+ const plan = createPlan({
657
+ 'details.status': {
658
+ equals: 'available'
659
+ },
660
+ details_status: {
661
+ equals: 'available'
662
+ }
663
+ });
664
+ expect(plan.get('details.status')).toMatchObject({
665
+ columnPath: 'details_status',
666
+ type: 'invalid'
667
+ });
668
+ expect(plan.get('details_status')).toMatchObject({
669
+ columnPath: 'details_status',
670
+ type: 'invalid'
671
+ });
672
+ });
673
+ it('marks a configured scalar field as invalid when its table column is missing', ()=>{
674
+ const tableWithoutTitle = sqliteTable('articles_without_title', {
675
+ id: integer('id').primaryKey()
676
+ });
677
+ const adapterWithoutTitle = createAdapter({
678
+ articles: {
679
+ fields: [
680
+ {
681
+ name: 'title',
682
+ type: 'text'
683
+ }
684
+ ],
685
+ table: tableWithoutTitle
686
+ }
687
+ });
688
+ const plan = createPolymorphicJoinWherePlan({
689
+ adapter: adapterWithoutTitle,
690
+ collections: [
691
+ 'articles'
692
+ ],
693
+ where: {
694
+ title: {
695
+ equals: 'available'
696
+ }
697
+ }
698
+ });
699
+ expect(plan.get('title')).toMatchObject({
700
+ type: 'invalid'
701
+ });
702
+ });
703
+ it('marks an id path as invalid when a target table has no id column', ()=>{
704
+ const tableWithoutID = sqliteTable('articles_without_id', {
705
+ title: text('title')
706
+ });
707
+ const adapterWithoutID = createAdapter({
708
+ articles: {
709
+ fields: [
710
+ {
711
+ name: 'title',
712
+ type: 'text'
713
+ }
714
+ ],
715
+ table: tableWithoutID
716
+ }
717
+ });
718
+ const plan = createPolymorphicJoinWherePlan({
719
+ adapter: adapterWithoutID,
720
+ collections: [
721
+ 'articles'
722
+ ],
723
+ where: {
724
+ id: {
725
+ equals: 1
726
+ }
727
+ }
728
+ });
729
+ expect(plan.get('id')).toMatchObject({
730
+ type: 'invalid'
731
+ });
732
+ });
733
+ it('marks every requested path as invalid when there are no target collections', ()=>{
734
+ expect(createPlan({
735
+ title: {
736
+ equals: 'available'
737
+ }
738
+ }, []).get('title')).toMatchObject({
739
+ type: 'invalid'
740
+ });
741
+ });
742
+ it('throws a descriptive error when a target collection is not configured', ()=>{
743
+ expect(()=>createPlan({
744
+ title: {
745
+ equals: 'available'
746
+ }
747
+ }, [
748
+ 'missing'
749
+ ])).toThrow('Unknown polymorphic join collection "missing"');
750
+ });
751
+ it('throws a descriptive error when a configured collection has no database table', ()=>{
752
+ const adapterWithoutTable = createAdapter({
753
+ articles: {
754
+ fields: [
755
+ {
756
+ name: 'title',
757
+ type: 'text'
758
+ }
759
+ ],
760
+ table: articlesTable
761
+ }
762
+ });
763
+ adapterWithoutTable.tables = {};
764
+ expect(()=>createPolymorphicJoinWherePlan({
765
+ adapter: adapterWithoutTable,
766
+ collections: [
767
+ 'articles'
768
+ ],
769
+ where: {
770
+ title: {
771
+ equals: 'available'
772
+ }
773
+ }
774
+ })).toThrow('Polymorphic join collection "articles" has no database table');
775
+ });
776
+ });
777
+
778
+ //# sourceMappingURL=createPolymorphicJoinWherePlan.spec.js.map