@payloadcms/db-sqlite 3.0.0-canary.6d066c2 → 3.0.0-canary.6f0a417

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 (46) hide show
  1. package/README.md +1 -1
  2. package/dist/connect.d.ts.map +1 -1
  3. package/dist/connect.js +15 -3
  4. package/dist/connect.js.map +1 -1
  5. package/dist/countDistinct.d.ts.map +1 -1
  6. package/dist/countDistinct.js +3 -3
  7. package/dist/countDistinct.js.map +1 -1
  8. package/dist/createMigration.d.ts.map +1 -1
  9. package/dist/createMigration.js +5 -2
  10. package/dist/createMigration.js.map +1 -1
  11. package/dist/defaultSnapshot.d.ts +1 -1
  12. package/dist/defaultSnapshot.d.ts.map +1 -1
  13. package/dist/defaultSnapshot.js +1 -1
  14. package/dist/defaultSnapshot.js.map +1 -1
  15. package/dist/getMigrationTemplate.d.ts +1 -0
  16. package/dist/getMigrationTemplate.d.ts.map +1 -1
  17. package/dist/getMigrationTemplate.js +3 -2
  18. package/dist/getMigrationTemplate.js.map +1 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +8 -3
  21. package/dist/index.js.map +1 -1
  22. package/dist/init.d.ts.map +1 -1
  23. package/dist/init.js +35 -4
  24. package/dist/init.js.map +1 -1
  25. package/dist/requireDrizzleKit.js +1 -1
  26. package/dist/requireDrizzleKit.js.map +1 -1
  27. package/dist/schema/build.d.ts +21 -17
  28. package/dist/schema/build.d.ts.map +1 -1
  29. package/dist/schema/build.js +42 -11
  30. package/dist/schema/build.js.map +1 -1
  31. package/dist/schema/createIndex.d.ts +2 -2
  32. package/dist/schema/createIndex.d.ts.map +1 -1
  33. package/dist/schema/createIndex.js +4 -2
  34. package/dist/schema/createIndex.js.map +1 -1
  35. package/dist/schema/traverseFields.d.ts +11 -3
  36. package/dist/schema/traverseFields.d.ts.map +1 -1
  37. package/dist/schema/traverseFields.js +225 -78
  38. package/dist/schema/traverseFields.js.map +1 -1
  39. package/dist/schema/withDefault.d.ts +4 -0
  40. package/dist/schema/withDefault.d.ts.map +1 -0
  41. package/dist/schema/withDefault.js +12 -0
  42. package/dist/schema/withDefault.js.map +1 -0
  43. package/dist/types.d.ts +46 -19
  44. package/dist/types.d.ts.map +1 -1
  45. package/dist/types.js.map +1 -1
  46. package/package.json +10 -8
@@ -1,14 +1,15 @@
1
- /* eslint-disable no-param-reassign */ import { createTableName, hasLocalesTable, validateExistingBlockIsIdentical } from '@payloadcms/drizzle';
1
+ import { 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
- export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull, disableUnique = false, fieldPrefix, fields, forceLocalized, indexes, locales, localesColumns, localesIndexes, newTableName, parentTableName, relationsToBuild, relationships, rootRelationsToBuild, rootTableIDColType, rootTableName, versions })=>{
11
+ import { withDefault } from './withDefault.js';
12
+ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull, disableRelsTableUnique, disableUnique = false, fieldPrefix, fields, forceLocalized, indexes, joins, locales, localesColumns, localesIndexes, newTableName, parentTableName, relationships, relationsToBuild, rootRelationsToBuild, rootTableIDColType, rootTableName, uniqueRelationships, versions, withinLocalizedArrayOrBlock })=>{
12
13
  let hasLocalizedField = false;
13
14
  let hasLocalizedRelationshipField = false;
14
15
  let hasManyTextField = false;
@@ -16,11 +17,22 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
16
17
  let hasManyNumberField = false;
17
18
  let hasLocalizedManyNumberField = false;
18
19
  let parentIDColType = 'integer';
19
- if (columns.id instanceof SQLiteIntegerBuilder) parentIDColType = 'integer';
20
- if (columns.id instanceof SQLiteNumericBuilder) parentIDColType = 'numeric';
21
- 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
+ }
22
29
  fields.forEach((field)=>{
23
- 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
+ }
24
36
  let columnName;
25
37
  let fieldName;
26
38
  let targetTable = columns;
@@ -35,14 +47,15 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
35
47
  targetTable = localesColumns;
36
48
  targetIndexes = localesIndexes;
37
49
  }
