@payloadcms/drizzle 4.0.0-canary.1 → 4.0.0-canary.3

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 (41) hide show
  1. package/dist/exports/postgres.d.ts +1 -0
  2. package/dist/exports/postgres.d.ts.map +1 -1
  3. package/dist/exports/postgres.js +1 -0
  4. package/dist/exports/postgres.js.map +1 -1
  5. package/dist/exports/sqlite.d.ts +1 -0
  6. package/dist/exports/sqlite.d.ts.map +1 -1
  7. package/dist/exports/sqlite.js +1 -0
  8. package/dist/exports/sqlite.js.map +1 -1
  9. package/dist/postgres/predefinedMigrations/localize-status/index.d.ts +11 -0
  10. package/dist/postgres/predefinedMigrations/localize-status/index.d.ts.map +1 -0
  11. package/dist/postgres/predefinedMigrations/localize-status/index.js +296 -0
  12. package/dist/postgres/predefinedMigrations/localize-status/index.js.map +1 -0
  13. package/dist/postgres/predefinedMigrations/localize-status/migrateMainCollection.d.ts +13 -0
  14. package/dist/postgres/predefinedMigrations/localize-status/migrateMainCollection.d.ts.map +1 -0
  15. package/dist/postgres/predefinedMigrations/localize-status/migrateMainCollection.js +51 -0
  16. package/dist/postgres/predefinedMigrations/localize-status/migrateMainCollection.js.map +1 -0
  17. package/dist/postgres/predefinedMigrations/localize-status/migrateMainGlobal.d.ts +13 -0
  18. package/dist/postgres/predefinedMigrations/localize-status/migrateMainGlobal.d.ts.map +1 -0
  19. package/dist/postgres/predefinedMigrations/localize-status/migrateMainGlobal.js +54 -0
  20. package/dist/postgres/predefinedMigrations/localize-status/migrateMainGlobal.js.map +1 -0
  21. package/dist/sqlite/predefinedMigrations/localize-status/index.d.ts +28 -0
  22. package/dist/sqlite/predefinedMigrations/localize-status/index.d.ts.map +1 -0
  23. package/dist/sqlite/predefinedMigrations/localize-status/index.js +198 -0
  24. package/dist/sqlite/predefinedMigrations/localize-status/index.js.map +1 -0
  25. package/dist/sqlite/predefinedMigrations/localize-status/migrateMainCollection.d.ts +12 -0
  26. package/dist/sqlite/predefinedMigrations/localize-status/migrateMainCollection.d.ts.map +1 -0
  27. package/dist/sqlite/predefinedMigrations/localize-status/migrateMainCollection.js +24 -0
  28. package/dist/sqlite/predefinedMigrations/localize-status/migrateMainCollection.js.map +1 -0
  29. package/dist/sqlite/predefinedMigrations/localize-status/migrateMainGlobal.d.ts +12 -0
  30. package/dist/sqlite/predefinedMigrations/localize-status/migrateMainGlobal.d.ts.map +1 -0
  31. package/dist/sqlite/predefinedMigrations/localize-status/migrateMainGlobal.js +28 -0
  32. package/dist/sqlite/predefinedMigrations/localize-status/migrateMainGlobal.js.map +1 -0
  33. package/dist/upsertRow/handleUpsertError.d.ts.map +1 -1
  34. package/dist/upsertRow/handleUpsertError.js +2 -1
  35. package/dist/upsertRow/handleUpsertError.js.map +1 -1
  36. package/dist/upsertRow/handleUpsertError.spec.js +42 -0
  37. package/dist/upsertRow/handleUpsertError.spec.js.map +1 -0
  38. package/dist/upsertRow/index.d.ts.map +1 -1
  39. package/dist/upsertRow/index.js +5 -2
  40. package/dist/upsertRow/index.js.map +1 -1
  41. package/package.json +3 -3
