@payloadcms/db-sqlite 3.0.0-canary.518fabe → 3.0.0-canary.5624723

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
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, relationships, relationsToBuild, rootRelationsToBuild, rootTableIDColType, rootTableName, versions, withinLocalizedArrayOrBlock })=>{
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;
@@ -30,6 +30,9 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
30
30
  if ('name' in field && field.name === 'id') {
31
31
  return;
32
32
  }
33
+ if (fieldIsVirtual(field)) {
34
+ return;
35
+ }
33
36
  let columnName;
34
37
  let fieldName;
35
38
  let targetTable = columns;
@@ -44,14 +47,15 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
44
47
  targetTable = localesColumns;
45
48
  targetIndexes = localesIndexes;
46
49
  }
47
- if ((field.unique || field.index) && ![
50
+ if ((field.unique || field.index || [
51
+ 'relationship',
52
+ 'upload'
53
+ ].includes(field.type)) && ![
48
54
  'array',
49
55
  'blocks',
50
56
  'group',
51
- 'point',
52
- 'relationship',
53
- 'upload'
54
- ].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))) {
55
59
  const unique = disableUnique !== true && field.unique;
56
60
  if (unique) {
57
61
  const constraintValue = `${fieldPrefix || ''}${field.name}`;
@@ -60,173 +64,21 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
60
64
  }
61
65
  adapter.fieldConstraints[rootTableName][`${columnName}_idx`] = constraintValue;
62
66
  }
63
- targetIndexes[`${newTableName}_${field.name}Idx`] = createIndex({
64
- name: fieldName,
65
- columnName,
66
- 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,
67
77
  unique
68
78
  });
69
79
  }
70
80
  }