38
- if ((field.unique || field.index) && ![
50
+ if ((field.unique || field.index || [
51
+ 'relationship',
52
+ 'upload'
53
+ ].includes(field.type)) && ![
39
54
  'array',
40
55
  'blocks',
41
56
  'group',
42
- 'point',
43
- 'relationship',
44
- 'upload'
45
- ].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))) {
46
59
  const unique = disableUnique !== true && field.unique;
47
60
  if (unique) {
48
61
  const constraintValue = `${fieldPrefix || ''}${field.name}`;
@@ -52,7 +65,10 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
52
65
  adapter.fieldConstraints[rootTableName][`${columnName}_idx`] = constraintValue;
53
66
  }
54
67
  targetIndexes[`${newTableName}_${field.name}Idx`] = createIndex({
55
- name: fieldName,
68
+ name: field.localized ? [
69
+ fieldName,
70
+ '_locale'
71
+ ] : fieldName,
56
72
  columnName,
57
73
  tableName: newTableName,
58
74
  unique
@@ -63,7 +79,8 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
63
79
  case 'text':
64
80
  {
65
81
  if (field.hasMany) {
66
- if (field.localized) {
82
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
83
+ if (isLocalized) {
67
84
  hasLocalizedManyTextField = true;
68
85
  }
69
86
  if (field.index) {
@@ -75,7 +92,7 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
75
92
  throw new InvalidConfiguration('Unique is not supported in SQLite for hasMany text fields.');
76
93
  }
77
94
  } else {
78
- targetTable[fieldName] = text(columnName);
95
+ targetTable[fieldName] = withDefault(text(columnName), field);
79
96
  }
80
97
  break;
81
98
  }
@@ -83,13 +100,14 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
83
100
  case 'code':
84
101
  case 'textarea':
85
102
  {
86
- targetTable[fieldName] = text(columnName);
103
+ targetTable[fieldName] = withDefault(text(columnName), field);
87
104
  break;
88
105
  }
89
106
  case 'number':
90
107
  {
91
108
  if (field.hasMany) {
92
- if (field.localized) {
109
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
110
+ if (isLocalized) {
93
111
  hasLocalizedManyNumberField = true;
94
112
  }
95
113
  if (field.index) {
@@ -101,21 +119,21 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
101
119
  throw new InvalidConfiguration('Unique is not supported in Postgres for hasMany number fields.');
102
120
  }
103
121
  } else {
104
- targetTable[fieldName] = numeric(columnName);
122
+ targetTable[fieldName] = withDefault(numeric(columnName), field);
105
123
  }
106
124
  break;
107
125
  }
108
126
  case 'richText':
109
127
  case 'json':
110
128
  {
111
- targetTable[fieldName] = text(columnName, {
129
+ targetTable[fieldName] = withDefault(text(columnName, {
112
130
  mode: 'json'
113
- });
131
+ }), field);
114
132
  break;
115
133
  }
116
134
  case 'date':
117
135
  {
118
- targetTable[fieldName] = text(columnName);
136
+ targetTable[fieldName] = withDefault(text(columnName), field);
119
137
  break;
120
138
  }
121
139
  case 'point':
@@ -164,7 +182,8 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
164
182
  }).onDelete('cascade'),
165
183
  parentIdx: (cols)=>index(`${selectTableName}_parent_idx`).on(cols.parent)
166
184
  };
167
- if (field.localized) {
185
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
186
+ if (isLocalized) {
168
187
  baseColumns.locale = text('locale', {
169
188
  enum: locales
170
189
  }).notNull();
@@ -202,17 +221,17 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
202
221
  })
203
222
  }));
204
223
  } else {
205
- targetTable[fieldName] = text(fieldName, {
224
+ targetTable[fieldName] = withDefault(text(columnName, {
206
225
  enum: options
207
- });
226
+ }), field);
208
227
  }
209
228
  break;
210
229
  }
211
230
  case 'checkbox':
212
231
  {
213
- targetTable[fieldName] = integer(columnName, {
232
+ targetTable[fieldName] = withDefault(integer(columnName, {
214
233
  mode: 'boolean'
215
- });
234
+ }), field);
216
235
  break;
217
236
  }
