@payloadcms/db-sqlite 3.0.0-canary.cf66341 → 3.0.0-canary.dc8b1fe

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.
@@ -1,15 +1,15 @@
1
- import { createTableName, hasLocalesTable, validateExistingBlockIsIdentical } from '@payloadcms/drizzle';
1
+ import { buildIndexName, createTableName, hasLocalesTable, validateExistingBlockIsIdentical } from '@payloadcms/drizzle';
2
2
  import { relations } from 'drizzle-orm';
3
- import { SQLiteIntegerBuilder, SQLiteNumericBuilder, SQLiteTextBuilder, foreignKey, index, integer, numeric, text } from 'drizzle-orm/sqlite-core';
3
+ import { foreignKey, index, integer, numeric, SQLiteIntegerBuilder, SQLiteNumericBuilder, SQLiteTextBuilder, text } from 'drizzle-orm/sqlite-core';
4
4
  import { InvalidConfiguration } from 'payload';
5
- import { fieldAffectsData, optionIsObject } from 'payload/shared';
5
+ import { fieldAffectsData, fieldIsVirtual, optionIsObject } from 'payload/shared';
6
6
  import toSnakeCase from 'to-snake-case';
7
7
  import { buildTable } from './build.js';
8
8
  import { createIndex } from './createIndex.js';
9
9
  import { getIDColumn } from './getIDColumn.js';
10
10
  import { idToUUID } from './idToUUID.js';
11
11
  import { withDefault } from './withDefault.js';