71
81
  switch(field.type){
72
- case 'text':
73
- {
74
- if (field.hasMany) {
75
- const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock;
76
- if (isLocalized) {
77
- hasLocalizedManyTextField = true;
78
- }
79
- if (field.index) {
80
- hasManyTextField = 'index';
81
- } else if (!hasManyTextField) {
82
- hasManyTextField = true;
83
- }
84
- if (field.unique) {
85
- throw new InvalidConfiguration('Unique is not supported in SQLite for hasMany text fields.');
86
- }
87
- } else {
88
- targetTable[fieldName] = withDefault(text(columnName), field);
89
- }
90
- break;
91
- }
92
- case 'email':
93
- case 'code':
94
- case 'textarea':
95
- {
96
- targetTable[fieldName] = withDefault(text(columnName), field);
97
- break;
98
- }
99
- case 'number':
100
- {
101
- if (field.hasMany) {
102
- const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock;
103
- if (isLocalized) {
104
- hasLocalizedManyNumberField = true;
105
- }
106
- if (field.index) {
107
- hasManyNumberField = 'index';
108
- } else if (!hasManyNumberField) {
109
- hasManyNumberField = true;
110
- }
111
- if (field.unique) {
112
- throw new InvalidConfiguration('Unique is not supported in Postgres for hasMany number fields.');
113
- }
114
- } else {
115
- targetTable[fieldName] = withDefault(numeric(columnName), field);
116
- }
117
- break;
118
- }
119
- case 'richText':
120
- case 'json':
121
- {
122
- targetTable[fieldName] = withDefault(text(columnName, {
123
- mode: 'json'
124
- }), field);
125
- break;
126
- }
127
- case 'date':
128
- {
129
- targetTable[fieldName] = withDefault(text(columnName), field);
130
- break;
131
- }
132
- case 'point':
133
- {
134
- break;
135
- }
136
- case 'radio':
137
- case 'select':
138
- {
139
- const options = field.options.map((option)=>{
140
- if (optionIsObject(option)) {
141
- return option.value;
142
- }
143
- return option;
144
- });
145
- if (field.type === 'select' && field.hasMany) {
146
- const selectTableName = createTableName({
147
- adapter,
148
- config: field,
149
- parentTableName: newTableName,
150
- prefix: `${newTableName}_`,
151
- versionsCustomName: versions
152
- });
153
- const baseColumns = {
154
- order: integer('order').notNull(),
155
- parent: getIDColumn({
156
- name: 'parent_id',
157
- type: parentIDColType,
158
- notNull: true,
159
- primaryKey: false
160
- }),
161
- value: text('value', {
162
- enum: options
163
- })
164
- };
165
- const baseExtraConfig = {
166
- orderIdx: (cols)=>index(`${selectTableName}_order_idx`).on(cols.order),
167
- parentFk: (cols)=>foreignKey({
168
- name: `${selectTableName}_parent_fk`,
169
- columns: [
170
- cols.parent
171
- ],
172
- foreignColumns: [
173
- adapter.tables[parentTableName].id
174
- ]
175
- }).onDelete('cascade'),
176
- parentIdx: (cols)=>index(`${selectTableName}_parent_idx`).on(cols.parent)
177
- };
178
- const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock;
179
- if (isLocalized) {
180
- baseColumns.locale = text('locale', {
181
- enum: locales
182
- }).notNull();
183
- baseExtraConfig.localeIdx = (cols)=>index(`${selectTableName}_locale_idx`).on(cols.locale);
184
- }
185
- if (field.index) {
186
- baseExtraConfig.value = (cols)=>index(`${selectTableName}_value_idx`).on(cols.value);
187
- }
188
- buildTable({
189
- adapter,
190
- baseColumns,
191
- baseExtraConfig,
192
- disableNotNull,
193
- disableUnique,
194
- fields: [],
195
- rootTableName,
196
- tableName: selectTableName,
197
- versions
198
- });
199
- relationsToBuild.set(fieldName, {
200
- type: 'many',
201
- // selects have their own localized table, independent of the base table.
202
- localized: false,
203
- target: selectTableName
204
- });
205
- adapter.relations[`relations_${selectTableName}`] = relations(adapter.tables[selectTableName], ({ one })=>({
206
- parent: one(adapter.tables[parentTableName], {
207
- fields: [
208
- adapter.tables[selectTableName].parent
209
- ],
210
- references: [
211
- adapter.tables[parentTableName].id
212
- ],
213
- relationName: fieldName
214
- })
215
- }));
216
- } else {
217
- targetTable[fieldName] = withDefault(text(fieldName, {
218
- enum: options
219
- }), field);
220
- }
221
- break;
222
- }
223
- case 'checkbox':
224
- {
225
- targetTable[fieldName] = withDefault(integer(columnName, {
226
- mode: 'boolean'
227
- }), field);
228
- break;
229
- }
230
82
  case 'array':
231
83
  {
232
84
  const disableNotNullFromHere = Boolean(field.admin?.condition) || disableNotNull;
@@ -259,7 +111,7 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
259
111
  }).onDelete('cascade'),
260
112
  _parentIDIdx: (cols)=>index(`${arrayTableName}_parent_id_idx`).on(cols._parentID)
261
113
  };