218
237
  case 'array':
@@ -247,31 +266,48 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
247
266
  }).onDelete('cascade'),
248
267
  _parentIDIdx: (cols)=>index(`${arrayTableName}_parent_id_idx`).on(cols._parentID)
249
268
  };
250
- if (field.localized && adapter.payload.config.localization) {
269
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
270
+ if (isLocalized) {
251
271
  baseColumns._locale = text('_locale', {
252
272
  enum: locales
253
273
  }).notNull();
254
274
  baseExtraConfig._localeIdx = (cols)=>index(`${arrayTableName}_locale_idx`).on(cols._locale);
255
275
  }
256
- const { hasManyNumberField: subHasManyNumberField, hasManyTextField: subHasManyTextField, relationsToBuild: subRelationsToBuild } = buildTable({
276
+ const { hasLocalizedManyNumberField: subHasLocalizedManyNumberField, hasLocalizedManyTextField: subHasLocalizedManyTextField, hasLocalizedRelationshipField: subHasLocalizedRelationshipField, hasManyNumberField: subHasManyNumberField, hasManyTextField: subHasManyTextField, relationsToBuild: subRelationsToBuild } = buildTable({
257
277
  adapter,
258
278
  baseColumns,
259
279
  baseExtraConfig,
260
280
  disableNotNull: disableNotNullFromHere,
281
+ disableRelsTableUnique: true,
261
282
  disableUnique,
262
283
  fields: disableUnique ? idToUUID(field.fields) : field.fields,
263
- rootRelationsToBuild,
264
284
  rootRelationships: relationships,
285
+ rootRelationsToBuild,
265
286
  rootTableIDColType,
266
287
  rootTableName,
288
+ rootUniqueRelationships: uniqueRelationships,
267
289
  tableName: arrayTableName,
268
- versions
290
+ versions,
291
+ withinLocalizedArrayOrBlock: isLocalized
269
292
  });
293
+ if (subHasLocalizedManyNumberField) {
294
+ hasLocalizedManyNumberField = subHasLocalizedManyNumberField;
295
+ }
296
+ if (subHasLocalizedRelationshipField) {
297
+ hasLocalizedRelationshipField = subHasLocalizedRelationshipField;
298
+ }
299
+ if (subHasLocalizedManyTextField) {
300
+ hasLocalizedManyTextField = subHasLocalizedManyTextField;
301
+ }
270
302
  if (subHasManyTextField) {
271
- if (!hasManyTextField || subHasManyTextField === 'index') hasManyTextField = subHasManyTextField;
303
+ if (!hasManyTextField || subHasManyTextField === 'index') {
304
+ hasManyTextField = subHasManyTextField;
305
+ }
272
306
  }
273
307
  if (subHasManyNumberField) {
274
- if (!hasManyNumberField || subHasManyNumberField === 'index') hasManyNumberField = subHasManyNumberField;
308
+ if (!hasManyNumberField || subHasManyNumberField === 'index') {
309
+ hasManyNumberField = subHasManyNumberField;
310
+ }
275
311
  }
276
312
  relationsToBuild.set(fieldName, {
277
313
  type: 'many',
@@ -343,7 +379,6 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
343
379
  };
344
380
  const baseExtraConfig = {
345
381
  _orderIdx: (cols)=>index(`${blockTableName}_order_idx`).on(cols._order),
346
- _parentIDIdx: (cols)=>index(`${blockTableName}_parent_id_idx`).on(cols._parentID),
347
382
  _parentIdFk: (cols)=>foreignKey({
348
383
  name: `${blockTableName}_parent_id_fk`,
349
384
  columns: [
@@ -353,33 +388,51 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
353
388
  adapter.tables[rootTableName].id
354
389
  ]
355
390
  }).onDelete('cascade'),
391
+ _parentIDIdx: (cols)=>index(`${blockTableName}_parent_id_idx`).on(cols._parentID),
356
392
  _pathIdx: (cols)=>index(`${blockTableName}_path_idx`).on(cols._path)
357
393
  };
358
- if (field.localized && adapter.payload.config.localization) {
394
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
395
+ if (isLocalized) {
359
396
  baseColumns._locale = text('_locale', {
360
397
  enum: locales
361
398
  }).notNull();
362
399
  baseExtraConfig._localeIdx = (cols)=>index(`${blockTableName}_locale_idx`).on(cols._locale);
363
400
  }
364
- const { hasManyNumberField: subHasManyNumberField, hasManyTextField: subHasManyTextField, relationsToBuild: subRelationsToBuild } = buildTable({
401
+ const { hasLocalizedManyNumberField: subHasLocalizedManyNumberField, hasLocalizedManyTextField: subHasLocalizedManyTextField, hasLocalizedRelationshipField: subHasLocalizedRelationshipField, hasManyNumberField: subHasManyNumberField, hasManyTextField: subHasManyTextField, relationsToBuild: subRelationsToBuild } = buildTable({
365
402
  adapter,
366
403
  baseColumns,
367
404
  baseExtraConfig,
368
405
  disableNotNull: disableNotNullFromHere,
406
+ disableRelsTableUnique: true,
369
407
  disableUnique,
370
408
  fields: disableUnique ? idToUUID(block.fields) : block.fields,
371
- rootRelationsToBuild,
372
409
  rootRelationships: relationships,
410
+ rootRelationsToBuild,
373
411
  rootTableIDColType,
374
412
  rootTableName,
413
+ rootUniqueRelationships: uniqueRelationships,
375
414
  tableName: blockTableName,
376
- versions
415
+ versions,
416
+ withinLocalizedArrayOrBlock: isLocalized
377
417
  });
418
+ if (subHasLocalizedManyNumberField) {
419
+ hasLocalizedManyNumberField = subHasLocalizedManyNumberField;
420
+ }
421
+ if (subHasLocalizedRelationshipField) {
422
+ hasLocalizedRelationshipField = subHasLocalizedRelationshipField;
423
+ }
424
+ if (subHasLocalizedManyTextField) {
425
+ hasLocalizedManyTextField = subHasLocalizedManyTextField;
426
+ }
378
427
  if (subHasManyTextField) {
379
- if (!hasManyTextField || subHasManyTextField === 'index') hasManyTextField = subHasManyTextField;
428
+ if (!hasManyTextField || subHasManyTextField === 'index') {
429
+ hasManyTextField = subHasManyTextField;
430
+ }
380
431
  }
381
432
  if (subHasManyNumberField) {
382
- if (!hasManyNumberField || subHasManyNumberField === 'index') hasManyNumberField = subHasManyNumberField;
433
+ if (!hasManyNumberField || subHasManyNumberField === 'index') {
434
+ hasManyNumberField = subHasManyNumberField;
435
+ }
383
436
  }
384
437
  adapter.relations[`relations_${blockTableName}`] = relations(adapter.tables[blockTableName], ({ many, one })=>{
385
438
  const result = {
@@ -452,24 +505,39 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
452
505
  fields: field.fields,
453
506
  forceLocalized,
454
507
  indexes,
508
+ joins,
455
509
  locales,
456
510
  localesColumns,
457
511
  localesIndexes,
458
512
  newTableName,
459
513
  parentTableName,
460
- relationsToBuild,
461
514
  relationships,
515
+ relationsToBuild,
462
516
  rootRelationsToBuild,
463
517
  rootTableIDColType,
464
518
  rootTableName,
465
- versions
519
+ uniqueRelationships,
520
+ versions,
521
+ withinLocalizedArrayOrBlock
466
522
  });
467
- if (groupHasLocalizedField) hasLocalizedField = true;
468
- if (groupHasLocalizedRelationshipField) hasLocalizedRelationshipField = true;
469
- if (groupHasManyTextField) hasManyTextField = true;
470
- if (groupHasLocalizedManyTextField) hasLocalizedManyTextField = true;
471
- if (groupHasManyNumberField) hasManyNumberField = true;
472
- if (groupHasLocalizedManyNumberField) hasLocalizedManyNumberField = true;
523
+ if (groupHasLocalizedField) {
524
+ hasLocalizedField = true;
525
+ }
526
+ if (groupHasLocalizedRelationshipField) {
527
+ hasLocalizedRelationshipField = true;
528
+ }
529
+ if (groupHasManyTextField) {
530
+ hasManyTextField = true;
531
+ }
532
+ if (groupHasLocalizedManyTextField) {
533
+ hasLocalizedManyTextField = true;
534
+ }
535
+ if (groupHasManyNumberField) {
536
+ hasManyNumberField = true;
537
+ }
538
+ if (groupHasLocalizedManyNumberField) {
539
+ hasLocalizedManyNumberField = true;
540
+ }
473
541
  break;
474
542
  }
475
543
  const disableNotNullFromHere = Boolean(field.admin?.condition) || disableNotNull;
@@ -483,24 +551,39 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
483
551
  fields: field.fields,
484
552
  forceLocalized: field.localized,
485
553
  indexes,
554
+ joins,
486
555
  locales,
487
556
  localesColumns,
488
557
  localesIndexes,
489
558
  newTableName: `${parentTableName}_${columnName}`,
490
559
  parentTableName,
491
- relationsToBuild,
492
560
  relationships,
561
+ relationsToBuild,
493
562
  rootRelationsToBuild,
494
563
  rootTableIDColType,
495
564
  rootTableName,
496
- versions
565
+ uniqueRelationships,
566
+ versions,
567
+ withinLocalizedArrayOrBlock: withinLocalizedArrayOrBlock || field.localized
497
568
  });
498
- if (groupHasLocalizedField) hasLocalizedField = true;
499
- if (groupHasLocalizedRelationshipField) hasLocalizedRelationshipField = true;
500
- if (groupHasManyTextField) hasManyTextField = true;
501
- if (groupHasLocalizedManyTextField) hasLocalizedManyTextField = true;
502
- if (groupHasManyNumberField) hasManyNumberField = true;
503
- if (groupHasLocalizedManyNumberField) hasLocalizedManyNumberField = true;
569
+ if (groupHasLocalizedField) {
570
+ hasLocalizedField = true;
571
+ }
572
+ if (groupHasLocalizedRelationshipField) {
573
+ hasLocalizedRelationshipField = true;
574
+ }
575
+ if (groupHasManyTextField) {
576
+ hasManyTextField = true;
577
+ }
578
+ if (groupHasLocalizedManyTextField) {
579
+ hasLocalizedManyTextField = true;
580
+ }
581
+ if (groupHasManyNumberField) {
582
+ hasManyNumberField = true;
583
+ }
584
+ if (groupHasLocalizedManyNumberField) {
585
+ hasLocalizedManyNumberField = true;
586
+ }
504
587
  break;
505
588
  }
506
589
  case 'tabs':
@@ -519,24 +602,39 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
519
602
  })),
520
603
  forceLocalized,
521
604
  indexes,
605
+ joins,
522
606
  locales,
523
607
  localesColumns,
524
608
  localesIndexes,
525
609
  newTableName,
526
610
  parentTableName,
527
- relationsToBuild,
528
611
  relationships,
612
+ relationsToBuild,
529
613
  rootRelationsToBuild,
530
614
  rootTableIDColType,
531
615
  rootTableName,
532
- versions
616
+ uniqueRelationships,
617
+ versions,
618
+ withinLocalizedArrayOrBlock
533
619
  });
