@payloadcms/drizzle 4.0.0-canary.35 → 4.0.0-canary.36
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.
- package/package.json +3 -3
- package/dist/find/buildPolymorphicJoinQuery.spec.js +0 -384
- package/dist/find/buildPolymorphicJoinQuery.spec.js.map +0 -1
- package/dist/find/buildPolymorphicJoinWhere.spec.js +0 -805
- package/dist/find/buildPolymorphicJoinWhere.spec.js.map +0 -1
- package/dist/find/createPolymorphicJoinWherePlan.spec.js +0 -778
- package/dist/find/createPolymorphicJoinWherePlan.spec.js.map +0 -1
- package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.spec.js +0 -91
- package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.spec.js.map +0 -1
- package/dist/postgres/query/postgresUnaccent.spec.js +0 -71
- package/dist/postgres/query/postgresUnaccent.spec.js.map +0 -1
- package/dist/queries/buildOperatorConstraint.spec.js +0 -348
- package/dist/queries/buildOperatorConstraint.spec.js.map +0 -1
- package/dist/queries/validateOperatorHandlers.spec.js +0 -142
- package/dist/queries/validateOperatorHandlers.spec.js.map +0 -1
- package/dist/schema/buildRawSchema.spec.js +0 -290
- package/dist/schema/buildRawSchema.spec.js.map +0 -1
- package/dist/updateOne.spec.js +0 -84
- package/dist/updateOne.spec.js.map +0 -1
- package/dist/upsertRow/conditionalUpdate.spec.js +0 -61
- package/dist/upsertRow/conditionalUpdate.spec.js.map +0 -1
- package/dist/upsertRow/handleUpsertError.spec.js +0 -42
- package/dist/upsertRow/handleUpsertError.spec.js.map +0 -1
- package/dist/utilities/checkTruncatedIdentifiers.spec.js +0 -301
- package/dist/utilities/checkTruncatedIdentifiers.spec.js.map +0 -1
- package/dist/utilities/isValidStringID.spec.js +0 -15
- package/dist/utilities/isValidStringID.spec.js.map +0 -1
- package/dist/utilities/validateIdentifierLength.spec.js +0 -19
- package/dist/utilities/validateIdentifierLength.spec.js.map +0 -1
|
@@ -1,778 +0,0 @@
|
|
|
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
|