262
- const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock;
114
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
263
115
  if (isLocalized) {
264
116
  baseColumns._locale = text('_locale', {
265
117
  enum: locales
@@ -271,12 +123,14 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
271
123
  baseColumns,
272
124
  baseExtraConfig,
273
125
  disableNotNull: disableNotNullFromHere,
126
+ disableRelsTableUnique: true,
274
127
  disableUnique,
275
128
  fields: disableUnique ? idToUUID(field.fields) : field.fields,
276
129
  rootRelationships: relationships,
277
130
  rootRelationsToBuild,
278
131
  rootTableIDColType,
279
132
  rootTableName,
133
+ rootUniqueRelationships: uniqueRelationships,
280
134
  tableName: arrayTableName,
281
135
  versions,
282
136
  withinLocalizedArrayOrBlock: isLocalized
@@ -382,7 +236,7 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
382
236
  _parentIDIdx: (cols)=>index(`${blockTableName}_parent_id_idx`).on(cols._parentID),
383
237
  _pathIdx: (cols)=>index(`${blockTableName}_path_idx`).on(cols._path)
384
238
  };
385
- const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock;
239
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
386
240
  if (isLocalized) {
387
241
  baseColumns._locale = text('_locale', {
388
242
  enum: locales
@@ -394,12 +248,14 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
394
248
  baseColumns,
395
249
  baseExtraConfig,
396
250
  disableNotNull: disableNotNullFromHere,
251
+ disableRelsTableUnique: true,
397
252
  disableUnique,
398
253
  fields: disableUnique ? idToUUID(block.fields) : block.fields,
399
254
  rootRelationships: relationships,
400
255
  rootRelationsToBuild,
401
256
  rootTableIDColType,
402
257
  rootTableName,
258
+ rootUniqueRelationships: uniqueRelationships,
403
259
  tableName: blockTableName,
404
260
  versions,
405
261
  withinLocalizedArrayOrBlock: isLocalized
@@ -480,8 +336,75 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
480
336
  });
481
337
  break;
482
338
  }
483
- case 'tab':
339
+ case 'checkbox':
340
+ {
341
+ targetTable[fieldName] = withDefault(integer(columnName, {
342
+ mode: 'boolean'
343
+ }), field);
344
+ break;
345
+ }
346
+ case 'code':
347
+ case 'email':
348
+ case 'textarea':
349
+ {
350
+ targetTable[fieldName] = withDefault(text(columnName), field);
351
+ break;
352
+ }
353
+ case 'collapsible':
354
+ case 'row':
355
+ {
356
+ const disableNotNullFromHere = Boolean(field.admin?.condition) || disableNotNull;
357
+ const { hasLocalizedField: rowHasLocalizedField, hasLocalizedManyNumberField: rowHasLocalizedManyNumberField, hasLocalizedManyTextField: rowHasLocalizedManyTextField, hasLocalizedRelationshipField: rowHasLocalizedRelationshipField, hasManyNumberField: rowHasManyNumberField, hasManyTextField: rowHasManyTextField } = traverseFields({
358
+ adapter,
359
+ columnPrefix,
360
+ columns,
361
+ disableNotNull: disableNotNullFromHere,
362
+ disableUnique,
363
+ fieldPrefix,
364
+ fields: field.fields,
365
+ forceLocalized,
366
+ indexes,
367
+ locales,
368
+ localesColumns,
369
+ localesIndexes,
370
+ newTableName,
371
+ parentTableName,
372
+ relationships,
373
+ relationsToBuild,
374
+ rootRelationsToBuild,
375
+ rootTableIDColType,
376
+ rootTableName,
377
+ uniqueRelationships,
378
+ versions,
379
+ withinLocalizedArrayOrBlock
380
+ });
381
+ if (rowHasLocalizedField) {
382
+ hasLocalizedField = true;
383
+ }
384
+ if (rowHasLocalizedRelationshipField) {
385
+ hasLocalizedRelationshipField = true;
386
+ }
387
+ if (rowHasManyTextField) {
388
+ hasManyTextField = true;
389
+ }
390
+ if (rowHasLocalizedManyTextField) {
391
+ hasLocalizedManyTextField = true;
392
+ }
393
+ if (rowHasManyNumberField) {
394
+ hasManyNumberField = true;
395
+ }
396
+ if (rowHasLocalizedManyNumberField) {
397
+ hasLocalizedManyNumberField = true;
398
+ }
399
+ break;
400
+ }
401
+ case 'date':
402
+ {
403
+ targetTable[fieldName] = withDefault(text(columnName), field);
404
+ break;
405
+ }
484
406
  case 'group':
407
+ case 'tab':
485
408
  {
486
409
  if (!('name' in field)) {
487
410
  const { hasLocalizedField: groupHasLocalizedField, hasLocalizedManyNumberField: groupHasLocalizedManyNumberField, hasLocalizedManyTextField: groupHasLocalizedManyTextField, hasLocalizedRelationshipField: groupHasLocalizedRelationshipField, hasManyNumberField: groupHasManyNumberField, hasManyTextField: groupHasManyTextField } = traverseFields({
@@ -504,6 +427,7 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
504
427
  rootRelationsToBuild,
505
428
  rootTableIDColType,
506
429
  rootTableName,
430
+ uniqueRelationships,
507
431
  versions,
508
432
  withinLocalizedArrayOrBlock
509
433
  });
@@ -548,8 +472,9 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
548
472
  rootRelationsToBuild,
549
473
  rootTableIDColType,
550
474
  rootTableName,
475
+ uniqueRelationships,
551
476
  versions,
552
- withinLocalizedArrayOrBlock
477
+ withinLocalizedArrayOrBlock: withinLocalizedArrayOrBlock || field.localized
553
478
  });
554
479
  if (groupHasLocalizedField) {
555
480
  hasLocalizedField = true;
@@ -571,6 +496,176 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
571
496
  }
572
497
  break;
573
498
  }
499
+ case 'json':
500
+ case 'richText':
501
+ {
502
+ targetTable[fieldName] = withDefault(text(columnName, {
503
+ mode: 'json'
504
+ }), field);
505
+ break;
506
+ }
507
+ case 'number':
508
+ {
509
+ if (field.hasMany) {
510
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
511
+ if (isLocalized) {
512
+ hasLocalizedManyNumberField = true;
513
+ }
514
+ if (field.index) {
515
+ hasManyNumberField = 'index';
516
+ } else if (!hasManyNumberField) {
517
+ hasManyNumberField = true;
518
+ }
519
+ if (field.unique) {
520
+ throw new InvalidConfiguration('Unique is not supported in Postgres for hasMany number fields.');
521
+ }
522
+ } else {
523
+ targetTable[fieldName] = withDefault(numeric(columnName), field);
524
+ }
525
+ break;
526
+ }
527
+ case 'point':
528
+ {
529
+ break;
530
+ }
531
+ case 'radio':
532
+ case 'select':
533
+ {
534
+ const options = field.options.map((option)=>{
535
+ if (optionIsObject(option)) {
536
+ return option.value;
537
+ }
538
+ return option;
539
+ });
540
+ if (field.type === 'select' && field.hasMany) {
541
+ const selectTableName = createTableName({
542
+ adapter,
543
+ config: field,
544
+ parentTableName: newTableName,
545
+ prefix: `${newTableName}_`,
546
+ versionsCustomName: versions
547
+ });
548
+ const baseColumns = {
549
+ order: integer('order').notNull(),
550
+ parent: getIDColumn({
551
+ name: 'parent_id',
552
+ type: parentIDColType,
553
+ notNull: true,
554
+ primaryKey: false
555
+ }),
556
+ value: text('value', {
557
+ enum: options
558
+ })
559
+ };
560
+ const baseExtraConfig = {
561
+ orderIdx: (cols)=>index(`${selectTableName}_order_idx`).on(cols.order),
562
+ parentFk: (cols)=>foreignKey({
563
+ name: `${selectTableName}_parent_fk`,
564
+ columns: [
565
+ cols.parent
566
+ ],
567
+ foreignColumns: [
568
+ adapter.tables[parentTableName].id
569
+ ]
570
+ }).onDelete('cascade'),
571
+ parentIdx: (cols)=>index(`${selectTableName}_parent_idx`).on(cols.parent)
572
+ };
573
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
574
+ if (isLocalized) {
575
+ baseColumns.locale = text('locale', {
576
+ enum: locales
577
+ }).notNull();
578
+ baseExtraConfig.localeIdx = (cols)=>index(`${selectTableName}_locale_idx`).on(cols.locale);
579
+ }
580
+ if (field.index) {
581
+ baseExtraConfig.value = (cols)=>index(`${selectTableName}_value_idx`).on(cols.value);
582
+ }
583
+ buildTable({
584
+ adapter,
585
+ baseColumns,
586
+ baseExtraConfig,
587
+ disableNotNull,
588
+ disableUnique,
589
+ fields: [],
590
+ rootTableName,
591
+ tableName: selectTableName,
592
+ versions
593
+ });
594
+ relationsToBuild.set(fieldName, {
595
+ type: 'many',
596
+ // selects have their own localized table, independent of the base table.
597
+ localized: false,
598
+ target: selectTableName
599
+ });
600
+ adapter.relations[`relations_${selectTableName}`] = relations(adapter.tables[selectTableName], ({ one })=>({
601
+ parent: one(adapter.tables[parentTableName], {
602
+ fields: [
603
+ adapter.tables[selectTableName].parent
604
+ ],
605
+ references: [
606
+ adapter.tables[parentTableName].id
607
+ ],
608
+ relationName: fieldName
609
+ })
610
+ }));
611
+ } else {
612
+ targetTable[fieldName] = withDefault(text(columnName, {
613
+ enum: options
614
+ }), field);
615
+ }
616
+ break;
617
+ }
618
+ case 'relationship':
619
+ case 'upload':
620
+ if (Array.isArray(field.relationTo)) {
621
+ field.relationTo.forEach((relation)=>{
622
+ relationships.add(relation);
623
+ if (field.unique && !disableUnique && !disableRelsTableUnique) {
624
+ uniqueRelationships.add(relation);
625
+ }
626
+ });
627
+ } else if (field.hasMany) {
628
+ relationships.add(field.relationTo);
629
+ if (field.unique && !disableUnique && !disableRelsTableUnique) {
630
+ uniqueRelationships.add(field.relationTo);
631
+ }
632
+ } else {
633
+ // simple relationships get a column on the targetTable with a foreign key to the relationTo table
634
+ const relationshipConfig = adapter.payload.collections[field.relationTo].config;
635
+ const tableName = adapter.tableNameMap.get(toSnakeCase(field.relationTo));
636
+ // get the id type of the related collection
637
+ let colType = 'integer';
638
+ const relatedCollectionCustomID = relationshipConfig.fields.find((field)=>fieldAffectsData(field) && field.name === 'id');
639
+ if (relatedCollectionCustomID?.type === 'number') {
640
+ colType = 'numeric';
641
+ }
642
+ if (relatedCollectionCustomID?.type === 'text') {
643
+ colType = 'text';
644
+ }
645
+ // make the foreign key column for relationship using the correct id column type
646
+ targetTable[fieldName] = getIDColumn({
647
+ name: `${columnName}_id`,
648
+ type: colType,
649
+ primaryKey: false
650
+ }).references(()=>adapter.tables[tableName].id, {
651
+ onDelete: 'set null'
652
+ });
653
+ // add relationship to table
654
+ relationsToBuild.set(fieldName, {
655
+ type: 'one',
656
+ localized: adapter.payload.config.localization && (field.localized || forceLocalized),
657
+ target: tableName
658
+ });
659
+ // add notNull when not required
660
+ if (!disableNotNull && field.required && !field.admin?.condition) {
661
+ targetTable[fieldName].notNull();
662
+ }
663
+ break;
664
+ }
665
+ if (Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock) {
666
+ hasLocalizedRelationshipField = true;
667
+ }
668
+ break;
574
669
  case 'tabs':
575
670
  {
576
671
  const disableNotNullFromHere = Boolean(field.admin?.condition) || disableNotNull;
@@ -597,6 +692,7 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
597
692
  rootRelationsToBuild,
598
693
  rootTableIDColType,
599
694
  rootTableName,
695
+ uniqueRelationships,
600
696
  versions,
601
697
  withinLocalizedArrayOrBlock
602
698
  });