534
- if (tabHasLocalizedField) hasLocalizedField = true;
535
- if (tabHasLocalizedRelationshipField) hasLocalizedRelationshipField = true;
536
- if (tabHasManyTextField) hasManyTextField = true;
537
- if (tabHasLocalizedManyTextField) hasLocalizedManyTextField = true;
538
- if (tabHasManyNumberField) hasManyNumberField = true;
539
- 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
+ }
540
638
  break;
541
639
  }
542
640
  case 'row':
@@ -553,32 +651,55 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
553
651
  fields: field.fields,
554
652
  forceLocalized,
555
653
  indexes,
654
+ joins,
556
655
  locales,
557
656
  localesColumns,
558
657
  localesIndexes,
559
658
  newTableName,
560
659
  parentTableName,
561
- relationsToBuild,
562
660
  relationships,
661
+ relationsToBuild,
563
662
  rootRelationsToBuild,
564
663
  rootTableIDColType,
565
664
  rootTableName,
566
- versions
665
+ uniqueRelationships,
666
+ versions,
667
+ withinLocalizedArrayOrBlock
567
668
  });
568
- if (rowHasLocalizedField) hasLocalizedField = true;
569
- if (rowHasLocalizedRelationshipField) hasLocalizedRelationshipField = true;
570
- if (rowHasManyTextField) hasManyTextField = true;
571
- if (rowHasLocalizedManyTextField) hasLocalizedManyTextField = true;
572
- if (rowHasManyNumberField) hasManyNumberField = true;
573
- if (rowHasLocalizedManyNumberField) hasLocalizedManyNumberField = true;
669
+ if (rowHasLocalizedField) {
670
+ hasLocalizedField = true;
671
+ }
672
+ if (rowHasLocalizedRelationshipField) {
673
+ hasLocalizedRelationshipField = true;
674
+ }
675
+ if (rowHasManyTextField) {
676
+ hasManyTextField = true;
677
+ }
678
+ if (rowHasLocalizedManyTextField) {
679
+ hasLocalizedManyTextField = true;
680
+ }
681
+ if (rowHasManyNumberField) {
682
+ hasManyNumberField = true;
683
+ }
684
+ if (rowHasLocalizedManyNumberField) {
685
+ hasLocalizedManyNumberField = true;
686
+ }
574
687
  break;
