@payloadcms/drizzle 4.0.0-internal.5d5a2b2 → 4.0.0-internal.688c4d0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/exports/postgres.d.ts +1 -0
- package/dist/exports/postgres.d.ts.map +1 -1
- package/dist/exports/postgres.js +1 -0
- package/dist/exports/postgres.js.map +1 -1
- package/dist/exports/sqlite.d.ts +1 -0
- package/dist/exports/sqlite.d.ts.map +1 -1
- package/dist/exports/sqlite.js +1 -0
- package/dist/exports/sqlite.js.map +1 -1
- package/dist/find/traverseFields.js +1 -2
- package/dist/find/traverseFields.js.map +1 -1
- package/dist/postgres/predefinedMigrations/localize-status/index.d.ts +11 -0
- package/dist/postgres/predefinedMigrations/localize-status/index.d.ts.map +1 -0
- package/dist/postgres/predefinedMigrations/localize-status/index.js +296 -0
- package/dist/postgres/predefinedMigrations/localize-status/index.js.map +1 -0
- package/dist/postgres/predefinedMigrations/localize-status/migrateMainCollection.d.ts +13 -0
- package/dist/postgres/predefinedMigrations/localize-status/migrateMainCollection.d.ts.map +1 -0
- package/dist/postgres/predefinedMigrations/localize-status/migrateMainCollection.js +51 -0
- package/dist/postgres/predefinedMigrations/localize-status/migrateMainCollection.js.map +1 -0
- package/dist/postgres/predefinedMigrations/localize-status/migrateMainGlobal.d.ts +13 -0
- package/dist/postgres/predefinedMigrations/localize-status/migrateMainGlobal.d.ts.map +1 -0
- package/dist/postgres/predefinedMigrations/localize-status/migrateMainGlobal.js +54 -0
- package/dist/postgres/predefinedMigrations/localize-status/migrateMainGlobal.js.map +1 -0
- package/dist/postgres/predefinedMigrations/v2-v3/fetchAndResave/traverseFields.d.ts.map +1 -1
- package/dist/postgres/predefinedMigrations/v2-v3/fetchAndResave/traverseFields.js.map +1 -1
- package/dist/queries/getTableColumnFromPath.js +2 -2
- package/dist/queries/getTableColumnFromPath.js.map +1 -1
- package/dist/schema/traverseFields.js +1 -1
- package/dist/schema/traverseFields.js.map +1 -1
- package/dist/sqlite/predefinedMigrations/localize-status/index.d.ts +28 -0
- package/dist/sqlite/predefinedMigrations/localize-status/index.d.ts.map +1 -0
- package/dist/sqlite/predefinedMigrations/localize-status/index.js +198 -0
- package/dist/sqlite/predefinedMigrations/localize-status/index.js.map +1 -0
- package/dist/sqlite/predefinedMigrations/localize-status/migrateMainCollection.d.ts +12 -0
- package/dist/sqlite/predefinedMigrations/localize-status/migrateMainCollection.d.ts.map +1 -0
- package/dist/sqlite/predefinedMigrations/localize-status/migrateMainCollection.js +24 -0
- package/dist/sqlite/predefinedMigrations/localize-status/migrateMainCollection.js.map +1 -0
- package/dist/sqlite/predefinedMigrations/localize-status/migrateMainGlobal.d.ts +12 -0
- package/dist/sqlite/predefinedMigrations/localize-status/migrateMainGlobal.d.ts.map +1 -0
- package/dist/sqlite/predefinedMigrations/localize-status/migrateMainGlobal.js +28 -0
- package/dist/sqlite/predefinedMigrations/localize-status/migrateMainGlobal.js.map +1 -0
- package/dist/transform/read/traverseFields.js +2 -2
- package/dist/transform/read/traverseFields.js.map +1 -1
- package/dist/transform/write/blocks.js +1 -1
- package/dist/transform/write/blocks.js.map +1 -1
- package/dist/transform/write/traverseFields.js +1 -2
- package/dist/transform/write/traverseFields.js.map +1 -1
- package/dist/upsertRow/index.d.ts.map +1 -1
- package/dist/upsertRow/index.js +5 -2
- package/dist/upsertRow/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { calculateVersionLocaleStatuses } from 'payload/migrations';
|
|
2
|
+
import toSnakeCase from 'to-snake-case';
|
|
3
|
+
import { migrateMainCollectionStatus } from './migrateMainCollection.js';
|
|
4
|
+
import { migrateMainGlobalStatus } from './migrateMainGlobal.js';
|
|
5
|
+
export async function migratePostgresLocalizeStatus(args) {
|
|
6
|
+
const { collectionSlug, db, globalSlug, payload, req, sql } = args;
|
|
7
|
+
const schemaName = db.schemaName ?? 'public';
|
|
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
|
+
// Convert camelCase slugs to snake_case and add version prefix/suffix
|
|
16
|
+
const versionsTable = collectionSlug ? `_${toSnakeCase(collectionSlug)}_v` : `_${toSnakeCase(globalSlug)}_v`;
|
|
17
|
+
const localesTable = `${versionsTable}_locales`;
|
|
18
|
+
if (!payload.config.localization) {
|
|
19
|
+
throw new Error('Localization is not enabled in payload config');
|
|
20
|
+
}
|
|
21
|
+
// Check if versions are enabled on this collection/global
|
|
22
|
+
let entityConfig;
|
|
23
|
+
if (collectionSlug) {
|
|
24
|
+
const collection = payload.config.collections.find((c)=>c.slug === collectionSlug);
|
|
25
|
+
if (collection) {
|
|
26
|
+
entityConfig = collection;
|
|
27
|
+
}
|
|
28
|
+
} else if (globalSlug) {
|
|
29
|
+
const global = payload.config.globals.find((g)=>g.slug === globalSlug);
|
|
30
|
+
if (global) {
|
|
31
|
+
entityConfig = global;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (!entityConfig) {
|
|
35
|
+
throw new Error(`${collectionSlug ? 'Collection' : 'Global'} not found: ${collectionSlug || globalSlug}`);
|
|
36
|
+
}
|
|
37
|
+
payload.logger.info({
|
|
38
|
+
msg: `Starting _status localization migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug}`
|
|
39
|
+
});
|
|
40
|
+
// Get filtered locales if filterAvailableLocales is defined
|
|
41
|
+
let locales = payload.config.localization.localeCodes;
|
|
42
|
+
if (typeof payload.config.localization.filterAvailableLocales === 'function') {
|
|
43
|
+
const filteredLocaleObjects = await payload.config.localization.filterAvailableLocales({
|
|
44
|
+
locales: payload.config.localization.locales,
|
|
45
|
+
req
|
|
46
|
+
});
|
|
47
|
+
locales = filteredLocaleObjects.map((locale)=>locale.code);
|
|
48
|
+
}
|
|
49
|
+
payload.logger.info({
|
|
50
|
+
msg: `Locales: ${locales.join(', ')}`
|
|
51
|
+
});
|
|
52
|
+
// Check if versions are enabled in config (skip if not)
|
|
53
|
+
if (!entityConfig.versions) {
|
|
54
|
+
payload.logger.info({
|
|
55
|
+
msg: `Skipping migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug} - versions not enabled`
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Validate that version__status column exists before proceeding
|
|
60
|
+
const columnCheckResult = await db.execute({
|
|
61
|
+
drizzle: db.drizzle,
|
|
62
|
+
sql: sql`
|
|
63
|
+
SELECT EXISTS (
|
|
64
|
+
SELECT FROM information_schema.columns
|
|
65
|
+
WHERE table_schema = ${schemaName}
|
|
66
|
+
AND table_name = ${versionsTable}
|
|
67
|
+
AND column_name = 'version__status'
|
|
68
|
+
) as exists
|
|
69
|
+
`
|
|
70
|
+
});
|
|
71
|
+
if (!columnCheckResult.rows[0]?.exists) {
|
|
72
|
+
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.`);
|
|
73
|
+
}
|
|
74
|
+
// 1. Check if the locales table exists
|
|
75
|
+
const localesTableCheckResult = await db.execute({
|
|
76
|
+
drizzle: db.drizzle,
|
|
77
|
+
sql: sql`
|
|
78
|
+
SELECT EXISTS (
|
|
79
|
+
SELECT FROM information_schema.tables
|
|
80
|
+
WHERE table_schema = ${schemaName}
|
|
81
|
+
AND table_name = ${localesTable}
|
|
82
|
+
) as exists
|
|
83
|
+
`
|
|
84
|
+
});
|
|
85
|
+
const localesTableExists = localesTableCheckResult.rows[0]?.exists;
|
|
86
|
+
if (!localesTableExists) {
|
|
87
|
+
// SCENARIO 1: Create the locales table (first localized field in versions)
|
|
88
|
+
payload.logger.info({
|
|
89
|
+
msg: `Creating new locales table: ${localesTable}`
|
|
90
|
+
});
|
|
91
|
+
await db.execute({
|
|
92
|
+
drizzle: db.drizzle,
|
|
93
|
+
sql: sql`
|
|
94
|
+
CREATE TABLE ${sql.identifier(localesTable)} (
|
|
95
|
+
id SERIAL PRIMARY KEY,
|
|
96
|
+
_locale VARCHAR NOT NULL,
|
|
97
|
+
_parent_id INTEGER NOT NULL,
|
|
98
|
+
version__status VARCHAR,
|
|
99
|
+
UNIQUE(_locale, _parent_id),
|
|
100
|
+
FOREIGN KEY (_parent_id) REFERENCES ${sql.identifier(versionsTable)}(id) ON DELETE CASCADE
|
|
101
|
+
)
|
|
102
|
+
`
|
|
103
|
+
});
|
|
104
|
+
// Create one row per locale per version record
|
|
105
|
+
// Simple approach: copy the same status to all locales
|
|
106
|
+
for (const locale of locales){
|
|
107
|
+
const inserted = await db.execute({
|
|
108
|
+
drizzle: db.drizzle,
|
|
109
|
+
sql: sql`
|
|
110
|
+
INSERT INTO ${sql.identifier(localesTable)} (_locale, _parent_id, version__status)
|
|
111
|
+
SELECT ${locale}, id, version__status
|
|
112
|
+
FROM ${sql.identifier(versionsTable)}
|
|
113
|
+
RETURNING id
|
|
114
|
+
`
|
|
115
|
+
});
|
|
116
|
+
payload.logger.info({
|
|
117
|
+
msg: `Inserted ${inserted.length} rows for locale: ${locale}`
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
// SCENARIO 2: Add version__status column to existing locales table
|
|
122
|
+
payload.logger.info({
|
|
123
|
+
msg: `Adding version__status column to existing table: ${localesTable}`
|
|
124
|
+
});
|
|
125
|
+
await db.execute({
|
|
126
|
+
drizzle: db.drizzle,
|
|
127
|
+
sql: sql`
|
|
128
|
+
ALTER TABLE ${sql.identifier(localesTable)} ADD COLUMN version__status VARCHAR
|
|
129
|
+
`
|
|
130
|
+
});
|
|
131
|
+
// INTELLIGENT DATA MIGRATION using historical publishedLocale data
|
|
132
|
+
payload.logger.info({
|
|
133
|
+
msg: 'Processing version history to determine status per locale...'
|
|
134
|
+
});
|
|
135
|
+
// First, get the list of locales that actually exist in the locales table
|
|
136
|
+
// This is important because the config may have more locales defined than what's in the OLD schema
|
|
137
|
+
const existingLocalesResult = await db.execute({
|
|
138
|
+
drizzle: db.drizzle,
|
|
139
|
+
sql: sql`
|
|
140
|
+
SELECT DISTINCT _locale
|
|
141
|
+
FROM ${sql.identifier(localesTable)}
|
|
142
|
+
ORDER BY _locale
|
|
143
|
+
`
|
|
144
|
+
});
|
|
145
|
+
const existingLocales = existingLocalesResult.rows.map((row)=>row._locale);
|
|
146
|
+
payload.logger.info({
|
|
147
|
+
msg: `Found existing locales in table: ${existingLocales.join(', ')}`
|
|
148
|
+
});
|
|
149
|
+
// Check if the snapshot column exists (only present on DBs that used publishSpecificLocale)
|
|
150
|
+
const snapshotColumnCheckResult = await db.execute({
|
|
151
|
+
drizzle: db.drizzle,
|
|
152
|
+
sql: sql`
|
|
153
|
+
SELECT EXISTS (
|
|
154
|
+
SELECT FROM information_schema.columns
|
|
155
|
+
WHERE table_schema = ${schemaName}
|
|
156
|
+
AND table_name = ${versionsTable}
|
|
157
|
+
AND column_name = 'snapshot'
|
|
158
|
+
) as exists
|
|
159
|
+
`
|
|
160
|
+
});
|
|
161
|
+
const hasSnapshotColumn = snapshotColumnCheckResult.rows[0]?.exists === true;
|
|
162
|
+
// Get all version records grouped by parent document, ordered chronologically
|
|
163
|
+
const versionsResult = await db.execute({
|
|
164
|
+
drizzle: db.drizzle,
|
|
165
|
+
sql: hasSnapshotColumn ? sql`
|
|
166
|
+
SELECT id, parent_id as parent, version__status as _status, published_locale, snapshot, created_at
|
|
167
|
+
FROM ${sql.identifier(versionsTable)}
|
|
168
|
+
ORDER BY parent_id, created_at ASC
|
|
169
|
+
` : sql`
|
|
170
|
+
SELECT id, parent_id as parent, version__status as _status, published_locale, created_at
|
|
171
|
+
FROM ${sql.identifier(versionsTable)}
|
|
172
|
+
ORDER BY parent_id, created_at ASC
|
|
173
|
+
`
|
|
174
|
+
});
|
|
175
|
+
// Use shared function to calculate version locale statuses
|
|
176
|
+
// Only process locales that actually exist in the locales table
|
|
177
|
+
const versionLocaleStatus = calculateVersionLocaleStatuses(versionsResult.rows, existingLocales, payload);
|
|
178
|
+
// Now update the locales table with the calculated status for each version
|
|
179
|
+
payload.logger.info({
|
|
180
|
+
msg: 'Updating locales table with calculated statuses...'
|
|
181
|
+
});
|
|
182
|
+
let updateCount = 0;
|
|
183
|
+
for (const [versionId, localeMap] of versionLocaleStatus.entries()){
|
|
184
|
+
for (const [locale, status] of localeMap.entries()){
|
|
185
|
+
await db.execute({
|
|
186
|
+
drizzle: db.drizzle,
|
|
187
|
+
sql: sql`
|
|
188
|
+
UPDATE ${sql.identifier(localesTable)}
|
|
189
|
+
SET version__status = ${status}
|
|
190
|
+
WHERE _parent_id = ${versionId}
|
|
191
|
+
AND _locale = ${locale}
|
|
192
|
+
`
|
|
193
|
+
});
|
|
194
|
+
updateCount++;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
payload.logger.info({
|
|
198
|
+
msg: `Updated ${updateCount} locale rows with status`
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// 3. Drop the old version__status column from main versions table
|
|
202
|
+
await db.execute({
|
|
203
|
+
drizzle: db.drizzle,
|
|
204
|
+
sql: sql`
|
|
205
|
+
ALTER TABLE ${sql.identifier(versionsTable)} DROP COLUMN version__status
|
|
206
|
+
`
|
|
207
|
+
});
|
|
208
|
+
// 4. Create and populate _status column in main collection/global locales table
|
|
209
|
+
// With localizeStatus enabled, _status is a localized field stored in the collection's locales table
|
|
210
|
+
// We need to create this column and populate it based on the latest version status per locale
|
|
211
|
+
const mainTable = collectionSlug ? toSnakeCase(collectionSlug) : toSnakeCase(globalSlug);
|
|
212
|
+
const mainLocalesTable = `${mainTable}_locales`;
|
|
213
|
+
const localesTableCheck = await db.execute({
|
|
214
|
+
drizzle: db.drizzle,
|
|
215
|
+
sql: sql`
|
|
216
|
+
SELECT EXISTS (
|
|
217
|
+
SELECT FROM information_schema.tables
|
|
218
|
+
WHERE table_schema = ${schemaName}
|
|
219
|
+
AND table_name = ${mainLocalesTable}
|
|
220
|
+
) as exists
|
|
221
|
+
`
|
|
222
|
+
});
|
|
223
|
+
if (localesTableCheck.rows[0]?.exists) {
|
|
224
|
+
// Check if _status column already exists in the locales table
|
|
225
|
+
const statusColumnCheck = await db.execute({
|
|
226
|
+
drizzle: db.drizzle,
|
|
227
|
+
sql: sql`
|
|
228
|
+
SELECT EXISTS (
|
|
229
|
+
SELECT FROM information_schema.columns
|
|
230
|
+
WHERE table_schema = ${schemaName}
|
|
231
|
+
AND table_name = ${mainLocalesTable}
|
|
232
|
+
AND column_name = '_status'
|
|
233
|
+
) as exists
|
|
234
|
+
`
|
|
235
|
+
});
|
|
236
|
+
if (!statusColumnCheck.rows[0]?.exists) {
|
|
237
|
+
// Add _status column to locales table
|
|
238
|
+
await db.execute({
|
|
239
|
+
drizzle: db.drizzle,
|
|
240
|
+
sql: sql`
|
|
241
|
+
ALTER TABLE ${sql.identifier(mainLocalesTable)}
|
|
242
|
+
ADD COLUMN _status VARCHAR DEFAULT 'draft'
|
|
243
|
+
`
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
// Now populate the _status values from the latest version
|
|
247
|
+
if (collectionSlug) {
|
|
248
|
+
await migrateMainCollectionStatus({
|
|
249
|
+
collectionSlug,
|
|
250
|
+
db,
|
|
251
|
+
locales,
|
|
252
|
+
payload,
|
|
253
|
+
sql,
|
|
254
|
+
versionsTable
|
|
255
|
+
});
|
|
256
|
+
} else if (globalSlug) {
|
|
257
|
+
await migrateMainGlobalStatus({
|
|
258
|
+
db,
|
|
259
|
+
globalSlug,
|
|
260
|
+
locales,
|
|
261
|
+
payload,
|
|
262
|
+
sql,
|
|
263
|
+
versionsTable
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
} else {
|
|
267
|
+
payload.logger.info({
|
|
268
|
+
msg: `No locales table found: ${mainLocalesTable} (collection/global not localized)`
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
// 5. Drop _status from main table if it exists (it will be in locales table now)
|
|
272
|
+
const mainTableStatusCheck = await db.execute({
|
|
273
|
+
drizzle: db.drizzle,
|
|
274
|
+
sql: sql`
|
|
275
|
+
SELECT EXISTS (
|
|
276
|
+
SELECT FROM information_schema.columns
|
|
277
|
+
WHERE table_schema = ${schemaName}
|
|
278
|
+
AND table_name = ${mainTable}
|
|
279
|
+
AND column_name = '_status'
|
|
280
|
+
) as exists
|
|
281
|
+
`
|
|
282
|
+
});
|
|
283
|
+
if (mainTableStatusCheck.rows[0]?.exists) {
|
|
284
|
+
await db.execute({
|
|
285
|
+
drizzle: db.drizzle,
|
|
286
|
+
sql: sql`
|
|
287
|
+
ALTER TABLE ${sql.identifier(mainTable)} DROP COLUMN _status
|
|
288
|
+
`
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
payload.logger.info({
|
|
292
|
+
msg: 'Migration completed successfully'
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/postgres/predefinedMigrations/localize-status/index.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\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 sql: any\n}\n\nexport async function migratePostgresLocalizeStatus(args: LocalizeStatusArgs): Promise<void> {\n const { collectionSlug, db, globalSlug, payload, req, sql } = args\n const schemaName = db.schemaName ?? 'public'\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 // Convert camelCase slugs to snake_case and add version prefix/suffix\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 const collection = payload.config.collections.find((c) => c.slug === collectionSlug)\n if (collection) {\n entityConfig = collection\n }\n } else if (globalSlug) {\n const global = payload.config.globals.find((g) => g.slug === globalSlug)\n if (global) {\n entityConfig = global\n }\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) => locale.code)\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 const columnCheckResult = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n SELECT EXISTS (\n SELECT FROM information_schema.columns\n WHERE table_schema = ${schemaName}\n AND table_name = ${versionsTable}\n AND column_name = 'version__status'\n ) as exists\n `,\n })\n\n if (!columnCheckResult.rows[0]?.exists) {\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 // 1. Check if the locales table exists\n const localesTableCheckResult = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n SELECT EXISTS (\n SELECT FROM information_schema.tables\n WHERE table_schema = ${schemaName}\n AND table_name = ${localesTable}\n ) as exists\n `,\n })\n\n const localesTableExists = localesTableCheckResult.rows[0]?.exists\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.execute({\n drizzle: db.drizzle,\n sql: sql`\n CREATE TABLE ${sql.identifier(localesTable)} (\n id SERIAL PRIMARY KEY,\n _locale VARCHAR NOT NULL,\n _parent_id INTEGER NOT NULL,\n version__status VARCHAR,\n UNIQUE(_locale, _parent_id),\n FOREIGN KEY (_parent_id) REFERENCES ${sql.identifier(versionsTable)}(id) ON DELETE CASCADE\n )\n `,\n })\n\n // Create one row per locale per version record\n // Simple approach: copy the same status to all locales\n for (const locale of locales) {\n const inserted = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n INSERT INTO ${sql.identifier(localesTable)} (_locale, _parent_id, version__status)\n SELECT ${locale}, id, version__status\n FROM ${sql.identifier(versionsTable)}\n 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.execute({\n drizzle: db.drizzle,\n sql: sql`\n ALTER TABLE ${sql.identifier(localesTable)} ADD COLUMN version__status VARCHAR\n `,\n })\n\n // INTELLIGENT DATA MIGRATION using historical publishedLocale data\n payload.logger.info({ msg: 'Processing version history to determine status per locale...' })\n\n // First, get the list of locales that actually exist in the locales table\n // This is important because the config may have more locales defined than what's in the OLD schema\n const existingLocalesResult = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n SELECT DISTINCT _locale\n FROM ${sql.identifier(localesTable)}\n ORDER BY _locale\n `,\n })\n const existingLocales = existingLocalesResult.rows.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 snapshotColumnCheckResult = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n SELECT EXISTS (\n SELECT FROM information_schema.columns\n WHERE table_schema = ${schemaName}\n AND table_name = ${versionsTable}\n AND column_name = 'snapshot'\n ) as exists\n `,\n })\n const hasSnapshotColumn = snapshotColumnCheckResult.rows[0]?.exists === true\n\n // Get all version records grouped by parent document, ordered chronologically\n const versionsResult = await db.execute({\n drizzle: db.drizzle,\n sql: hasSnapshotColumn\n ? sql`\n SELECT id, parent_id as parent, version__status as _status, published_locale, snapshot, created_at\n FROM ${sql.identifier(versionsTable)}\n ORDER BY parent_id, created_at ASC\n `\n : sql`\n SELECT id, parent_id as parent, version__status as _status, published_locale, created_at\n FROM ${sql.identifier(versionsTable)}\n ORDER BY parent_id, created_at ASC\n `,\n })\n\n // Use shared function to calculate version locale statuses\n // Only process locales that actually exist in the locales table\n const versionLocaleStatus = calculateVersionLocaleStatuses(\n versionsResult.rows,\n existingLocales,\n payload,\n )\n\n // Now update the locales table with the calculated status for each version\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.execute({\n drizzle: db.drizzle,\n sql: sql`\n UPDATE ${sql.identifier(localesTable)}\n SET version__status = ${status}\n WHERE _parent_id = ${versionId}\n AND _locale = ${locale}\n `,\n })\n updateCount++\n }\n }\n\n payload.logger.info({ msg: `Updated ${updateCount} locale rows with status` })\n }\n\n // 3. Drop the old version__status column from main versions table\n await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n ALTER TABLE ${sql.identifier(versionsTable)} DROP COLUMN version__status\n `,\n })\n\n // 4. Create and populate _status column in main collection/global locales table\n // With localizeStatus enabled, _status is a localized field stored in the collection's locales table\n // We need to create this column and populate it based on the latest version status per locale\n const mainTable = collectionSlug ? toSnakeCase(collectionSlug) : toSnakeCase(globalSlug!)\n const mainLocalesTable = `${mainTable}_locales`\n\n const localesTableCheck = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n SELECT EXISTS (\n SELECT FROM information_schema.tables\n WHERE table_schema = ${schemaName}\n AND table_name = ${mainLocalesTable}\n ) as exists\n `,\n })\n\n if (localesTableCheck.rows[0]?.exists) {\n // Check if _status column already exists in the locales table\n const statusColumnCheck = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n SELECT EXISTS (\n SELECT FROM information_schema.columns\n WHERE table_schema = ${schemaName}\n AND table_name = ${mainLocalesTable}\n AND column_name = '_status'\n ) as exists\n `,\n })\n\n if (!statusColumnCheck.rows[0]?.exists) {\n // Add _status column to locales table\n await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n ALTER TABLE ${sql.identifier(mainLocalesTable)}\n ADD COLUMN _status VARCHAR DEFAULT 'draft'\n `,\n })\n }\n\n // Now populate the _status values from the latest version\n if (collectionSlug) {\n await migrateMainCollectionStatus({\n collectionSlug,\n db,\n locales,\n payload,\n sql,\n versionsTable,\n })\n } else if (globalSlug) {\n await migrateMainGlobalStatus({ db, globalSlug, locales, payload, sql, versionsTable })\n }\n } else {\n payload.logger.info({\n msg: `No locales table found: ${mainLocalesTable} (collection/global not localized)`,\n })\n }\n\n // 5. Drop _status from main table if it exists (it will be in locales table now)\n const mainTableStatusCheck = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n SELECT EXISTS (\n SELECT FROM information_schema.columns\n WHERE table_schema = ${schemaName}\n AND table_name = ${mainTable}\n AND column_name = '_status'\n ) as exists\n `,\n })\n\n if (mainTableStatusCheck.rows[0]?.exists) {\n await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n ALTER TABLE ${sql.identifier(mainTable)} DROP COLUMN _status\n `,\n })\n }\n\n payload.logger.info({ msg: 'Migration completed successfully' })\n}\n"],"names":["calculateVersionLocaleStatuses","toSnakeCase","migrateMainCollectionStatus","migrateMainGlobalStatus","migratePostgresLocalizeStatus","args","collectionSlug","db","globalSlug","payload","req","sql","schemaName","Error","entitySlug","versionsTable","localesTable","config","localization","entityConfig","collection","collections","find","c","slug","global","globals","g","logger","info","msg","locales","localeCodes","filterAvailableLocales","filteredLocaleObjects","map","locale","code","join","versions","columnCheckResult","execute","drizzle","rows","exists","localesTableCheckResult","localesTableExists","identifier","inserted","length","existingLocalesResult","existingLocales","row","_locale","snapshotColumnCheckResult","hasSnapshotColumn","versionsResult","versionLocaleStatus","updateCount","versionId","localeMap","entries","status","mainTable","mainLocalesTable","localesTableCheck","statusColumnCheck","mainTableStatusCheck"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
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, sql, versionsTable, }: {
|
|
6
|
+
collectionSlug: string;
|
|
7
|
+
db: any;
|
|
8
|
+
locales: string[];
|
|
9
|
+
payload: Payload;
|
|
10
|
+
sql: any;
|
|
11
|
+
versionsTable: string;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=migrateMainCollection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrateMainCollection.d.ts","sourceRoot":"","sources":["../../../../src/postgres/predefinedMigrations/localize-status/migrateMainCollection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAItC;;GAEG;AACH,wBAAsB,2BAA2B,CAAC,EAChD,cAAc,EACd,EAAE,EACF,OAAO,EACP,OAAO,EACP,GAAG,EACH,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,GAAG,EAAE,GAAG,CAAA;IACR,aAAa,EAAE,MAAM,CAAA;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+ChB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import toSnakeCase from 'to-snake-case';
|
|
2
|
+
/**
|
|
3
|
+
* Migrates main collection documents from _status to per-locale status object
|
|
4
|
+
*/ export async function migrateMainCollectionStatus({ collectionSlug, db, locales, payload, sql, versionsTable }) {
|
|
5
|
+
const mainTable = toSnakeCase(collectionSlug);
|
|
6
|
+
const mainLocalesTable = `${mainTable}_locales`;
|
|
7
|
+
payload.logger.info({
|
|
8
|
+
msg: `Migrating main collection locales for: ${mainLocalesTable}`
|
|
9
|
+
});
|
|
10
|
+
// Get all documents
|
|
11
|
+
const documents = await db.execute({
|
|
12
|
+
drizzle: db.drizzle,
|
|
13
|
+
sql: sql`
|
|
14
|
+
SELECT DISTINCT id
|
|
15
|
+
FROM ${sql.identifier(mainTable)}
|
|
16
|
+
`
|
|
17
|
+
});
|
|
18
|
+
for (const doc of documents.rows){
|
|
19
|
+
// For each locale, get the latest version status
|
|
20
|
+
for (const locale of locales){
|
|
21
|
+
const latestVersionStatus = await db.execute({
|
|
22
|
+
drizzle: db.drizzle,
|
|
23
|
+
sql: sql`
|
|
24
|
+
SELECT l.version__status as _status
|
|
25
|
+
FROM ${sql.identifier(versionsTable)} v
|
|
26
|
+
JOIN ${sql.raw(`${versionsTable}_locales`)} l ON l._parent_id = v.id
|
|
27
|
+
WHERE v.parent_id = ${doc.id}
|
|
28
|
+
AND l._locale = ${locale}
|
|
29
|
+
ORDER BY v.created_at DESC
|
|
30
|
+
LIMIT 1
|
|
31
|
+
`
|
|
32
|
+
});
|
|
33
|
+
const status = latestVersionStatus.rows[0]?._status || 'draft';
|
|
34
|
+
// Update the main collection's locales table with this status
|
|
35
|
+
await db.execute({
|
|
36
|
+
drizzle: db.drizzle,
|
|
37
|
+
sql: sql`
|
|
38
|
+
UPDATE ${sql.identifier(mainLocalesTable)}
|
|
39
|
+
SET _status = ${status}
|
|
40
|
+
WHERE _parent_id = ${doc.id}
|
|
41
|
+
AND _locale = ${locale}
|
|
42
|
+
`
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
payload.logger.info({
|
|
47
|
+
msg: `Migrated ${documents.rows.length} collection documents`
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=migrateMainCollection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/postgres/predefinedMigrations/localize-status/migrateMainCollection.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\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 sql,\n versionsTable,\n}: {\n collectionSlug: string\n db: any\n locales: string[]\n payload: Payload\n sql: any\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 // Get all documents\n const documents = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n SELECT DISTINCT id\n FROM ${sql.identifier(mainTable)}\n `,\n })\n\n for (const doc of documents.rows) {\n // For each locale, get the latest version status\n for (const locale of locales) {\n const latestVersionStatus = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n SELECT l.version__status as _status\n FROM ${sql.identifier(versionsTable)} v\n JOIN ${sql.raw(`${versionsTable}_locales`)} l ON l._parent_id = v.id\n WHERE v.parent_id = ${doc.id}\n AND l._locale = ${locale}\n ORDER BY v.created_at DESC\n LIMIT 1\n `,\n })\n\n const status = latestVersionStatus.rows[0]?._status || 'draft'\n\n // Update the main collection's locales table with this status\n await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n UPDATE ${sql.identifier(mainLocalesTable)}\n SET _status = ${status}\n WHERE _parent_id = ${doc.id}\n AND _locale = ${locale}\n `,\n })\n }\n }\n\n payload.logger.info({ msg: `Migrated ${documents.rows.length} collection documents` })\n}\n"],"names":["toSnakeCase","migrateMainCollectionStatus","collectionSlug","db","locales","payload","sql","versionsTable","mainTable","mainLocalesTable","logger","info","msg","documents","execute","drizzle","identifier","doc","rows","locale","latestVersionStatus","raw","id","status","_status","length"],"mappings":"AAEA,OAAOA,iBAAiB,gBAAe;AAEvC;;CAEC,GACD,OAAO,eAAeC,4BAA4B,EAChDC,cAAc,EACdC,EAAE,EACFC,OAAO,EACPC,OAAO,EACPC,GAAG,EACHC,aAAa,EAQd;IACC,MAAMC,YAAYR,YAAYE;IAC9B,MAAMO,mBAAmB,GAAGD,UAAU,QAAQ,CAAC;IAE/CH,QAAQK,MAAM,CAACC,IAAI,CAAC;QAAEC,KAAK,CAAC,uCAAuC,EAAEH,kBAAkB;IAAC;IAExF,oBAAoB;IACpB,MAAMI,YAAY,MAAMV,GAAGW,OAAO,CAAC;QACjCC,SAASZ,GAAGY,OAAO;QACnBT,KAAKA,GAAG,CAAC;;WAEF,EAAEA,IAAIU,UAAU,CAACR,WAAW;IACnC,CAAC;IACH;IAEA,KAAK,MAAMS,OAAOJ,UAAUK,IAAI,CAAE;QAChC,iDAAiD;QACjD,KAAK,MAAMC,UAAUf,QAAS;YAC5B,MAAMgB,sBAAsB,MAAMjB,GAAGW,OAAO,CAAC;gBAC3CC,SAASZ,GAAGY,OAAO;gBACnBT,KAAKA,GAAG,CAAC;;eAEF,EAAEA,IAAIU,UAAU,CAACT,eAAe;eAChC,EAAED,IAAIe,GAAG,CAAC,GAAGd,cAAc,QAAQ,CAAC,EAAE;8BACvB,EAAEU,IAAIK,EAAE,CAAC;0BACb,EAAEH,OAAO;;;QAG3B,CAAC;YACH;YAEA,MAAMI,SAASH,oBAAoBF,IAAI,CAAC,EAAE,EAAEM,WAAW;YAEvD,8DAA8D;YAC9D,MAAMrB,GAAGW,OAAO,CAAC;gBACfC,SAASZ,GAAGY,OAAO;gBACnBT,KAAKA,GAAG,CAAC;iBACA,EAAEA,IAAIU,UAAU,CAACP,kBAAkB;wBAC5B,EAAEc,OAAO;6BACJ,EAAEN,IAAIK,EAAE,CAAC;wBACd,EAAEH,OAAO;QACzB,CAAC;YACH;QACF;IACF;IAEAd,QAAQK,MAAM,CAACC,IAAI,CAAC;QAAEC,KAAK,CAAC,SAAS,EAAEC,UAAUK,IAAI,CAACO,MAAM,CAAC,qBAAqB,CAAC;IAAC;AACtF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
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, sql, versionsTable, }: {
|
|
6
|
+
db: any;
|
|
7
|
+
globalSlug: string;
|
|
8
|
+
locales: string[];
|
|
9
|
+
payload: Payload;
|
|
10
|
+
sql: any;
|
|
11
|
+
versionsTable: string;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=migrateMainGlobal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrateMainGlobal.d.ts","sourceRoot":"","sources":["../../../../src/postgres/predefinedMigrations/localize-status/migrateMainGlobal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAItC;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,EAC5C,EAAE,EACF,UAAU,EACV,OAAO,EACP,OAAO,EACP,GAAG,EACH,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,GAAG,EAAE,GAAG,CAAA;IACR,aAAa,EAAE,MAAM,CAAA;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkDhB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import toSnakeCase from 'to-snake-case';
|
|
2
|
+
/**
|
|
3
|
+
* Migrates main global document from _status to per-locale status object
|
|
4
|
+
*/ export async function migrateMainGlobalStatus({ db, globalSlug, locales, payload, sql, versionsTable }) {
|
|
5
|
+
const globalTable = toSnakeCase(globalSlug);
|
|
6
|
+
const globalLocalesTable = `${globalTable}_locales`;
|
|
7
|
+
payload.logger.info({
|
|
8
|
+
msg: `Migrating main global locales for: ${globalLocalesTable}`
|
|
9
|
+
});
|
|
10
|
+
// For each locale, get the latest version status
|
|
11
|
+
for (const locale of locales){
|
|
12
|
+
const latestVersionStatus = await db.execute({
|
|
13
|
+
drizzle: db.drizzle,
|
|
14
|
+
sql: sql`
|
|
15
|
+
SELECT l.version__status as _status
|
|
16
|
+
FROM ${sql.identifier(versionsTable)} v
|
|
17
|
+
JOIN ${sql.raw(`${versionsTable}_locales`)} l ON l._parent_id = v.id
|
|
18
|
+
WHERE l._locale = ${locale}
|
|
19
|
+
ORDER BY v.created_at DESC
|
|
20
|
+
LIMIT 1
|
|
21
|
+
`
|
|
22
|
+
});
|
|
23
|
+
const status = latestVersionStatus.rows[0]?._status || 'draft';
|
|
24
|
+
// Get the global document ID from the globals table
|
|
25
|
+
const globalDoc = await db.execute({
|
|
26
|
+
drizzle: db.drizzle,
|
|
27
|
+
sql: sql`
|
|
28
|
+
SELECT id FROM ${sql.identifier(globalTable)} LIMIT 1
|
|
29
|
+
`
|
|
30
|
+
});
|
|
31
|
+
if (globalDoc.rows.length === 0) {
|
|
32
|
+
payload.logger.warn({
|
|
33
|
+
msg: `No global document found for ${globalSlug}, skipping`
|
|
34
|
+
});
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const globalId = globalDoc.rows[0].id;
|
|
38
|
+
// Update the global's locales table with this status
|
|
39
|
+
await db.execute({
|
|
40
|
+
drizzle: db.drizzle,
|
|
41
|
+
sql: sql`
|
|
42
|
+
UPDATE ${sql.identifier(globalLocalesTable)}
|
|
43
|
+
SET _status = ${status}
|
|
44
|
+
WHERE _parent_id = ${globalId}
|
|
45
|
+
AND _locale = ${locale}
|
|
46
|
+
`
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
payload.logger.info({
|
|
50
|
+
msg: 'Migrated global document'
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=migrateMainGlobal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/postgres/predefinedMigrations/localize-status/migrateMainGlobal.ts"],"sourcesContent":["import type { Payload } from 'payload'\n\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 sql,\n versionsTable,\n}: {\n db: any\n globalSlug: string\n locales: string[]\n payload: Payload\n sql: any\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 // For each locale, get the latest version status\n for (const locale of locales) {\n const latestVersionStatus = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n SELECT l.version__status as _status\n FROM ${sql.identifier(versionsTable)} v\n JOIN ${sql.raw(`${versionsTable}_locales`)} l ON l._parent_id = v.id\n WHERE l._locale = ${locale}\n ORDER BY v.created_at DESC\n LIMIT 1\n `,\n })\n\n const status = latestVersionStatus.rows[0]?._status || 'draft'\n\n // Get the global document ID from the globals table\n const globalDoc = await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n SELECT id FROM ${sql.identifier(globalTable)} LIMIT 1\n `,\n })\n\n if (globalDoc.rows.length === 0) {\n payload.logger.warn({ msg: `No global document found for ${globalSlug}, skipping` })\n continue\n }\n\n const globalId = globalDoc.rows[0].id\n\n // Update the global's locales table with this status\n await db.execute({\n drizzle: db.drizzle,\n sql: sql`\n UPDATE ${sql.identifier(globalLocalesTable)}\n SET _status = ${status}\n WHERE _parent_id = ${globalId}\n AND _locale = ${locale}\n `,\n })\n }\n\n payload.logger.info({ msg: 'Migrated global document' })\n}\n"],"names":["toSnakeCase","migrateMainGlobalStatus","db","globalSlug","locales","payload","sql","versionsTable","globalTable","globalLocalesTable","logger","info","msg","locale","latestVersionStatus","execute","drizzle","identifier","raw","status","rows","_status","globalDoc","length","warn","globalId","id"],"mappings":"AAEA,OAAOA,iBAAiB,gBAAe;AAEvC;;CAEC,GACD,OAAO,eAAeC,wBAAwB,EAC5CC,EAAE,EACFC,UAAU,EACVC,OAAO,EACPC,OAAO,EACPC,GAAG,EACHC,aAAa,EAQd;IACC,MAAMC,cAAcR,YAAYG;IAChC,MAAMM,qBAAqB,GAAGD,YAAY,QAAQ,CAAC;IAEnDH,QAAQK,MAAM,CAACC,IAAI,CAAC;QAAEC,KAAK,CAAC,mCAAmC,EAAEH,oBAAoB;IAAC;IAEtF,iDAAiD;IACjD,KAAK,MAAMI,UAAUT,QAAS;QAC5B,MAAMU,sBAAsB,MAAMZ,GAAGa,OAAO,CAAC;YAC3CC,SAASd,GAAGc,OAAO;YACnBV,KAAKA,GAAG,CAAC;;aAEF,EAAEA,IAAIW,UAAU,CAACV,eAAe;aAChC,EAAED,IAAIY,GAAG,CAAC,GAAGX,cAAc,QAAQ,CAAC,EAAE;0BACzB,EAAEM,OAAO;;;MAG7B,CAAC;QACH;QAEA,MAAMM,SAASL,oBAAoBM,IAAI,CAAC,EAAE,EAAEC,WAAW;QAEvD,oDAAoD;QACpD,MAAMC,YAAY,MAAMpB,GAAGa,OAAO,CAAC;YACjCC,SAASd,GAAGc,OAAO;YACnBV,KAAKA,GAAG,CAAC;uBACQ,EAAEA,IAAIW,UAAU,CAACT,aAAa;MAC/C,CAAC;QACH;QAEA,IAAIc,UAAUF,IAAI,CAACG,MAAM,KAAK,GAAG;YAC/BlB,QAAQK,MAAM,CAACc,IAAI,CAAC;gBAAEZ,KAAK,CAAC,6BAA6B,EAAET,WAAW,UAAU,CAAC;YAAC;YAClF;QACF;QAEA,MAAMsB,WAAWH,UAAUF,IAAI,CAAC,EAAE,CAACM,EAAE;QAErC,qDAAqD;QACrD,MAAMxB,GAAGa,OAAO,CAAC;YACfC,SAASd,GAAGc,OAAO;YACnBV,KAAKA,GAAG,CAAC;eACA,EAAEA,IAAIW,UAAU,CAACR,oBAAoB;sBAC9B,EAAEU,OAAO;2BACJ,EAAEM,SAAS;sBAChB,EAAEZ,OAAO;MACzB,CAAC;QACH;IACF;IAEAR,QAAQK,MAAM,CAACC,IAAI,CAAC;QAAEC,KAAK;IAA2B;AACxD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traverseFields.d.ts","sourceRoot":"","sources":["../../../../../src/postgres/predefinedMigrations/v2-v3/fetchAndResave/traverseFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"traverseFields.d.ts","sourceRoot":"","sources":["../../../../../src/postgres/predefinedMigrations/v2-v3/fetchAndResave/traverseFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7D,KAAK,IAAI,GAAG;IACV,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC5B,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;CAChC,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,qCAAqC,IAAI,SAwKvE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/postgres/predefinedMigrations/v2-v3/fetchAndResave/traverseFields.ts"],"sourcesContent":["import type { FlattenedField } from 'payload'\n\ntype Args = {\n doc: Record<string, unknown>\n fields: FlattenedField[]\n locale?: string\n path: string\n rows: Record<string, unknown>[]\n}\n\nexport const traverseFields = ({ doc, fields, locale, path, rows }: Args) => {\n fields.forEach((field) => {\n switch (field.type) {\n case 'array': {\n const rowData = doc?.[field.name]\n\n if (field.localized && typeof rowData === 'object' && rowData !== null) {\n Object.entries(rowData).forEach(([locale, localeRows]) => {\n if (Array.isArray(localeRows)) {\n localeRows.forEach((row, i) => {\n return traverseFields({\n doc: row as Record<string, unknown>,\n fields: field.flattenedFields,\n locale,\n path: `${path ? `${path}.` : ''}${field.name}.${i}`,\n rows,\n })\n })\n }\n })\n }\n\n if (Array.isArray(rowData)) {\n rowData.forEach((row, i) => {\n return traverseFields({\n doc: row as Record<string, unknown>,\n fields: field.flattenedFields,\n path: `${path ? `${path}.` : ''}${field.name}.${i}`,\n rows,\n })\n })\n }\n\n break\n }\n\n case 'blocks': {\n const rowData = doc?.[field.name]\n\n if (field.localized && typeof rowData === 'object' && rowData !== null) {\n Object.entries(rowData).forEach(([locale, localeRows]) => {\n if (Array.isArray(localeRows)) {\n localeRows.forEach((row, i) => {\n // Can ignore string blocks, as those were added in v3 and don't need to be migrated\n const matchedBlock = field.blocks.find(\n (block) => typeof block !== 'string' && block.slug === row.blockType,\n )\n\n if (matchedBlock) {\n return traverseFields({\n doc: row as Record<string, unknown>,\n fields: matchedBlock.flattenedFields,\n locale,\n path: `${path ? `${path}.` : ''}${field.name}.${i}`,\n rows,\n })\n }\n })\n }\n })\n }\n\n if (Array.isArray(rowData)) {\n rowData.forEach((row, i) => {\n // Can ignore string blocks, as those were added in v3 and don't need to be migrated\n const matchedBlock = field.blocks.find(\n (block) => typeof block !== 'string' && block.slug === row.blockType,\n )\n\n if (matchedBlock) {\n return traverseFields({\n doc: row as Record<string, unknown>,\n fields: matchedBlock.flattenedFields,\n path: `${path ? `${path}.` : ''}${field.name}.${i}`,\n rows,\n })\n }\n })\n }\n\n break\n }\n\n case 'group':\n case 'tab': {\n const newPath = `${path ? `${path}.` : ''}${field.name}`\n const newDoc = doc?.[field.name]\n\n if (typeof newDoc === 'object' && newDoc !== null) {\n if (field.localized) {\n Object.entries(newDoc).forEach(([locale, localeDoc]) => {\n return traverseFields({\n doc: localeDoc,\n fields: field.flattenedFields,\n locale,\n path: newPath,\n rows,\n })\n })\n } else {\n return traverseFields({\n doc: newDoc as Record<string, unknown>,\n fields: field.flattenedFields,\n path: newPath,\n rows,\n })\n }\n }\n\n break\n }\n\n case 'relationship':\n // falls through\n case 'upload': {\n if (typeof field.relationTo === 'string') {\n if (field.type === 'upload' || !field.hasMany) {\n const relationshipPath = `${path ? `${path}.` : ''}${field.name}`\n\n if (field.localized) {\n const matchedRelationshipsWithLocales = rows.filter(\n (row) => row.path === relationshipPath,\n )\n\n if (matchedRelationshipsWithLocales.length && !doc[field.name]) {\n doc[field.name] = {}\n }\n\n const newDoc = doc[field.name] as Record<string, unknown>\n\n matchedRelationshipsWithLocales.forEach((localeRow) => {\n if (typeof localeRow.locale === 'string') {\n const [, id] = Object.entries(localeRow).find(\n ([key, val]) =>\n val !== null && !['id', 'locale', 'order', 'parent_id', 'path'].includes(key),\n )\n\n newDoc[localeRow.locale] = id\n }\n })\n } else {\n const matchedRelationship = rows.find((row) => {\n const matchesPath = row.path === relationshipPath\n\n if (locale) {\n return matchesPath && locale === row.locale\n }\n\n return row.path === relationshipPath\n })\n\n if (matchedRelationship) {\n const [, id] = Object.entries(matchedRelationship).find(\n ([key, val]) =>\n val !== null && !['id', 'locale', 'order', 'parent_id', 'path'].includes(key),\n )\n\n doc[field.name] = id\n }\n }\n }\n }\n break\n }\n }\n })\n}\n"],"names":["traverseFields","doc","fields","locale","path","rows","forEach","field","type","rowData","name","localized","Object","entries","localeRows","Array","isArray","row","i","flattenedFields","matchedBlock","blocks","find","block","slug","blockType","newPath","newDoc","localeDoc","relationTo","hasMany","relationshipPath","matchedRelationshipsWithLocales","filter","length","localeRow","id","key","val","includes","matchedRelationship","matchesPath"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/postgres/predefinedMigrations/v2-v3/fetchAndResave/traverseFields.ts"],"sourcesContent":["import type { FlattenedBlock, FlattenedField } from 'payload'\n\ntype Args = {\n doc: Record<string, unknown>\n fields: FlattenedField[]\n locale?: string\n path: string\n rows: Record<string, unknown>[]\n}\n\nexport const traverseFields = ({ doc, fields, locale, path, rows }: Args) => {\n fields.forEach((field) => {\n switch (field.type) {\n case 'array': {\n const rowData = doc?.[field.name]\n\n if (field.localized && typeof rowData === 'object' && rowData !== null) {\n Object.entries(rowData).forEach(([locale, localeRows]) => {\n if (Array.isArray(localeRows)) {\n localeRows.forEach((row, i) => {\n return traverseFields({\n doc: row as Record<string, unknown>,\n fields: field.flattenedFields,\n locale,\n path: `${path ? `${path}.` : ''}${field.name}.${i}`,\n rows,\n })\n })\n }\n })\n }\n\n if (Array.isArray(rowData)) {\n rowData.forEach((row, i) => {\n return traverseFields({\n doc: row as Record<string, unknown>,\n fields: field.flattenedFields,\n path: `${path ? `${path}.` : ''}${field.name}.${i}`,\n rows,\n })\n })\n }\n\n break\n }\n\n case 'blocks': {\n const rowData = doc?.[field.name]\n\n if (field.localized && typeof rowData === 'object' && rowData !== null) {\n Object.entries(rowData).forEach(([locale, localeRows]) => {\n if (Array.isArray(localeRows)) {\n localeRows.forEach((row, i) => {\n // Can ignore string blocks, as those were added in v3 and don't need to be migrated\n const matchedBlock = field.blocks.find(\n (block): block is FlattenedBlock =>\n typeof block !== 'string' && block.slug === row.blockType,\n )\n\n if (matchedBlock) {\n return traverseFields({\n doc: row as Record<string, unknown>,\n fields: matchedBlock.flattenedFields,\n locale,\n path: `${path ? `${path}.` : ''}${field.name}.${i}`,\n rows,\n })\n }\n })\n }\n })\n }\n\n if (Array.isArray(rowData)) {\n rowData.forEach((row, i) => {\n // Can ignore string blocks, as those were added in v3 and don't need to be migrated\n const matchedBlock = field.blocks.find(\n (block): block is FlattenedBlock =>\n typeof block !== 'string' && block.slug === row.blockType,\n )\n\n if (matchedBlock) {\n return traverseFields({\n doc: row as Record<string, unknown>,\n fields: matchedBlock.flattenedFields,\n path: `${path ? `${path}.` : ''}${field.name}.${i}`,\n rows,\n })\n }\n })\n }\n\n break\n }\n\n case 'group':\n case 'tab': {\n const newPath = `${path ? `${path}.` : ''}${field.name}`\n const newDoc = doc?.[field.name]\n\n if (typeof newDoc === 'object' && newDoc !== null) {\n if (field.localized) {\n Object.entries(newDoc).forEach(([locale, localeDoc]) => {\n return traverseFields({\n doc: localeDoc,\n fields: field.flattenedFields,\n locale,\n path: newPath,\n rows,\n })\n })\n } else {\n return traverseFields({\n doc: newDoc as Record<string, unknown>,\n fields: field.flattenedFields,\n path: newPath,\n rows,\n })\n }\n }\n\n break\n }\n\n case 'relationship':\n // falls through\n case 'upload': {\n if (typeof field.relationTo === 'string') {\n if (field.type === 'upload' || !field.hasMany) {\n const relationshipPath = `${path ? `${path}.` : ''}${field.name}`\n\n if (field.localized) {\n const matchedRelationshipsWithLocales = rows.filter(\n (row) => row.path === relationshipPath,\n )\n\n if (matchedRelationshipsWithLocales.length && !doc[field.name]) {\n doc[field.name] = {}\n }\n\n const newDoc = doc[field.name] as Record<string, unknown>\n\n matchedRelationshipsWithLocales.forEach((localeRow) => {\n if (typeof localeRow.locale === 'string') {\n const [, id] = Object.entries(localeRow).find(\n ([key, val]) =>\n val !== null && !['id', 'locale', 'order', 'parent_id', 'path'].includes(key),\n )\n\n newDoc[localeRow.locale] = id\n }\n })\n } else {\n const matchedRelationship = rows.find((row) => {\n const matchesPath = row.path === relationshipPath\n\n if (locale) {\n return matchesPath && locale === row.locale\n }\n\n return row.path === relationshipPath\n })\n\n if (matchedRelationship) {\n const [, id] = Object.entries(matchedRelationship).find(\n ([key, val]) =>\n val !== null && !['id', 'locale', 'order', 'parent_id', 'path'].includes(key),\n )\n\n doc[field.name] = id\n }\n }\n }\n }\n break\n }\n }\n })\n}\n"],"names":["traverseFields","doc","fields","locale","path","rows","forEach","field","type","rowData","name","localized","Object","entries","localeRows","Array","isArray","row","i","flattenedFields","matchedBlock","blocks","find","block","slug","blockType","newPath","newDoc","localeDoc","relationTo","hasMany","relationshipPath","matchedRelationshipsWithLocales","filter","length","localeRow","id","key","val","includes","matchedRelationship","matchesPath"],"mappings":"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"}
|
|
@@ -114,7 +114,7 @@ import { getTableAlias } from './getTableAlias.js';
|
|
|
114
114
|
value
|
|
115
115
|
];
|
|
116
116
|
blockTypes.forEach((blockType)=>{
|
|
117
|
-
const block = adapter.payload.blocks[blockType] ??
|
|
117
|
+
const block = adapter.payload.blocks[blockType] ?? field.blocks.find((block)=>typeof block !== 'string' && block.slug === blockType);
|
|
118
118
|
newTableName = resolveBlockTableName(block, adapter.tableNameMap.get(`${tableName}_blocks_${toSnakeCase(block.slug)}`));
|
|
119
119
|
const { newAliasTable } = getTableAlias({
|
|
120
120
|
adapter,
|
|
@@ -137,7 +137,7 @@ import { getTableAlias } from './getTableAlias.js';
|
|
|
137
137
|
table: adapter.tables[tableName]
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
|
-
const hasBlockField =
|
|
140
|
+
const hasBlockField = field.blocks.some((_block)=>{
|
|
141
141
|
const block = typeof _block === 'string' ? adapter.payload.blocks[_block] : _block;
|
|
142
142
|
newTableName = resolveBlockTableName(block, adapter.tableNameMap.get(`${tableName}_blocks_${toSnakeCase(block.slug)}`));
|
|
143
143
|
constraintPath = `${constraintPath}${field.name}.%.`;
|