12
- export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull, disableUnique = false, fieldPrefix, fields, forceLocalized, indexes, locales, localesColumns, localesIndexes, newTableName, parentTableName, relationsToBuild, relationships, rootRelationsToBuild, rootTableIDColType, rootTableName, versions })=>{
12
+ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull, disableRelsTableUnique, disableUnique = false, fieldPrefix, fields, forceLocalized, indexes, locales, localesColumns, localesIndexes, newTableName, parentTableName, relationships, relationsToBuild, rootRelationsToBuild, rootTableIDColType, rootTableName, uniqueRelationships, versions, withinLocalizedArrayOrBlock })=>{
13
13
  let hasLocalizedField = false;
14
14
  let hasLocalizedRelationshipField = false;
15
15
  let hasManyTextField = false;
@@ -17,11 +17,22 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
17
17
  let hasManyNumberField = false;
18
18
  let hasLocalizedManyNumberField = false;
19
19
  let parentIDColType = 'integer';
20
- if (columns.id instanceof SQLiteIntegerBuilder) parentIDColType = 'integer';
21
- if (columns.id instanceof SQLiteNumericBuilder) parentIDColType = 'numeric';
22
- if (columns.id instanceof SQLiteTextBuilder) parentIDColType = 'text';
20
+ if (columns.id instanceof SQLiteIntegerBuilder) {
21
+ parentIDColType = 'integer';
22
+ }
23
+ if (columns.id instanceof SQLiteNumericBuilder) {
24
+ parentIDColType = 'numeric';
25
+ }
26
+ if (columns.id instanceof SQLiteTextBuilder) {
27
+ parentIDColType = 'text';
28
+ }
23
29
  fields.forEach((field)=>{
24
- if ('name' in field && field.name === 'id') return;
30
+ if ('name' in field && field.name === 'id') {
31
+ return;
32
+ }
33
+ if (fieldIsVirtual(field)) {
34
+ return;
35
+ }
25
36
  let columnName;
26
37
  let fieldName;
27
38
  let targetTable = columns;
@@ -36,14 +47,15 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
36
47
  targetTable = localesColumns;
37
48
  targetIndexes = localesIndexes;
38
49
  }
39
- if ((field.unique || field.index) && ![
50
+ if ((field.unique || field.index || [
51
+ 'relationship',
52
+ 'upload'
53
+ ].includes(field.type)) && ![
40
54
  'array',
41
55
  'blocks',
42
56
  'group',
43
- 'point',
44
- 'relationship',
45
- 'upload'
46
- ].includes(field.type) && !('hasMany' in field && field.hasMany === true)) {
57
+ 'point'
58
+ ].includes(field.type) && !('hasMany' in field && field.hasMany === true) && !('relationTo' in field && Array.isArray(field.relationTo))) {
47
59
  const unique = disableUnique !== true && field.unique;
48
60
  if (unique) {
49
61
  const constraintValue = `${fieldPrefix || ''}${field.name}`;
@@ -52,10 +64,16 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
52
64
  }
53
65
  adapter.fieldConstraints[rootTableName][`${columnName}_idx`] = constraintValue;
54
66
  }
55
- targetIndexes[`${newTableName}_${field.name}Idx`] = createIndex({
56
- name: fieldName,
57
- columnName,
58
- tableName: newTableName,
67
+ const indexName = buildIndexName({
68
+ name: `${newTableName}_${columnName}`,
69
+ adapter: adapter
70
+ });
71
+ targetIndexes[indexName] = createIndex({
72
+ name: field.localized ? [
73
+ fieldName,
74
+ '_locale'
75
+ ] : fieldName,
76
+ indexName,
59
77
  unique
60
78
  });
61
79
  }
@@ -64,7 +82,8 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
64
82
  case 'text':
65
83
  {
66
84
  if (field.hasMany) {
67
- if (field.localized) {
85
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
86
+ if (isLocalized) {
68
87
  hasLocalizedManyTextField = true;
69
88
  }
70
89
  if (field.index) {
@@ -90,7 +109,8 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
90
109
  case 'number':
91
110
  {
92
111
  if (field.hasMany) {
93
- if (field.localized) {
112
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
113
+ if (isLocalized) {
94
114
  hasLocalizedManyNumberField = true;
95
115
  }
96
116
  if (field.index) {
@@ -165,7 +185,8 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
165
185
  }).onDelete('cascade'),
166
186
  parentIdx: (cols)=>index(`${selectTableName}_parent_idx`).on(cols.parent)
167
187
  };
168
- if (field.localized) {
188
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
189
+ if (isLocalized) {
169
190
  baseColumns.locale = text('locale', {
170
191
  enum: locales
171
192
  }).notNull();
@@ -203,7 +224,7 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
203
224
  })
204
225
  }));
205
226
  } else {
206
- targetTable[fieldName] = withDefault(text(fieldName, {
227
+ targetTable[fieldName] = withDefault(text(columnName, {
207
228
  enum: options
208
229
  }), field);
209
230
  }
@@ -248,31 +269,48 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
248
269
  }).onDelete('cascade'),
249
270
  _parentIDIdx: (cols)=>index(`${arrayTableName}_parent_id_idx`).on(cols._parentID)
250
271
  };
251
- if (field.localized && adapter.payload.config.localization) {
272
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
273
+ if (isLocalized) {
252
274
  baseColumns._locale = text('_locale', {
253
275
  enum: locales
254
276
  }).notNull();
255
277
  baseExtraConfig._localeIdx = (cols)=>index(`${arrayTableName}_locale_idx`).on(cols._locale);
256
278
  }
257
- const { hasManyNumberField: subHasManyNumberField, hasManyTextField: subHasManyTextField, relationsToBuild: subRelationsToBuild } = buildTable({
279
+ const { hasLocalizedManyNumberField: subHasLocalizedManyNumberField, hasLocalizedManyTextField: subHasLocalizedManyTextField, hasLocalizedRelationshipField: subHasLocalizedRelationshipField, hasManyNumberField: subHasManyNumberField, hasManyTextField: subHasManyTextField, relationsToBuild: subRelationsToBuild } = buildTable({
258
280
  adapter,
259
281
  baseColumns,
260
282
  baseExtraConfig,
261
283
  disableNotNull: disableNotNullFromHere,
284
+ disableRelsTableUnique: true,
262
285
  disableUnique,
263
286
  fields: disableUnique ? idToUUID(field.fields) : field.fields,
264
- rootRelationsToBuild,
265
287
  rootRelationships: relationships,
288
+ rootRelationsToBuild,
266
289
  rootTableIDColType,
267
290
  rootTableName,
291
+ rootUniqueRelationships: uniqueRelationships,
268
292
  tableName: arrayTableName,
269
- versions
293
+ versions,
294
+ withinLocalizedArrayOrBlock: isLocalized
270
295
  });
296
+ if (subHasLocalizedManyNumberField) {
297
+ hasLocalizedManyNumberField = subHasLocalizedManyNumberField;
298
+ }
299
+ if (subHasLocalizedRelationshipField) {
300
+ hasLocalizedRelationshipField = subHasLocalizedRelationshipField;
301
+ }
302
+ if (subHasLocalizedManyTextField) {
303
+ hasLocalizedManyTextField = subHasLocalizedManyTextField;
304
+ }
271
305
  if (subHasManyTextField) {
272
- if (!hasManyTextField || subHasManyTextField === 'index') hasManyTextField = subHasManyTextField;
306
+ if (!hasManyTextField || subHasManyTextField === 'index') {
307
+ hasManyTextField = subHasManyTextField;
308
+ }
273
309
  }
274
310
  if (subHasManyNumberField) {
275
- if (!hasManyNumberField || subHasManyNumberField === 'index') hasManyNumberField = subHasManyNumberField;
311
+ if (!hasManyNumberField || subHasManyNumberField === 'index') {
312
+ hasManyNumberField = subHasManyNumberField;
313
+ }
276
314
  }
277
315
  relationsToBuild.set(fieldName, {
278
316
  type: 'many',
@@ -344,7 +382,6 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
344
382
  };
345
383
  const baseExtraConfig = {
346
384
  _orderIdx: (cols)=>index(`${blockTableName}_order_idx`).on(cols._order),
347
- _parentIDIdx: (cols)=>index(`${blockTableName}_parent_id_idx`).on(cols._parentID),
348
385
  _parentIdFk: (cols)=>foreignKey({
349
386
  name: `${blockTableName}_parent_id_fk`,
350
387
  columns: [
@@ -354,33 +391,51 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
354
391
  adapter.tables[rootTableName].id
355
392
  ]
356
393
  }).onDelete('cascade'),
394
+ _parentIDIdx: (cols)=>index(`${blockTableName}_parent_id_idx`).on(cols._parentID),
357
395
  _pathIdx: (cols)=>index(`${blockTableName}_path_idx`).on(cols._path)
358
396
  };
359
- if (field.localized && adapter.payload.config.localization) {
397
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
398
+ if (isLocalized) {
360
399
  baseColumns._locale = text('_locale', {
361
400
  enum: locales
362
401
  }).notNull();
363
402
  baseExtraConfig._localeIdx = (cols)=>index(`${blockTableName}_locale_idx`).on(cols._locale);
364
403
  }
365
- const { hasManyNumberField: subHasManyNumberField, hasManyTextField: subHasManyTextField, relationsToBuild: subRelationsToBuild } = buildTable({
404
+ const { hasLocalizedManyNumberField: subHasLocalizedManyNumberField, hasLocalizedManyTextField: subHasLocalizedManyTextField, hasLocalizedRelationshipField: subHasLocalizedRelationshipField, hasManyNumberField: subHasManyNumberField, hasManyTextField: subHasManyTextField, relationsToBuild: subRelationsToBuild } = buildTable({
366
405
  adapter,
367
406
  baseColumns,
368
407
  baseExtraConfig,
369
408
  disableNotNull: disableNotNullFromHere,
409
+ disableRelsTableUnique: true,
370
410
  disableUnique,
371
411
  fields: disableUnique ? idToUUID(block.fields) : block.fields,
372
- rootRelationsToBuild,
373
412
  rootRelationships: relationships,
413
+ rootRelationsToBuild,
374
414
  rootTableIDColType,
375
415
  rootTableName,
416
+ rootUniqueRelationships: uniqueRelationships,
376
417
  tableName: blockTableName,
377
- versions
418
+ versions,
419
+ withinLocalizedArrayOrBlock: isLocalized
378
420
  });
421
+ if (subHasLocalizedManyNumberField) {
422
+ hasLocalizedManyNumberField = subHasLocalizedManyNumberField;
423
+ }
424
+ if (subHasLocalizedRelationshipField) {
425
+ hasLocalizedRelationshipField = subHasLocalizedRelationshipField;
426
+ }
427
+ if (subHasLocalizedManyTextField) {
428
+ hasLocalizedManyTextField = subHasLocalizedManyTextField;
429
+ }
379
430
  if (subHasManyTextField) {
380
- if (!hasManyTextField || subHasManyTextField === 'index') hasManyTextField = subHasManyTextField;
431
+ if (!hasManyTextField || subHasManyTextField === 'index') {
432
+ hasManyTextField = subHasManyTextField;
433
+ }
381
434
  }
382
435
  if (subHasManyNumberField) {
383
- if (!hasManyNumberField || subHasManyNumberField === 'index') hasManyNumberField = subHasManyNumberField;
436
+ if (!hasManyNumberField || subHasManyNumberField === 'index') {
437
+ hasManyNumberField = subHasManyNumberField;
438
+ }
384
439
  }
385
440
  adapter.relations[`relations_${blockTableName}`] = relations(adapter.tables[blockTableName], ({ many, one })=>{
386
441
  const result = {
@@ -458,19 +513,33 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
458
513
  localesIndexes,
459
514
  newTableName,
460
515
  parentTableName,
461
- relationsToBuild,
462
516
  relationships,
517
+ relationsToBuild,
463
518
  rootRelationsToBuild,
464
519
  rootTableIDColType,
465
520
  rootTableName,
466
- versions
521
+ uniqueRelationships,
522
+ versions,
523
+ withinLocalizedArrayOrBlock
467
524
  });
468
- if (groupHasLocalizedField) hasLocalizedField = true;
469
- if (groupHasLocalizedRelationshipField) hasLocalizedRelationshipField = true;
470
- if (groupHasManyTextField) hasManyTextField = true;
471
- if (groupHasLocalizedManyTextField) hasLocalizedManyTextField = true;
472
- if (groupHasManyNumberField) hasManyNumberField = true;
473
- if (groupHasLocalizedManyNumberField) hasLocalizedManyNumberField = true;
525
+ if (groupHasLocalizedField) {
526
+ hasLocalizedField = true;
527
+ }
528
+ if (groupHasLocalizedRelationshipField) {
529
+ hasLocalizedRelationshipField = true;
530
+ }
531
+ if (groupHasManyTextField) {
532
+ hasManyTextField = true;
533
+ }
534
+ if (groupHasLocalizedManyTextField) {
535
+ hasLocalizedManyTextField = true;
536
+ }
537
+ if (groupHasManyNumberField) {
538
+ hasManyNumberField = true;
539
+ }
540
+ if (groupHasLocalizedManyNumberField) {
541
+ hasLocalizedManyNumberField = true;
542
+ }
474
543
  break;
475
544
  }
476
545
  const disableNotNullFromHere = Boolean(field.admin?.condition) || disableNotNull;
@@ -489,19 +558,33 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
489
558
  localesIndexes,
490
559
  newTableName: `${parentTableName}_${columnName}`,
491
560
  parentTableName,
492
- relationsToBuild,
493
561
  relationships,
562
+ relationsToBuild,
494
563
  rootRelationsToBuild,
495
564
  rootTableIDColType,
496
565
  rootTableName,
497
- versions
566
+ uniqueRelationships,
567
+ versions,
568
+ withinLocalizedArrayOrBlock: withinLocalizedArrayOrBlock || field.localized
498
569
  });
499
- if (groupHasLocalizedField) hasLocalizedField = true;
500
- if (groupHasLocalizedRelationshipField) hasLocalizedRelationshipField = true;
501
- if (groupHasManyTextField) hasManyTextField = true;
502
- if (groupHasLocalizedManyTextField) hasLocalizedManyTextField = true;
503
- if (groupHasManyNumberField) hasManyNumberField = true;
504
- if (groupHasLocalizedManyNumberField) hasLocalizedManyNumberField = true;
570
+ if (groupHasLocalizedField) {
571
+ hasLocalizedField = true;
572
+ }
573
+ if (groupHasLocalizedRelationshipField) {
574
+ hasLocalizedRelationshipField = true;
575
+ }
576
+ if (groupHasManyTextField) {
577
+ hasManyTextField = true;
578
+ }
579
+ if (groupHasLocalizedManyTextField) {
580
+ hasLocalizedManyTextField = true;
581
+ }
582
+ if (groupHasManyNumberField) {
583
+ hasManyNumberField = true;
584
+ }
585
+ if (groupHasLocalizedManyNumberField) {
586
+ hasLocalizedManyNumberField = true;
587
+ }
505
588
  break;
506
589
  }
507
590
  case 'tabs':
@@ -525,19 +608,33 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
525
608
  localesIndexes,
526
609
  newTableName,
527
610
  parentTableName,
528
- relationsToBuild,
529
611
  relationships,
612
+ relationsToBuild,
530
613
  rootRelationsToBuild,
531
614
  rootTableIDColType,
532
615
  rootTableName,
533
- versions
616
+ uniqueRelationships,
617
+ versions,
618
+ withinLocalizedArrayOrBlock
534
619
  });
535
- if (tabHasLocalizedField) hasLocalizedField = true;
536
- if (tabHasLocalizedRelationshipField) hasLocalizedRelationshipField = true;
537
- if (tabHasManyTextField) hasManyTextField = true;
538
- if (tabHasLocalizedManyTextField) hasLocalizedManyTextField = true;
539
- if (tabHasManyNumberField) hasManyNumberField = true;
540
- if (tabHasLocalizedManyNumberField) hasLocalizedManyNumberField = true;
620
+ if (tabHasLocalizedField) {
621
+ hasLocalizedField = true;
622
+ }
623
+ if (tabHasLocalizedRelationshipField) {
624
+ hasLocalizedRelationshipField = true;
625
+ }
626
+ if (tabHasManyTextField) {
627
+ hasManyTextField = true;
628
+ }
629
+ if (tabHasLocalizedManyTextField) {
630
+ hasLocalizedManyTextField = true;
631
+ }
632
+ if (tabHasManyNumberField) {
633
+ hasManyNumberField = true;
634
+ }
635
+ if (tabHasLocalizedManyNumberField) {
636
+ hasLocalizedManyNumberField = true;
637
+ }
541
638
  break;
542
639
  }
543
640
  case 'row':
@@ -559,27 +656,49 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
559
656
  localesIndexes,
560
657
  newTableName,
561
658
  parentTableName,
562
- relationsToBuild,
563
659
  relationships,
660
+ relationsToBuild,
564
661
  rootRelationsToBuild,
565
662
  rootTableIDColType,
566
663
  rootTableName,
567
- versions
664
+ uniqueRelationships,
665
+ versions,
666
+ withinLocalizedArrayOrBlock
568
667
  });
569
- if (rowHasLocalizedField) hasLocalizedField = true;
570
- if (rowHasLocalizedRelationshipField) hasLocalizedRelationshipField = true;
571
- if (rowHasManyTextField) hasManyTextField = true;
572
- if (rowHasLocalizedManyTextField) hasLocalizedManyTextField = true;
573
- if (rowHasManyNumberField) hasManyNumberField = true;
574
- if (rowHasLocalizedManyNumberField) hasLocalizedManyNumberField = true;
668
+ if (rowHasLocalizedField) {
669
+ hasLocalizedField = true;
670
+ }
671
+ if (rowHasLocalizedRelationshipField) {
672
+ hasLocalizedRelationshipField = true;
673
+ }
674
+ if (rowHasManyTextField) {
675
+ hasManyTextField = true;
676
+ }
677
+ if (rowHasLocalizedManyTextField) {
678
+ hasLocalizedManyTextField = true;
679
+ }
680
+ if (rowHasManyNumberField) {
681
+ hasManyNumberField = true;
682
+ }
683
+ if (rowHasLocalizedManyNumberField) {
684
+ hasLocalizedManyNumberField = true;
685
+ }
575
686
  break;
576
687
  }
577
688
  case 'relationship':
578
689
  case 'upload':
579
690
  if (Array.isArray(field.relationTo)) {
580
- field.relationTo.forEach((relation)=>relationships.add(relation));
581
- } else if (field.type === 'relationship' && field.hasMany) {
691
+ field.relationTo.forEach((relation)=>{
692
+ relationships.add(relation);
693
+ if (field.unique && !disableUnique && !disableRelsTableUnique) {
694
+ uniqueRelationships.add(relation);
695
+ }
696
+ });
697
+ } else if (field.hasMany) {
582
698
  relationships.add(field.relationTo);
699
+ if (field.unique && !disableUnique && !disableRelsTableUnique) {
700
+ uniqueRelationships.add(field.relationTo);
701
+ }
583
702
  } else {
584
703
  // simple relationships get a column on the targetTable with a foreign key to the relationTo table
585
704
  const relationshipConfig = adapter.payload.collections[field.relationTo].config;
@@ -587,8 +706,12 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
587
706
  // get the id type of the related collection
588
707
  let colType = 'integer';
589
708
  const relatedCollectionCustomID = relationshipConfig.fields.find((field)=>fieldAffectsData(field) && field.name === 'id');
590
- if (relatedCollectionCustomID?.type === 'number') colType = 'numeric';
591
- if (relatedCollectionCustomID?.type === 'text') colType = 'text';
709
+ if (relatedCollectionCustomID?.type === 'number') {
710
+ colType = 'numeric';
711
+ }
712
+ if (relatedCollectionCustomID?.type === 'text') {
713
+ colType = 'text';
714
+ }
592
715
  // make the foreign key column for relationship using the correct id column type
593
716
  targetTable[fieldName] = getIDColumn({
594
717
  name: `${columnName}_id`,
@@ -600,7 +723,7 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
600
723
  // add relationship to table
601
724
  relationsToBuild.set(fieldName, {
602
725
  type: 'one',
603
- localized: adapter.payload.config.localization && field.localized,
726
+ localized: adapter.payload.config.localization && (field.localized || forceLocalized),
604
727
  target: tableName
605
728
  });
606
729
  // add notNull when not required
@@ -609,7 +732,7 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
609
732
  }
610
733
  break;
611
734
  }
612
- if (adapter.payload.config.localization && field.localized) {
735
+ if (Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock) {
613
736
  hasLocalizedRelationshipField = true;
614
737
  }
615
738
  break;