575
688
  }
576
689
  case 'relationship':
577
690
  case 'upload':
578
691
  if (Array.isArray(field.relationTo)) {
579
- field.relationTo.forEach((relation)=>relationships.add(relation));
580
- } else if (field.type === 'relationship' && field.hasMany) {
692
+ field.relationTo.forEach((relation)=>{
693
+ relationships.add(relation);
694
+ if (field.unique && !disableUnique && !disableRelsTableUnique) {
695
+ uniqueRelationships.add(relation);
696
+ }
697
+ });
698
+ } else if (field.hasMany) {
581
699
  relationships.add(field.relationTo);
700
+ if (field.unique && !disableUnique && !disableRelsTableUnique) {
701
+ uniqueRelationships.add(field.relationTo);
702
+ }
582
703
  } else {
583
704
  // simple relationships get a column on the targetTable with a foreign key to the relationTo table
584
705
  const relationshipConfig = adapter.payload.collections[field.relationTo].config;
@@ -586,8 +707,12 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
586
707
  // get the id type of the related collection
587
708
  let colType = 'integer';
588
709
  const relatedCollectionCustomID = relationshipConfig.fields.find((field)=>fieldAffectsData(field) && field.name === 'id');
589
- if (relatedCollectionCustomID?.type === 'number') colType = 'numeric';
590
- if (relatedCollectionCustomID?.type === 'text') colType = 'text';
710
+ if (relatedCollectionCustomID?.type === 'number') {
711
+ colType = 'numeric';
712
+ }
713
+ if (relatedCollectionCustomID?.type === 'text') {
714
+ colType = 'text';
715
+ }
591
716
  // make the foreign key column for relationship using the correct id column type
592
717
  targetTable[fieldName] = getIDColumn({
593
718
  name: `${columnName}_id`,
@@ -599,7 +724,7 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
599
724
  // add relationship to table
600
725
  relationsToBuild.set(fieldName, {
601
726
  type: 'one',
602
- localized: adapter.payload.config.localization && field.localized,
727
+ localized: adapter.payload.config.localization && (field.localized || forceLocalized),
603
728
  target: tableName
604
729
  });
605
730
  // add notNull when not required
@@ -608,10 +733,32 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
608
733
  }
609
734
  break;
610
735
  }
611
- if (adapter.payload.config.localization && field.localized) {
736
+ if (Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock) {
612
737
  hasLocalizedRelationshipField = true;
613
738
  }
614
739
  break;
740
+ case 'join':
741
+ {
742
+ // fieldName could be 'posts' or 'group_posts'
743
+ // using `on` as the key for the relation
744
+ const localized = adapter.payload.config.localization && field.localized;
745
+ const fieldSchemaPath = `${fieldPrefix || ''}${field.name}`;
746
+ let target;
747
+ const joinConfig = joins[field.collection].find(({ schemaPath })=>fieldSchemaPath === schemaPath);
748
+ if (joinConfig.targetField.hasMany) {
749
+ target = `${adapter.tableNameMap.get(toSnakeCase(field.collection))}${adapter.relationshipsSuffix}`;
750
+ } else {
751
+ target = `${adapter.tableNameMap.get(toSnakeCase(field.collection))}${localized ? adapter.localesSuffix : ''}`;
752
+ }
753
+ relationsToBuild.set(fieldName, {
754
+ type: 'many',
755
+ // joins are not localized on the parent table
756
+ localized: false,
757
+ relationName: field.on.replaceAll('.', '_'),
758
+ target
759
+ });
760
+ break;
761
+ }
615
762
  default:
616
763
  break;
617
764
  }