@@ -620,96 +716,26 @@ export const traverseFields = ({ adapter, columnPrefix, columns, disableNotNull,
620
716
  }
621
717
  break;
622
718
  }
623
- case 'row':
624
- case 'collapsible':
719
+ case 'text':
625
720
  {
626
- const disableNotNullFromHere = Boolean(field.admin?.condition) || disableNotNull;
627
- const { hasLocalizedField: rowHasLocalizedField, hasLocalizedManyNumberField: rowHasLocalizedManyNumberField, hasLocalizedManyTextField: rowHasLocalizedManyTextField, hasLocalizedRelationshipField: rowHasLocalizedRelationshipField, hasManyNumberField: rowHasManyNumberField, hasManyTextField: rowHasManyTextField } = traverseFields({
628
- adapter,
629
- columnPrefix,
630
- columns,
631
- disableNotNull: disableNotNullFromHere,
632
- disableUnique,
633
- fieldPrefix,
634
- fields: field.fields,
635
- forceLocalized,
636
- indexes,
637
- locales,
638
- localesColumns,
639
- localesIndexes,
640
- newTableName,
641
- parentTableName,
642
- relationships,
643
- relationsToBuild,
644
- rootRelationsToBuild,
645
- rootTableIDColType,
646
- rootTableName,
647
- versions,
648
- withinLocalizedArrayOrBlock
649
- });
650
- if (rowHasLocalizedField) {
651
- hasLocalizedField = true;
652
- }
653
- if (rowHasLocalizedRelationshipField) {
654
- hasLocalizedRelationshipField = true;
655
- }
656
- if (rowHasManyTextField) {
657
- hasManyTextField = true;
658
- }
659
- if (rowHasLocalizedManyTextField) {
660
- hasLocalizedManyTextField = true;
661
- }
662
- if (rowHasManyNumberField) {
663
- hasManyNumberField = true;
664
- }
665
- if (rowHasLocalizedManyNumberField) {
666
- hasLocalizedManyNumberField = true;
667
- }
668
- break;
669
- }
670
- case 'relationship':
671
- case 'upload':
672
- if (Array.isArray(field.relationTo)) {
673
- field.relationTo.forEach((relation)=>relationships.add(relation));
674
- } else if (field.hasMany) {
675
- relationships.add(field.relationTo);
676
- } else {
677
- // simple relationships get a column on the targetTable with a foreign key to the relationTo table
678
- const relationshipConfig = adapter.payload.collections[field.relationTo].config;
679
- const tableName = adapter.tableNameMap.get(toSnakeCase(field.relationTo));
680
- // get the id type of the related collection
681
- let colType = 'integer';
682
- const relatedCollectionCustomID = relationshipConfig.fields.find((field)=>fieldAffectsData(field) && field.name === 'id');
683
- if (relatedCollectionCustomID?.type === 'number') {
684
- colType = 'numeric';
685
- }
686
- if (relatedCollectionCustomID?.type === 'text') {
687
- colType = 'text';
688
- }
689
- // make the foreign key column for relationship using the correct id column type
690
- targetTable[fieldName] = getIDColumn({
691
- name: `${columnName}_id`,
692
- type: colType,
693
- primaryKey: false
694
- }).references(()=>adapter.tables[tableName].id, {
695
- onDelete: 'set null'
696
- });
697
- // add relationship to table
698
- relationsToBuild.set(fieldName, {
699
- type: 'one',
700
- localized: adapter.payload.config.localization && field.localized,
701
- target: tableName
702
- });
703
- // add notNull when not required
704
- if (!disableNotNull && field.required && !field.admin?.condition) {
705
- targetTable[fieldName].notNull();
721
+ if (field.hasMany) {
722
+ const isLocalized = Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock || forceLocalized;
723
+ if (isLocalized) {
724
+ hasLocalizedManyTextField = true;
725
+ }
726
+ if (field.index) {
727
+ hasManyTextField = 'index';
728
+ } else if (!hasManyTextField) {
729
+ hasManyTextField = true;
730
+ }
731
+ if (field.unique) {
732
+ throw new InvalidConfiguration('Unique is not supported in SQLite for hasMany text fields.');
733
+ }
734
+ } else {
735
+ targetTable[fieldName] = withDefault(text(columnName), field);
706
736
  }
707
737
  break;
708
738
  }
709
- if (Boolean(field.localized && adapter.payload.config.localization) || withinLocalizedArrayOrBlock) {
710
- hasLocalizedRelationshipField = true;
711
- }
712
- break;
713
739
  default:
714
740
  break;
715
741
  }