@@ -0,0 +1,198 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import { calculateVersionLocaleStatuses } from 'payload/migrations';
3
+ import toSnakeCase from 'to-snake-case';
4
+ import { migrateMainCollectionStatus } from './migrateMainCollection.js';
5
+ import { migrateMainGlobalStatus } from './migrateMainGlobal.js';
6
+ export async function migrateSqliteLocalizeStatus(args) {
7
+ const { collectionSlug, db, globalSlug, payload, req } = args;
8
+ if (!collectionSlug && !globalSlug) {
9
+ throw new Error('Either collectionSlug or globalSlug must be provided');
10
+ }
11
+ if (collectionSlug && globalSlug) {
12
+ throw new Error('Cannot provide both collectionSlug and globalSlug');
13
+ }
14
+ const entitySlug = collectionSlug || globalSlug;
15
+ const versionsTable = collectionSlug ? `_${toSnakeCase(collectionSlug)}_v` : `_${toSnakeCase(globalSlug)}_v`;
16
+ const localesTable = `${versionsTable}_locales`;
17
+ if (!payload.config.localization) {
18
+ throw new Error('Localization is not enabled in payload config');
19
+ }
20
+ // Check if versions are enabled on this collection/global
21
+ let entityConfig;
22
+ if (collectionSlug) {
23
+ entityConfig = payload.config.collections.find((c)=>c.slug === collectionSlug);
24
+ } else if (globalSlug) {
25
+ entityConfig = payload.config.globals.find((g)=>g.slug === globalSlug);
26
+ }
27
+ if (!entityConfig) {
28
+ throw new Error(`${collectionSlug ? 'Collection' : 'Global'} not found: ${collectionSlug || globalSlug}`);
29
+ }
30
+ payload.logger.info({
31
+ msg: `Starting _status localization migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug}`
32
+ });
33
+ // Get filtered locales if filterAvailableLocales is defined
34
+ let locales = payload.config.localization.localeCodes;
35
+ if (typeof payload.config.localization.filterAvailableLocales === 'function') {
36
+ const filteredLocaleObjects = await payload.config.localization.filterAvailableLocales({
37
+ locales: payload.config.localization.locales,
38
+ req
39
+ });
40
+ locales = filteredLocaleObjects.map((locale)=>typeof locale === 'string' ? locale : locale.code);
41
+ }
42
+ payload.logger.info({
43
+ msg: `Locales: ${locales.join(', ')}`
44
+ });
45
+ // Check if versions are enabled in config (skip if not)
46
+ if (!entityConfig.versions) {
47
+ payload.logger.info({
48
+ msg: `Skipping migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug} - versions not enabled`
49
+ });
50
+ return;
51
+ }
52
+ // Validate that version__status column exists before proceeding
53
+ if (!await columnExists({
54
+ columnName: 'version__status',
55
+ db,
56
+ tableName: versionsTable
57
+ })) {
58
+ throw new Error(`Migration aborted: version__status column not found in ${versionsTable} table. ` + `This migration should only run on schemas that have NOT yet been migrated to per-locale status. ` + `If you've already run this migration, no action is needed.`);
59
+ }
60
+ const localesTableExists = await tableExists({
61
+ db,
62
+ tableName: localesTable
63
+ });
64
+ if (!localesTableExists) {
65
+ // SCENARIO 1: Create the locales table (first localized field in versions)
66
+ payload.logger.info({
67
+ msg: `Creating new locales table: ${localesTable}`
68
+ });
69
+ await db.run(sql.raw(`CREATE TABLE "${localesTable}" (
70
+ id INTEGER PRIMARY KEY,
71
+ _locale TEXT NOT NULL,
72
+ _parent_id INTEGER NOT NULL,
73
+ version__status TEXT,
74
+ UNIQUE(_locale, _parent_id),
75
+ FOREIGN KEY (_parent_id) REFERENCES "${versionsTable}"(id) ON DELETE CASCADE
76
+ )`));
77
+ for (const locale of locales){
78
+ const inserted = await db.all(sql.raw(`INSERT INTO "${localesTable}" (_locale, _parent_id, version__status) SELECT '${locale}', id, version__status FROM "${versionsTable}" RETURNING id`));
79
+ payload.logger.info({
80
+ msg: `Inserted ${inserted.length} rows for locale: ${locale}`
81
+ });
82
+ }
83
+ } else {
84
+ // SCENARIO 2: Add version__status column to existing locales table
85
+ payload.logger.info({
86
+ msg: `Adding version__status column to existing table: ${localesTable}`
87
+ });
88
+ await db.run(sql.raw(`ALTER TABLE "${localesTable}" ADD COLUMN version__status TEXT`));
89
+ payload.logger.info({
90
+ msg: 'Processing version history to determine status per locale...'
91
+ });
92
+ const existingLocaleRows = await db.all(sql.raw(`SELECT DISTINCT _locale FROM "${localesTable}" ORDER BY _locale`));
93
+ const existingLocales = existingLocaleRows.map((row)=>row._locale);
94
+ payload.logger.info({
95
+ msg: `Found existing locales in table: ${existingLocales.join(', ')}`
96
+ });
97
+ // Check if the snapshot column exists (only present on DBs that used publishSpecificLocale)
98
+ const hasSnapshotColumn = await columnExists({
99
+ columnName: 'snapshot',
100
+ db,
101
+ tableName: versionsTable
102
+ });
103
+ const versionRows = await db.all(sql.raw(hasSnapshotColumn ? `SELECT id, parent_id as parent, version__status as _status, published_locale, snapshot, created_at FROM "${versionsTable}" ORDER BY parent_id, created_at ASC` : `SELECT id, parent_id as parent, version__status as _status, published_locale, created_at FROM "${versionsTable}" ORDER BY parent_id, created_at ASC`));
104
+ const versionLocaleStatus = calculateVersionLocaleStatuses(versionRows, existingLocales, payload);
105
+ payload.logger.info({
106
+ msg: 'Updating locales table with calculated statuses...'
107
+ });
108
+ let updateCount = 0;
109
+ for (const [versionId, localeMap] of versionLocaleStatus.entries()){
110
+ for (const [locale, status] of localeMap.entries()){
111
+ await db.run(sql.raw(`UPDATE "${localesTable}" SET version__status = '${status}' WHERE _parent_id = ${versionId} AND _locale = '${locale}'`));
112
+ updateCount++;
113
+ }
114
+ }
115
+ payload.logger.info({
116
+ msg: `Updated ${updateCount} locale rows with status`
117
+ });
118
+ }
119
+ // Drop the old version__status column from the versions table
120
+ await dropColumn({
121
+ columnName: 'version__status',
122
+ db,
123
+ tableName: versionsTable
124
+ });
125
+ // Migrate main table _status to locales table
126
+ const mainTable = collectionSlug ? toSnakeCase(collectionSlug) : toSnakeCase(globalSlug);
127
+ const mainLocalesTable = `${mainTable}_locales`;
128
+ if (await tableExists({
129
+ db,
130
+ tableName: mainLocalesTable
131
+ })) {
132
+ if (!await columnExists({
133
+ columnName: '_status',
134
+ db,
135
+ tableName: mainLocalesTable
136
+ })) {
137
+ await db.run(sql.raw(`ALTER TABLE "${mainLocalesTable}" ADD COLUMN _status TEXT DEFAULT 'draft'`));
138
+ }
139
+ if (collectionSlug) {
140
+ await migrateMainCollectionStatus({
141
+ collectionSlug,
142
+ db,
143
+ locales,
144
+ payload,
145
+ versionsTable
146
+ });
147
+ } else if (globalSlug) {
148
+ await migrateMainGlobalStatus({
149
+ db,
150
+ globalSlug,
151
+ locales,
152
+ payload,
153
+ versionsTable
154
+ });
155
+ }
156
+ } else {
157
+ payload.logger.info({
158
+ msg: `No locales table found: ${mainLocalesTable} (collection/global not localized)`
159
+ });
160
+ }
161
+ // Drop _status from main table if it exists (it will be in locales table now)
162
+ if (await columnExists({
163
+ columnName: '_status',
164
+ db,
165
+ tableName: mainTable
166
+ })) {
167
+ await dropColumn({
168
+ columnName: '_status',
169
+ db,
170
+ tableName: mainTable
171
+ });
172
+ }
173
+ payload.logger.info({
174
+ msg: 'Migration completed successfully'
175
+ });
176
+ }
177
+ /**
178
+ * Drops a column, first removing any indexes that reference it. SQLite refuses to
179
+ * drop a column that is still referenced by an index.
180
+ */ export async function dropColumn({ columnName, db, tableName }) {
181
+ const indexes = await db.all(sql.raw(`SELECT name, sql FROM sqlite_master WHERE type='index' AND tbl_name='${tableName}'`));
182
+ for (const index of indexes){
183
+ if (typeof index.sql === 'string' && index.sql.includes(columnName)) {
184
+ await db.run(sql.raw(`DROP INDEX IF EXISTS "${index.name}"`));
185
+ }
186
+ }
187
+ await db.run(sql.raw(`ALTER TABLE "${tableName}" DROP COLUMN ${columnName}`));
188
+ }
189
+ export async function columnExists({ columnName, db, tableName }) {
190
+ const result = await db.all(sql.raw(`SELECT COUNT(*) as count FROM pragma_table_info('${tableName}') WHERE name = '${columnName}'`));
191
+ return Number(result[0]?.count ?? 0) > 0;
192
+ }
193
+ export async function tableExists({ db, tableName }) {
194
+ const result = await db.all(sql.raw(`SELECT COUNT(*) as count FROM sqlite_master WHERE type='table' AND name='${tableName}'`));
195
+ return Number(result[0]?.count ?? 0) > 0;
196
+ }
197
+
198
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/sqlite/predefinedMigrations/localize-status/index.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\nimport { sql } from 'drizzle-orm'\nimport { calculateVersionLocaleStatuses } from 'payload/migrations'\nimport toSnakeCase from 'to-snake-case'\n\nimport { migrateMainCollectionStatus } from './migrateMainCollection.js'\nimport { migrateMainGlobalStatus } from './migrateMainGlobal.js'\n\nexport type LocalizeStatusArgs = {\n collectionSlug?: string\n db: any\n globalSlug?: string\n payload: Payload\n req?: any\n}\n\nexport async function migrateSqliteLocalizeStatus(args: LocalizeStatusArgs): Promise<void> {\n const { collectionSlug, db, globalSlug, payload, req } = args\n\n if (!collectionSlug && !globalSlug) {\n throw new Error('Either collectionSlug or globalSlug must be provided')\n }\n\n if (collectionSlug && globalSlug) {\n throw new Error('Cannot provide both collectionSlug and globalSlug')\n }\n\n const entitySlug = collectionSlug || globalSlug\n const versionsTable = collectionSlug\n ? `_${toSnakeCase(collectionSlug)}_v`\n : `_${toSnakeCase(globalSlug)}_v`\n const localesTable = `${versionsTable}_locales`\n\n if (!payload.config.localization) {\n throw new Error('Localization is not enabled in payload config')\n }\n\n // Check if versions are enabled on this collection/global\n let entityConfig\n if (collectionSlug) {\n entityConfig = payload.config.collections.find((c) => c.slug === collectionSlug)\n } else if (globalSlug) {\n entityConfig = payload.config.globals.find((g) => g.slug === globalSlug)\n }\n\n if (!entityConfig) {\n throw new Error(\n `${collectionSlug ? 'Collection' : 'Global'} not found: ${collectionSlug || globalSlug}`,\n )\n }\n\n payload.logger.info({\n msg: `Starting _status localization migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug}`,\n })\n\n // Get filtered locales if filterAvailableLocales is defined\n let locales = payload.config.localization.localeCodes\n if (typeof payload.config.localization.filterAvailableLocales === 'function') {\n const filteredLocaleObjects = await payload.config.localization.filterAvailableLocales({\n locales: payload.config.localization.locales,\n req,\n })\n locales = filteredLocaleObjects.map((locale) =>\n typeof locale === 'string' ? locale : locale.code,\n )\n }\n payload.logger.info({ msg: `Locales: ${locales.join(', ')}` })\n\n // Check if versions are enabled in config (skip if not)\n if (!entityConfig.versions) {\n payload.logger.info({\n msg: `Skipping migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug} - versions not enabled`,\n })\n return\n }\n\n // Validate that version__status column exists before proceeding\n if (!(await columnExists({ columnName: 'version__status', db, tableName: versionsTable }))) {\n throw new Error(\n `Migration aborted: version__status column not found in ${versionsTable} table. ` +\n `This migration should only run on schemas that have NOT yet been migrated to per-locale status. ` +\n `If you've already run this migration, no action is needed.`,\n )\n }\n\n const localesTableExists = await tableExists({ db, tableName: localesTable })\n\n if (!localesTableExists) {\n // SCENARIO 1: Create the locales table (first localized field in versions)\n payload.logger.info({ msg: `Creating new locales table: ${localesTable}` })\n\n await db.run(\n sql.raw(`CREATE TABLE \"${localesTable}\" (\n id INTEGER PRIMARY KEY,\n _locale TEXT NOT NULL,\n _parent_id INTEGER NOT NULL,\n version__status TEXT,\n UNIQUE(_locale, _parent_id),\n FOREIGN KEY (_parent_id) REFERENCES \"${versionsTable}\"(id) ON DELETE CASCADE\n )`),\n )\n\n for (const locale of locales) {\n const inserted: any[] = await db.all(\n sql.raw(\n `INSERT INTO \"${localesTable}\" (_locale, _parent_id, version__status) SELECT '${locale}', id, version__status FROM \"${versionsTable}\" RETURNING id`,\n ),\n )\n payload.logger.info({\n msg: `Inserted ${inserted.length} rows for locale: ${locale}`,\n })\n }\n } else {\n // SCENARIO 2: Add version__status column to existing locales table\n payload.logger.info({ msg: `Adding version__status column to existing table: ${localesTable}` })\n\n await db.run(sql.raw(`ALTER TABLE \"${localesTable}\" ADD COLUMN version__status TEXT`))\n\n payload.logger.info({ msg: 'Processing version history to determine status per locale...' })\n\n const existingLocaleRows: any[] = await db.all(\n sql.raw(`SELECT DISTINCT _locale FROM \"${localesTable}\" ORDER BY _locale`),\n )\n const existingLocales = existingLocaleRows.map((row: any) => row._locale as string)\n payload.logger.info({\n msg: `Found existing locales in table: ${existingLocales.join(', ')}`,\n })\n\n // Check if the snapshot column exists (only present on DBs that used publishSpecificLocale)\n const hasSnapshotColumn = await columnExists({\n columnName: 'snapshot',\n db,\n tableName: versionsTable,\n })\n\n const versionRows: any[] = await db.all(\n sql.raw(\n hasSnapshotColumn\n ? `SELECT id, parent_id as parent, version__status as _status, published_locale, snapshot, created_at FROM \"${versionsTable}\" ORDER BY parent_id, created_at ASC`\n : `SELECT id, parent_id as parent, version__status as _status, published_locale, created_at FROM \"${versionsTable}\" ORDER BY parent_id, created_at ASC`,\n ),\n )\n\n const versionLocaleStatus = calculateVersionLocaleStatuses(\n versionRows,\n existingLocales,\n payload,\n )\n\n payload.logger.info({ msg: 'Updating locales table with calculated statuses...' })\n\n let updateCount = 0\n for (const [versionId, localeMap] of versionLocaleStatus.entries()) {\n for (const [locale, status] of localeMap.entries()) {\n await db.run(\n sql.raw(\n `UPDATE \"${localesTable}\" SET version__status = '${status}' WHERE _parent_id = ${versionId} AND _locale = '${locale}'`,\n ),\n )\n updateCount++\n }\n }\n\n payload.logger.info({ msg: `Updated ${updateCount} locale rows with status` })\n }\n\n // Drop the old version__status column from the versions table\n await dropColumn({ columnName: 'version__status', db, tableName: versionsTable })\n\n // Migrate main table _status to locales table\n const mainTable = collectionSlug ? toSnakeCase(collectionSlug) : toSnakeCase(globalSlug)\n const mainLocalesTable = `${mainTable}_locales`\n\n if (await tableExists({ db, tableName: mainLocalesTable })) {\n if (!(await columnExists({ columnName: '_status', db, tableName: mainLocalesTable }))) {\n await db.run(\n sql.raw(`ALTER TABLE \"${mainLocalesTable}\" ADD COLUMN _status TEXT DEFAULT 'draft'`),\n )\n }\n\n if (collectionSlug) {\n await migrateMainCollectionStatus({\n collectionSlug,\n db,\n locales,\n payload,\n versionsTable,\n })\n } else if (globalSlug) {\n await migrateMainGlobalStatus({ db, globalSlug, locales, payload, versionsTable })\n }\n } else {\n payload.logger.info({\n msg: `No locales table found: ${mainLocalesTable} (collection/global not localized)`,\n })\n }\n\n // Drop _status from main table if it exists (it will be in locales table now)\n if (await columnExists({ columnName: '_status', db, tableName: mainTable })) {\n await dropColumn({ columnName: '_status', db, tableName: mainTable })\n }\n\n payload.logger.info({ msg: 'Migration completed successfully' })\n}\n\n/**\n * Drops a column, first removing any indexes that reference it. SQLite refuses to\n * drop a column that is still referenced by an index.\n */\nexport async function dropColumn({\n columnName,\n db,\n tableName,\n}: {\n columnName: string\n db: any\n tableName: string\n}): Promise<void> {\n const indexes = await db.all(\n sql.raw(`SELECT name, sql FROM sqlite_master WHERE type='index' AND tbl_name='${tableName}'`),\n )\n\n for (const index of indexes as Array<{ name: string; sql: null | string }>) {\n if (typeof index.sql === 'string' && index.sql.includes(columnName)) {\n await db.run(sql.raw(`DROP INDEX IF EXISTS \"${index.name}\"`))\n }\n }\n\n await db.run(sql.raw(`ALTER TABLE \"${tableName}\" DROP COLUMN ${columnName}`))\n}\n\nexport async function columnExists({\n columnName,\n db,\n tableName,\n}: {\n columnName: string\n db: any\n tableName: string\n}): Promise<boolean> {\n const result = await db.all(\n sql.raw(\n `SELECT COUNT(*) as count FROM pragma_table_info('${tableName}') WHERE name = '${columnName}'`,\n ),\n )\n return Number(result[0]?.count ?? 0) > 0\n}\n\nexport async function tableExists({\n db,\n tableName,\n}: {\n db: any\n tableName: string\n}): Promise<boolean> {\n const result = await db.all(\n sql.raw(\n `SELECT COUNT(*) as count FROM sqlite_master WHERE type='table' AND name='${tableName}'`,\n ),\n )\n return Number(result[0]?.count ?? 0) > 0\n}\n"],"names":["sql","calculateVersionLocaleStatuses","toSnakeCase","migrateMainCollectionStatus","migrateMainGlobalStatus","migrateSqliteLocalizeStatus","args","collectionSlug","db","globalSlug","payload","req","Error","entitySlug","versionsTable","localesTable","config","localization","entityConfig","collections","find","c","slug","globals","g","logger","info","msg","locales","localeCodes","filterAvailableLocales","filteredLocaleObjects","map","locale","code","join","versions","columnExists","columnName","tableName","localesTableExists","tableExists","run","raw","inserted","all","length","existingLocaleRows","existingLocales","row","_locale","hasSnapshotColumn","versionRows","versionLocaleStatus","updateCount","versionId","localeMap","entries","status","dropColumn","mainTable","mainLocalesTable","indexes","index","includes","name","result","Number","count"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Payload } from 'payload';
2
+ /**
3
+ * Migrates main collection documents from _status to per-locale status object
4
+ */
5
+ export declare function migrateMainCollectionStatus({ collectionSlug, db, locales, payload, versionsTable, }: {
6
+ collectionSlug: string;
7
+ db: any;
8
+ locales: string[];
9
+ payload: Payload;
10
+ versionsTable: string;
11
+ }): Promise<void>;
12
+ //# sourceMappingURL=migrateMainCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrateMainCollection.d.ts","sourceRoot":"","sources":["../../../../src/sqlite/predefinedMigrations/localize-status/migrateMainCollection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAKtC;;GAEG;AACH,wBAAsB,2BAA2B,CAAC,EAChD,cAAc,EACd,EAAE,EACF,OAAO,EACP,OAAO,EACP,aAAa,GACd,EAAE;IACD,cAAc,EAAE,MAAM,CAAA;IACtB,EAAE,EAAE,GAAG,CAAA;IACP,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BhB"}
@@ -0,0 +1,24 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import toSnakeCase from 'to-snake-case';
3
+ /**
4
+ * Migrates main collection documents from _status to per-locale status object
5
+ */ export async function migrateMainCollectionStatus({ collectionSlug, db, locales, payload, versionsTable }) {
6
+ const mainTable = toSnakeCase(collectionSlug);
7
+ const mainLocalesTable = `${mainTable}_locales`;
8
+ payload.logger.info({
9
+ msg: `Migrating main collection locales for: ${mainLocalesTable}`
10
+ });
11
+ const documents = await db.all(sql.raw(`SELECT DISTINCT id FROM "${mainTable}"`));
12
+ for (const doc of documents){
13
+ for (const locale of locales){
14
+ const latestVersionRows = await db.all(sql.raw(`SELECT l.version__status as _status FROM "${versionsTable}" v JOIN "${versionsTable}_locales" l ON l._parent_id = v.id WHERE v.parent_id = ${doc.id} AND l._locale = '${locale}' ORDER BY v.created_at DESC LIMIT 1`));
15
+ const status = latestVersionRows[0]?._status || 'draft';
16
+ await db.run(sql.raw(`UPDATE "${mainLocalesTable}" SET _status = '${status}' WHERE _parent_id = ${doc.id} AND _locale = '${locale}'`));
17
+ }
18
+ }
19
+ payload.logger.info({
20
+ msg: `Migrated ${documents.length} collection documents`
21
+ });
22
+ }
23
+
24
+ //# sourceMappingURL=migrateMainCollection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/sqlite/predefinedMigrations/localize-status/migrateMainCollection.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\nimport { sql } from 'drizzle-orm'\nimport toSnakeCase from 'to-snake-case'\n\n/**\n * Migrates main collection documents from _status to per-locale status object\n */\nexport async function migrateMainCollectionStatus({\n collectionSlug,\n db,\n locales,\n payload,\n versionsTable,\n}: {\n collectionSlug: string\n db: any\n locales: string[]\n payload: Payload\n versionsTable: string\n}): Promise<void> {\n const mainTable = toSnakeCase(collectionSlug)\n const mainLocalesTable = `${mainTable}_locales`\n\n payload.logger.info({ msg: `Migrating main collection locales for: ${mainLocalesTable}` })\n\n const documents: any[] = await db.all(sql.raw(`SELECT DISTINCT id FROM \"${mainTable}\"`))\n\n for (const doc of documents) {\n for (const locale of locales) {\n const latestVersionRows: any[] = await db.all(\n sql.raw(\n `SELECT l.version__status as _status FROM \"${versionsTable}\" v JOIN \"${versionsTable}_locales\" l ON l._parent_id = v.id WHERE v.parent_id = ${doc.id} AND l._locale = '${locale}' ORDER BY v.created_at DESC LIMIT 1`,\n ),\n )\n\n const status = latestVersionRows[0]?._status || 'draft'\n\n await db.run(\n sql.raw(\n `UPDATE \"${mainLocalesTable}\" SET _status = '${status}' WHERE _parent_id = ${doc.id} AND _locale = '${locale}'`,\n ),\n )\n }\n }\n\n payload.logger.info({ msg: `Migrated ${documents.length} collection documents` })\n}\n"],"names":["sql","toSnakeCase","migrateMainCollectionStatus","collectionSlug","db","locales","payload","versionsTable","mainTable","mainLocalesTable","logger","info","msg","documents","all","raw","doc","locale","latestVersionRows","id","status","_status","run","length"],"mappings":"AAEA,SAASA,GAAG,QAAQ,cAAa;AACjC,OAAOC,iBAAiB,gBAAe;AAEvC;;CAEC,GACD,OAAO,eAAeC,4BAA4B,EAChDC,cAAc,EACdC,EAAE,EACFC,OAAO,EACPC,OAAO,EACPC,aAAa,EAOd;IACC,MAAMC,YAAYP,YAAYE;IAC9B,MAAMM,mBAAmB,GAAGD,UAAU,QAAQ,CAAC;IAE/CF,QAAQI,MAAM,CAACC,IAAI,CAAC;QAAEC,KAAK,CAAC,uCAAuC,EAAEH,kBAAkB;IAAC;IAExF,MAAMI,YAAmB,MAAMT,GAAGU,GAAG,CAACd,IAAIe,GAAG,CAAC,CAAC,yBAAyB,EAAEP,UAAU,CAAC,CAAC;IAEtF,KAAK,MAAMQ,OAAOH,UAAW;QAC3B,KAAK,MAAMI,UAAUZ,QAAS;YAC5B,MAAMa,oBAA2B,MAAMd,GAAGU,GAAG,CAC3Cd,IAAIe,GAAG,CACL,CAAC,0CAA0C,EAAER,cAAc,UAAU,EAAEA,cAAc,uDAAuD,EAAES,IAAIG,EAAE,CAAC,kBAAkB,EAAEF,OAAO,oCAAoC,CAAC;YAIzN,MAAMG,SAASF,iBAAiB,CAAC,EAAE,EAAEG,WAAW;YAEhD,MAAMjB,GAAGkB,GAAG,CACVtB,IAAIe,GAAG,CACL,CAAC,QAAQ,EAAEN,iBAAiB,iBAAiB,EAAEW,OAAO,qBAAqB,EAAEJ,IAAIG,EAAE,CAAC,gBAAgB,EAAEF,OAAO,CAAC,CAAC;QAGrH;IACF;IAEAX,QAAQI,MAAM,CAACC,IAAI,CAAC;QAAEC,KAAK,CAAC,SAAS,EAAEC,UAAUU,MAAM,CAAC,qBAAqB,CAAC;IAAC;AACjF"}
@@ -0,0 +1,12 @@
1
+ import type { Payload } from 'payload';
2
+ /**
3
+ * Migrates main global document from _status to per-locale status object
4
+ */
5
+ export declare function migrateMainGlobalStatus({ db, globalSlug, locales, payload, versionsTable, }: {
6
+ db: any;
7
+ globalSlug: string;
8
+ locales: string[];
9
+ payload: Payload;
10
+ versionsTable: string;
11
+ }): Promise<void>;
12
+ //# sourceMappingURL=migrateMainGlobal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrateMainGlobal.d.ts","sourceRoot":"","sources":["../../../../src/sqlite/predefinedMigrations/localize-status/migrateMainGlobal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAKtC;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,EAC5C,EAAE,EACF,UAAU,EACV,OAAO,EACP,OAAO,EACP,aAAa,GACd,EAAE;IACD,EAAE,EAAE,GAAG,CAAA;IACP,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BhB"}
@@ -0,0 +1,28 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import toSnakeCase from 'to-snake-case';
3
+ /**
4
+ * Migrates main global document from _status to per-locale status object
5
+ */ export async function migrateMainGlobalStatus({ db, globalSlug, locales, payload, versionsTable }) {
6
+ const globalTable = toSnakeCase(globalSlug);
7
+ const globalLocalesTable = `${globalTable}_locales`;
8
+ payload.logger.info({
9
+ msg: `Migrating main global locales for: ${globalLocalesTable}`
10
+ });
11
+ const globalDoc = await db.get(sql.raw(`SELECT id FROM "${globalTable}" LIMIT 1`));
12
+ if (!globalDoc) {
13
+ payload.logger.warn({
14
+ msg: `No global document found for ${globalSlug}, skipping`
15
+ });
16
+ return;
17
+ }
18
+ for (const locale of locales){
19
+ const latestVersionRows = await db.all(sql.raw(`SELECT l.version__status as _status FROM "${versionsTable}" v JOIN "${versionsTable}_locales" l ON l._parent_id = v.id WHERE l._locale = '${locale}' ORDER BY v.created_at DESC LIMIT 1`));
20
+ const status = latestVersionRows[0]?._status || 'draft';
21
+ await db.run(sql.raw(`UPDATE "${globalLocalesTable}" SET _status = '${status}' WHERE _parent_id = ${globalDoc.id} AND _locale = '${locale}'`));
22
+ }
23
+ payload.logger.info({
24
+ msg: 'Migrated global document'
25
+ });
26
+ }
27
+
28
+ //# sourceMappingURL=migrateMainGlobal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/sqlite/predefinedMigrations/localize-status/migrateMainGlobal.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\nimport { sql } from 'drizzle-orm'\nimport toSnakeCase from 'to-snake-case'\n\n/**\n * Migrates main global document from _status to per-locale status object\n */\nexport async function migrateMainGlobalStatus({\n db,\n globalSlug,\n locales,\n payload,\n versionsTable,\n}: {\n db: any\n globalSlug: string\n locales: string[]\n payload: Payload\n versionsTable: string\n}): Promise<void> {\n const globalTable = toSnakeCase(globalSlug)\n const globalLocalesTable = `${globalTable}_locales`\n\n payload.logger.info({ msg: `Migrating main global locales for: ${globalLocalesTable}` })\n\n const globalDoc: any = await db.get(sql.raw(`SELECT id FROM \"${globalTable}\" LIMIT 1`))\n\n if (!globalDoc) {\n payload.logger.warn({ msg: `No global document found for ${globalSlug}, skipping` })\n return\n }\n\n for (const locale of locales) {\n const latestVersionRows: any[] = await db.all(\n sql.raw(\n `SELECT l.version__status as _status FROM \"${versionsTable}\" v JOIN \"${versionsTable}_locales\" l ON l._parent_id = v.id WHERE l._locale = '${locale}' ORDER BY v.created_at DESC LIMIT 1`,\n ),\n )\n\n const status = latestVersionRows[0]?._status || 'draft'\n\n await db.run(\n sql.raw(\n `UPDATE \"${globalLocalesTable}\" SET _status = '${status}' WHERE _parent_id = ${globalDoc.id} AND _locale = '${locale}'`,\n ),\n )\n }\n\n payload.logger.info({ msg: 'Migrated global document' })\n}\n"],"names":["sql","toSnakeCase","migrateMainGlobalStatus","db","globalSlug","locales","payload","versionsTable","globalTable","globalLocalesTable","logger","info","msg","globalDoc","get","raw","warn","locale","latestVersionRows","all","status","_status","run","id"],"mappings":"AAEA,SAASA,GAAG,QAAQ,cAAa;AACjC,OAAOC,iBAAiB,gBAAe;AAEvC;;CAEC,GACD,OAAO,eAAeC,wBAAwB,EAC5CC,EAAE,EACFC,UAAU,EACVC,OAAO,EACPC,OAAO,EACPC,aAAa,EAOd;IACC,MAAMC,cAAcP,YAAYG;IAChC,MAAMK,qBAAqB,GAAGD,YAAY,QAAQ,CAAC;IAEnDF,QAAQI,MAAM,CAACC,IAAI,CAAC;QAAEC,KAAK,CAAC,mCAAmC,EAAEH,oBAAoB;IAAC;IAEtF,MAAMI,YAAiB,MAAMV,GAAGW,GAAG,CAACd,IAAIe,GAAG,CAAC,CAAC,gBAAgB,EAAEP,YAAY,SAAS,CAAC;IAErF,IAAI,CAACK,WAAW;QACdP,QAAQI,MAAM,CAACM,IAAI,CAAC;YAAEJ,KAAK,CAAC,6BAA6B,EAAER,WAAW,UAAU,CAAC;QAAC;QAClF;IACF;IAEA,KAAK,MAAMa,UAAUZ,QAAS;QAC5B,MAAMa,oBAA2B,MAAMf,GAAGgB,GAAG,CAC3CnB,IAAIe,GAAG,CACL,CAAC,0CAA0C,EAAER,cAAc,UAAU,EAAEA,cAAc,sDAAsD,EAAEU,OAAO,oCAAoC,CAAC;QAI7L,MAAMG,SAASF,iBAAiB,CAAC,EAAE,EAAEG,WAAW;QAEhD,MAAMlB,GAAGmB,GAAG,CACVtB,IAAIe,GAAG,CACL,CAAC,QAAQ,EAAEN,mBAAmB,iBAAiB,EAAEW,OAAO,qBAAqB,EAAEP,UAAUU,EAAE,CAAC,gBAAgB,EAAEN,OAAO,CAAC,CAAC;IAG7H;IAEAX,QAAQI,MAAM,CAACC,IAAI,CAAC;QAAEC,KAAK;IAA2B;AACxD"}
@@ -1 +1 @@
1
- {"version":3,"file":"handleUpsertError.d.ts","sourceRoot":"","sources":["../../src/upsertRow/handleUpsertError.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAI7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD,KAAK,qBAAqB,GAAG;IAC3B,OAAO,EAAE,cAAc,CAAA;IACvB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,KAAK,EAAE,OAAO,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACpB,GAAG,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,kFAQ/B,qBAAqB,KAAG,KAiE1B,CAAA"}
1
+ {"version":3,"file":"handleUpsertError.d.ts","sourceRoot":"","sources":["../../src/upsertRow/handleUpsertError.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAI7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD,KAAK,qBAAqB,GAAG;IAC3B,OAAO,EAAE,cAAc,CAAA;IACvB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,KAAK,EAAE,OAAO,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACpB,GAAG,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,kFAQ/B,qBAAqB,KAAG,KAkE1B,CAAA"}
@@ -51,7 +51,8 @@ import { ValidationError } from 'payload';
51
51
  errors: [
52
52
  {
53
53
  message: req?.t ? req.t('error:valueMustBeUnique') : 'Value must be unique',
54
- path: fieldName
54
+ path: fieldName,
55
+ tableName
55
56
  }
56
57
  ],
57
58
  global: globalSlug,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/upsertRow/handleUpsertError.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { ValidationError } from 'payload'\n\nimport type { DrizzleAdapter } from '../types.js'\n\ntype HandleUpsertErrorArgs = {\n adapter: DrizzleAdapter\n collectionSlug?: string\n error: unknown\n globalSlug?: string\n id?: number | string\n req?: Partial<PayloadRequest>\n tableName: string\n}\n\n/**\n * Handles unique constraint violation errors from PostgreSQL and SQLite,\n * converting them to Payload ValidationErrors.\n * Re-throws non-constraint errors unchanged.\n */\nexport const handleUpsertError = ({\n id,\n adapter,\n collectionSlug,\n error: caughtError,\n globalSlug,\n req,\n tableName,\n}: HandleUpsertErrorArgs): never => {\n let error: any = caughtError\n if (typeof caughtError === 'object' && caughtError !== null && 'cause' in caughtError) {\n error = caughtError.cause\n }\n\n // PostgreSQL: 23505, SQLite: SQLITE_CONSTRAINT_UNIQUE\n if (error?.code === '23505' || error?.code === 'SQLITE_CONSTRAINT_UNIQUE') {\n let fieldName: null | string = null\n\n if (error.code === '23505') {\n // PostgreSQL - extract field name from constraint\n if (adapter.fieldConstraints?.[tableName]?.[error.constraint]) {\n fieldName = adapter.fieldConstraints[tableName][error.constraint]\n } else {\n const replacement = `${tableName}_`\n if (error.constraint?.includes(replacement)) {\n const replacedConstraint = error.constraint.replace(replacement, '')\n if (replacedConstraint && adapter.fieldConstraints[tableName]?.[replacedConstraint]) {\n fieldName = adapter.fieldConstraints[tableName][replacedConstraint]\n }\n }\n }\n\n if (!fieldName && error.detail) {\n // Extract from detail: \"Key (field)=(value) already exists.\"\n const regex = /Key \\(([^)]+)\\)=\\(([^)]+)\\)/\n const match: string[] = error.detail.match(regex)\n if (match && match[1]) {\n fieldName = match[1]\n }\n }\n } else if (error.code === 'SQLITE_CONSTRAINT_UNIQUE') {\n // SQLite - extract from message: \"UNIQUE constraint failed: table.field[, table.field2, ...]\"\n const regex = /UNIQUE constraint failed: ([^.]+)\\.([^.,]+)/\n const match: string[] = error.message?.match(regex)\n if (match && match[2]) {\n if (adapter.fieldConstraints[tableName]) {\n fieldName = adapter.fieldConstraints[tableName][`${match[2]}_idx`]\n }\n if (!fieldName) {\n fieldName = match[2]\n }\n }\n }\n\n throw new ValidationError(\n {\n id,\n collection: collectionSlug,\n errors: [\n {\n message: req?.t ? req.t('error:valueMustBeUnique') : 'Value must be unique',\n path: fieldName,\n },\n ],\n global: globalSlug,\n req,\n },\n req?.t,\n )\n }\n\n // Re-throw non-constraint errors\n throw caughtError\n}\n"],"names":["ValidationError","handleUpsertError","id","adapter","collectionSlug","error","caughtError","globalSlug","req","tableName","cause","code","fieldName","fieldConstraints","constraint","replacement","includes","replacedConstraint","replace","detail","regex","match","message","collection","errors","t","path","global"],"mappings":"AAEA,SAASA,eAAe,QAAQ,UAAS;AAczC;;;;CAIC,GACD,OAAO,MAAMC,oBAAoB,CAAC,EAChCC,EAAE,EACFC,OAAO,EACPC,cAAc,EACdC,OAAOC,WAAW,EAClBC,UAAU,EACVC,GAAG,EACHC,SAAS,EACa;IACtB,IAAIJ,QAAaC;IACjB,IAAI,OAAOA,gBAAgB,YAAYA,gBAAgB,QAAQ,WAAWA,aAAa;QACrFD,QAAQC,YAAYI,KAAK;IAC3B;IAEA,sDAAsD;IACtD,IAAIL,OAAOM,SAAS,WAAWN,OAAOM,SAAS,4BAA4B;QACzE,IAAIC,YAA2B;QAE/B,IAAIP,MAAMM,IAAI,KAAK,SAAS;YAC1B,kDAAkD;YAClD,IAAIR,QAAQU,gBAAgB,EAAE,CAACJ,UAAU,EAAE,CAACJ,MAAMS,UAAU,CAAC,EAAE;gBAC7DF,YAAYT,QAAQU,gBAAgB,CAACJ,UAAU,CAACJ,MAAMS,UAAU,CAAC;YACnE,OAAO;gBACL,MAAMC,cAAc,GAAGN,UAAU,CAAC,CAAC;gBACnC,IAAIJ,MAAMS,UAAU,EAAEE,SAASD,cAAc;oBAC3C,MAAME,qBAAqBZ,MAAMS,UAAU,CAACI,OAAO,CAACH,aAAa;oBACjE,IAAIE,sBAAsBd,QAAQU,gBAAgB,CAACJ,UAAU,EAAE,CAACQ,mBAAmB,EAAE;wBACnFL,YAAYT,QAAQU,gBAAgB,CAACJ,UAAU,CAACQ,mBAAmB;oBACrE;gBACF;YACF;YAEA,IAAI,CAACL,aAAaP,MAAMc,MAAM,EAAE;gBAC9B,6DAA6D;gBAC7D,MAAMC,QAAQ;gBACd,MAAMC,QAAkBhB,MAAMc,MAAM,CAACE,KAAK,CAACD;gBAC3C,IAAIC,SAASA,KAAK,CAAC,EAAE,EAAE;oBACrBT,YAAYS,KAAK,CAAC,EAAE;gBACtB;YACF;QACF,OAAO,IAAIhB,MAAMM,IAAI,KAAK,4BAA4B;YACpD,8FAA8F;YAC9F,MAAMS,QAAQ;YACd,MAAMC,QAAkBhB,MAAMiB,OAAO,EAAED,MAAMD;YAC7C,IAAIC,SAASA,KAAK,CAAC,EAAE,EAAE;gBACrB,IAAIlB,QAAQU,gBAAgB,CAACJ,UAAU,EAAE;oBACvCG,YAAYT,QAAQU,gBAAgB,CAACJ,UAAU,CAAC,GAAGY,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;gBACpE;gBACA,IAAI,CAACT,WAAW;oBACdA,YAAYS,KAAK,CAAC,EAAE;gBACtB;YACF;QACF;QAEA,MAAM,IAAIrB,gBACR;YACEE;YACAqB,YAAYnB;YACZoB,QAAQ;gBACN;oBACEF,SAASd,KAAKiB,IAAIjB,IAAIiB,CAAC,CAAC,6BAA6B;oBACrDC,MAAMd;gBACR;aACD;YACDe,QAAQpB;YACRC;QACF,GACAA,KAAKiB;IAET;IAEA,iCAAiC;IACjC,MAAMnB;AACR,EAAC"}
1
+ {"version":3,"sources":["../../src/upsertRow/handleUpsertError.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { ValidationError } from 'payload'\n\nimport type { DrizzleAdapter } from '../types.js'\n\ntype HandleUpsertErrorArgs = {\n adapter: DrizzleAdapter\n collectionSlug?: string\n error: unknown\n globalSlug?: string\n id?: number | string\n req?: Partial<PayloadRequest>\n tableName: string\n}\n\n/**\n * Handles unique constraint violation errors from PostgreSQL and SQLite,\n * converting them to Payload ValidationErrors.\n * Re-throws non-constraint errors unchanged.\n */\nexport const handleUpsertError = ({\n id,\n adapter,\n collectionSlug,\n error: caughtError,\n globalSlug,\n req,\n tableName,\n}: HandleUpsertErrorArgs): never => {\n let error: any = caughtError\n if (typeof caughtError === 'object' && caughtError !== null && 'cause' in caughtError) {\n error = caughtError.cause\n }\n\n // PostgreSQL: 23505, SQLite: SQLITE_CONSTRAINT_UNIQUE\n if (error?.code === '23505' || error?.code === 'SQLITE_CONSTRAINT_UNIQUE') {\n let fieldName: null | string = null\n\n if (error.code === '23505') {\n // PostgreSQL - extract field name from constraint\n if (adapter.fieldConstraints?.[tableName]?.[error.constraint]) {\n fieldName = adapter.fieldConstraints[tableName][error.constraint]\n } else {\n const replacement = `${tableName}_`\n if (error.constraint?.includes(replacement)) {\n const replacedConstraint = error.constraint.replace(replacement, '')\n if (replacedConstraint && adapter.fieldConstraints[tableName]?.[replacedConstraint]) {\n fieldName = adapter.fieldConstraints[tableName][replacedConstraint]\n }\n }\n }\n\n if (!fieldName && error.detail) {\n // Extract from detail: \"Key (field)=(value) already exists.\"\n const regex = /Key \\(([^)]+)\\)=\\(([^)]+)\\)/\n const match: string[] = error.detail.match(regex)\n if (match && match[1]) {\n fieldName = match[1]\n }\n }\n } else if (error.code === 'SQLITE_CONSTRAINT_UNIQUE') {\n // SQLite - extract from message: \"UNIQUE constraint failed: table.field[, table.field2, ...]\"\n const regex = /UNIQUE constraint failed: ([^.]+)\\.([^.,]+)/\n const match: string[] = error.message?.match(regex)\n if (match && match[2]) {\n if (adapter.fieldConstraints[tableName]) {\n fieldName = adapter.fieldConstraints[tableName][`${match[2]}_idx`]\n }\n if (!fieldName) {\n fieldName = match[2]\n }\n }\n }\n\n throw new ValidationError(\n {\n id,\n collection: collectionSlug,\n errors: [\n {\n message: req?.t ? req.t('error:valueMustBeUnique') : 'Value must be unique',\n path: fieldName,\n tableName,\n },\n ],\n global: globalSlug,\n req,\n },\n req?.t,\n )\n }\n\n // Re-throw non-constraint errors\n throw caughtError\n}\n"],"names":["ValidationError","handleUpsertError","id","adapter","collectionSlug","error","caughtError","globalSlug","req","tableName","cause","code","fieldName","fieldConstraints","constraint","replacement","includes","replacedConstraint","replace","detail","regex","match","message","collection","errors","t","path","global"],"mappings":"AAEA,SAASA,eAAe,QAAQ,UAAS;AAczC;;;;CAIC,GACD,OAAO,MAAMC,oBAAoB,CAAC,EAChCC,EAAE,EACFC,OAAO,EACPC,cAAc,EACdC,OAAOC,WAAW,EAClBC,UAAU,EACVC,GAAG,EACHC,SAAS,EACa;IACtB,IAAIJ,QAAaC;IACjB,IAAI,OAAOA,gBAAgB,YAAYA,gBAAgB,QAAQ,WAAWA,aAAa;QACrFD,QAAQC,YAAYI,KAAK;IAC3B;IAEA,sDAAsD;IACtD,IAAIL,OAAOM,SAAS,WAAWN,OAAOM,SAAS,4BAA4B;QACzE,IAAIC,YAA2B;QAE/B,IAAIP,MAAMM,IAAI,KAAK,SAAS;YAC1B,kDAAkD;YAClD,IAAIR,QAAQU,gBAAgB,EAAE,CAACJ,UAAU,EAAE,CAACJ,MAAMS,UAAU,CAAC,EAAE;gBAC7DF,YAAYT,QAAQU,gBAAgB,CAACJ,UAAU,CAACJ,MAAMS,UAAU,CAAC;YACnE,OAAO;gBACL,MAAMC,cAAc,GAAGN,UAAU,CAAC,CAAC;gBACnC,IAAIJ,MAAMS,UAAU,EAAEE,SAASD,cAAc;oBAC3C,MAAME,qBAAqBZ,MAAMS,UAAU,CAACI,OAAO,CAACH,aAAa;oBACjE,IAAIE,sBAAsBd,QAAQU,gBAAgB,CAACJ,UAAU,EAAE,CAACQ,mBAAmB,EAAE;wBACnFL,YAAYT,QAAQU,gBAAgB,CAACJ,UAAU,CAACQ,mBAAmB;oBACrE;gBACF;YACF;YAEA,IAAI,CAACL,aAAaP,MAAMc,MAAM,EAAE;gBAC9B,6DAA6D;gBAC7D,MAAMC,QAAQ;gBACd,MAAMC,QAAkBhB,MAAMc,MAAM,CAACE,KAAK,CAACD;gBAC3C,IAAIC,SAASA,KAAK,CAAC,EAAE,EAAE;oBACrBT,YAAYS,KAAK,CAAC,EAAE;gBACtB;YACF;QACF,OAAO,IAAIhB,MAAMM,IAAI,KAAK,4BAA4B;YACpD,8FAA8F;YAC9F,MAAMS,QAAQ;YACd,MAAMC,QAAkBhB,MAAMiB,OAAO,EAAED,MAAMD;YAC7C,IAAIC,SAASA,KAAK,CAAC,EAAE,EAAE;gBACrB,IAAIlB,QAAQU,gBAAgB,CAACJ,UAAU,EAAE;oBACvCG,YAAYT,QAAQU,gBAAgB,CAACJ,UAAU,CAAC,GAAGY,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;gBACpE;gBACA,IAAI,CAACT,WAAW;oBACdA,YAAYS,KAAK,CAAC,EAAE;gBACtB;YACF;QACF;QAEA,MAAM,IAAIrB,gBACR;YACEE;YACAqB,YAAYnB;YACZoB,QAAQ;gBACN;oBACEF,SAASd,KAAKiB,IAAIjB,IAAIiB,CAAC,CAAC,6BAA6B;oBACrDC,MAAMd;oBACNH;gBACF;aACD;YACDkB,QAAQpB;YACRC;QACF,GACAA,KAAKiB;IAET;IAEA,iCAAiC;IACjC,MAAMnB;AACR,EAAC"}
@@ -0,0 +1,42 @@
1
+ import { ValidationError } from 'payload';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { handleUpsertError } from './handleUpsertError.js';
4
+ const adapter = {
5
+ fieldConstraints: {}
6
+ };
7
+ describe('handleUpsertError', ()=>{
8
+ it('preserves the failing sub-table name on the ValidationError', ()=>{
9
+ const pgError = {
10
+ code: '23505',
11
+ constraint: 'ultrasonic_avail_country_pkey',
12
+ detail: 'Key (id)=(6a27e2a63f4b64567370f595) already exists.'
13
+ };
14
+ let thrown;
15
+ try {
16
+ handleUpsertError({
17
+ adapter,
18
+ collectionSlug: 'ultrasonic',
19
+ error: pgError,
20
+ tableName: 'ultrasonic_avail_country'
21
+ });
22
+ } catch (error) {
23
+ thrown = error;
24
+ }
25
+ expect(thrown).toBeInstanceOf(ValidationError);
26
+ const validationError = thrown;
27
+ const fieldError = validationError.data.errors[0];
28
+ expect(fieldError.path).toBe('id');
29
+ expect(fieldError.tableName).toBe('ultrasonic_avail_country');
30
+ });
31
+ it('re-throws non unique-constraint errors unchanged', ()=>{
32
+ const otherError = new Error('some other db error');
33
+ expect(()=>handleUpsertError({
34
+ adapter,
35
+ collectionSlug: 'ultrasonic',
36
+ error: otherError,
37
+ tableName: 'ultrasonic_avail_country'
38
+ })).toThrow(otherError);
39
+ });
40
+ });
41
+
42
+ //# sourceMappingURL=handleUpsertError.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/upsertRow/handleUpsertError.spec.ts"],"sourcesContent":["import { ValidationError } from 'payload'\nimport { describe, expect, it } from 'vitest'\n\nimport type { DrizzleAdapter } from '../types.js'\n\nimport { handleUpsertError } from './handleUpsertError.js'\n\nconst adapter = { fieldConstraints: {} } as unknown as DrizzleAdapter\n\ndescribe('handleUpsertError', () => {\n it('preserves the failing sub-table name on the ValidationError', () => {\n const pgError = {\n code: '23505',\n constraint: 'ultrasonic_avail_country_pkey',\n detail: 'Key (id)=(6a27e2a63f4b64567370f595) already exists.',\n }\n\n let thrown: unknown\n try {\n handleUpsertError({\n adapter,\n collectionSlug: 'ultrasonic',\n error: pgError,\n tableName: 'ultrasonic_avail_country',\n })\n } catch (error) {\n thrown = error\n }\n\n expect(thrown).toBeInstanceOf(ValidationError)\n const validationError = thrown as ValidationError\n const fieldError = validationError.data.errors[0]!\n expect(fieldError.path).toBe('id')\n expect(fieldError.tableName).toBe('ultrasonic_avail_country')\n })\n\n it('re-throws non unique-constraint errors unchanged', () => {\n const otherError = new Error('some other db error')\n\n expect(() =>\n handleUpsertError({\n adapter,\n collectionSlug: 'ultrasonic',\n error: otherError,\n tableName: 'ultrasonic_avail_country',\n }),\n ).toThrow(otherError)\n })\n})\n"],"names":["ValidationError","describe","expect","it","handleUpsertError","adapter","fieldConstraints","pgError","code","constraint","detail","thrown","collectionSlug","error","tableName","toBeInstanceOf","validationError","fieldError","data","errors","path","toBe","otherError","Error","toThrow"],"mappings":"AAAA,SAASA,eAAe,QAAQ,UAAS;AACzC,SAASC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAI7C,SAASC,iBAAiB,QAAQ,yBAAwB;AAE1D,MAAMC,UAAU;IAAEC,kBAAkB,CAAC;AAAE;AAEvCL,SAAS,qBAAqB;IAC5BE,GAAG,+DAA+D;QAChE,MAAMI,UAAU;YACdC,MAAM;YACNC,YAAY;YACZC,QAAQ;QACV;QAEA,IAAIC;QACJ,IAAI;YACFP,kBAAkB;gBAChBC;gBACAO,gBAAgB;gBAChBC,OAAON;gBACPO,WAAW;YACb;QACF,EAAE,OAAOD,OAAO;YACdF,SAASE;QACX;QAEAX,OAAOS,QAAQI,cAAc,CAACf;QAC9B,MAAMgB,kBAAkBL;QACxB,MAAMM,aAAaD,gBAAgBE,IAAI,CAACC,MAAM,CAAC,EAAE;QACjDjB,OAAOe,WAAWG,IAAI,EAAEC,IAAI,CAAC;QAC7BnB,OAAOe,WAAWH,SAAS,EAAEO,IAAI,CAAC;IACpC;IAEAlB,GAAG,oDAAoD;QACrD,MAAMmB,aAAa,IAAIC,MAAM;QAE7BrB,OAAO,IACLE,kBAAkB;gBAChBC;gBACAO,gBAAgB;gBAChBC,OAAOS;gBACPR,WAAW;YACb,IACAU,OAAO,CAACF;IACZ;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/upsertRow/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAKzC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAqBtC;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,GAAU,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,EAAE,6KAqB7E,IAAI,KAAG,OAAO,CAAC,CAAC,CAgtBlB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/upsertRow/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAKzC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAqBtC;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,GAAU,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,EAAE,6KAqB7E,IAAI,KAAG,OAAO,CAAC,CAAC,CAotBlB,CAAA"}
@@ -157,9 +157,12 @@ customID, joinQuery: _joinQuery, operation, path = '', req, select, tableName, u
157
157
  if (operation === 'update') {
158
158
  const target = upsertTarget || adapter.tables[tableName].id;
159
159
  // Check if we only have relationship operations and no main row data to update
160
- // Exclude timestamp-only updates when we only have relationship operations
160
+ // Exclude timestamp-only updates when we only have relationship operations.
161
+ // Localized field updates live in the `_locales` table, so the main row may only
162
+ // contain timestamps — in that case the parent row's `updatedAt` must still bump.
161
163
  const rowKeys = Object.keys(rowToInsert.row);
162
- const hasMainRowData = rowKeys.length > 0 && !rowKeys.every((key)=>key === 'updatedAt' || key === 'createdAt');
164
+ const hasLocalizedData = Object.keys(rowToInsert.locales).length > 0;
165
+ const hasMainRowData = rowKeys.length > 0 && (hasLocalizedData || !rowKeys.every((key)=>key === 'updatedAt' || key === 'createdAt'));
163
166
  if (hasMainRowData) {
164
167
  if (id) {
165
168
  rowToInsert.row.id = id;