feat: payload cms
This commit is contained in:
285
src/migrations/20260225_175000_native_localization.ts
Normal file
285
src/migrations/20260225_175000_native_localization.ts
Normal file
@@ -0,0 +1,285 @@
|
||||
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres';
|
||||
|
||||
/**
|
||||
* Migration: native_localization
|
||||
*
|
||||
* Transforms the existing schema (manual `locale` select column on each row)
|
||||
* into Payload's native localization join-table structure.
|
||||
*
|
||||
* Each statement is a separate db.execute call to avoid Drizzle multi-statement issues.
|
||||
*/
|
||||
export async function up({ db }: MigrateUpArgs): Promise<void> {
|
||||
// ── 1. Global locale enum ────────────────────────────────────────────────────
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "public"."enum__locales" AS ENUM('de', 'en');
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "public"."enum__posts_v_published_locale" AS ENUM('de', 'en');
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "public"."enum__products_v_published_locale" AS ENUM('de', 'en');
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "public"."enum__pages_v_published_locale" AS ENUM('de', 'en');
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "public"."enum_pages_layout" AS ENUM('default', 'fullBleed');
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "public"."enum__pages_v_version_layout" AS ENUM('default', 'fullBleed');
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "public"."enum__pages_v_version_status" AS ENUM('draft', 'published');
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "public"."enum__posts_v_version_status" AS ENUM('draft', 'published');
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "public"."enum__products_v_version_status" AS ENUM('draft', 'published');
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
|
||||
// ── 2. Alter pages table ─────────────────────────────────────────────────────
|
||||
await db.execute(sql`ALTER TABLE "pages" ADD COLUMN IF NOT EXISTS "layout" "enum_pages_layout" DEFAULT 'default'`);
|
||||
await db.execute(sql`ALTER TABLE "pages" ADD COLUMN IF NOT EXISTS "_status" "enum_pages_status" DEFAULT 'draft'`);
|
||||
|
||||
// ── 3. Create pages_locales join table ───────────────────────────────────────
|
||||
await db.execute(sql`
|
||||
CREATE TABLE IF NOT EXISTS "pages_locales" (
|
||||
"title" varchar,
|
||||
"slug" varchar,
|
||||
"excerpt" varchar,
|
||||
"content" jsonb,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "enum__locales" NOT NULL,
|
||||
"_parent_id" integer NOT NULL
|
||||
)
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "pages_locales" ADD CONSTRAINT "pages_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "pages_locales" ADD CONSTRAINT "pages_locales_parent_id_fk"
|
||||
FOREIGN KEY ("_parent_id") REFERENCES "pages"("id") ON DELETE cascade;
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
|
||||
// ── 4. Backfill pages_locales from old pages rows ────────────────────────────
|
||||
await db.execute(sql`
|
||||
INSERT INTO "pages_locales" ("title", "slug", "excerpt", "content", "_locale", "_parent_id")
|
||||
SELECT
|
||||
p.title, p.slug, p.excerpt, p.content,
|
||||
CASE WHEN p.locale::text = 'de' THEN 'de'::"enum__locales" ELSE 'en'::"enum__locales" END,
|
||||
p.id
|
||||
FROM "pages" p
|
||||
WHERE p.locale IS NOT NULL
|
||||
ON CONFLICT ("_locale", "_parent_id") DO UPDATE
|
||||
SET "title" = EXCLUDED."title",
|
||||
"slug" = EXCLUDED."slug",
|
||||
"excerpt" = EXCLUDED."excerpt",
|
||||
"content" = EXCLUDED."content"
|
||||
`);
|
||||
|
||||
// ── 5. Drop old columns from pages ───────────────────────────────────────────
|
||||
await db.execute(sql`ALTER TABLE "pages" DROP COLUMN IF EXISTS "title"`);
|
||||
await db.execute(sql`ALTER TABLE "pages" DROP COLUMN IF EXISTS "slug"`);
|
||||
await db.execute(sql`ALTER TABLE "pages" DROP COLUMN IF EXISTS "excerpt"`);
|
||||
await db.execute(sql`ALTER TABLE "pages" DROP COLUMN IF EXISTS "content"`);
|
||||
await db.execute(sql`ALTER TABLE "pages" DROP COLUMN IF EXISTS "locale"`);
|
||||
|
||||
// ── 6. Create posts_locales join table ───────────────────────────────────────
|
||||
await db.execute(sql`
|
||||
CREATE TABLE IF NOT EXISTS "posts_locales" (
|
||||
"title" varchar,
|
||||
"slug" varchar,
|
||||
"excerpt" varchar,
|
||||
"category" varchar,
|
||||
"content" jsonb,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "enum__locales" NOT NULL,
|
||||
"_parent_id" integer NOT NULL
|
||||
)
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "posts_locales" ADD CONSTRAINT "posts_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "posts_locales" ADD CONSTRAINT "posts_locales_parent_id_fk"
|
||||
FOREIGN KEY ("_parent_id") REFERENCES "posts"("id") ON DELETE cascade;
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
|
||||
// ── 7. Backfill posts_locales ────────────────────────────────────────────────
|
||||
await db.execute(sql`
|
||||
INSERT INTO "posts_locales" ("title", "slug", "excerpt", "category", "content", "_locale", "_parent_id")
|
||||
SELECT
|
||||
p.title, p.slug, p.excerpt, p.category, p.content,
|
||||
CASE WHEN p.locale::text = 'de' THEN 'de'::"enum__locales" ELSE 'en'::"enum__locales" END,
|
||||
p.id
|
||||
FROM "posts" p
|
||||
WHERE p.locale IS NOT NULL
|
||||
ON CONFLICT ("_locale", "_parent_id") DO UPDATE
|
||||
SET "title" = EXCLUDED."title",
|
||||
"slug" = EXCLUDED."slug",
|
||||
"excerpt" = EXCLUDED."excerpt",
|
||||
"category" = EXCLUDED."category",
|
||||
"content" = EXCLUDED."content"
|
||||
`);
|
||||
|
||||
// ── 8. Drop old columns from posts ───────────────────────────────────────────
|
||||
await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "title"`);
|
||||
await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "slug"`);
|
||||
await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "excerpt"`);
|
||||
await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "category"`);
|
||||
await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "content"`);
|
||||
await db.execute(sql`ALTER TABLE "posts" DROP COLUMN IF EXISTS "locale"`);
|
||||
|
||||
// ── 9. Create products_locales join table ────────────────────────────────────
|
||||
await db.execute(sql`
|
||||
CREATE TABLE IF NOT EXISTS "products_locales" (
|
||||
"title" varchar,
|
||||
"description" varchar,
|
||||
"application" jsonb,
|
||||
"content" jsonb,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "enum__locales" NOT NULL,
|
||||
"_parent_id" integer NOT NULL
|
||||
)
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "products_locales" ADD CONSTRAINT "products_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "products_locales" ADD CONSTRAINT "products_locales_parent_id_fk"
|
||||
FOREIGN KEY ("_parent_id") REFERENCES "products"("id") ON DELETE cascade;
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
|
||||
// ── 10. Backfill products_locales ────────────────────────────────────────────
|
||||
// Products were separate DE/EN rows — each becomes a locale entry on its own id
|
||||
await db.execute(sql`
|
||||
INSERT INTO "products_locales" ("title", "description", "application", "content", "_locale", "_parent_id")
|
||||
SELECT
|
||||
p.title, p.description, p.application, p.content,
|
||||
CASE WHEN p.locale::text = 'de' THEN 'de'::"enum__locales" ELSE 'en'::"enum__locales" END,
|
||||
p.id
|
||||
FROM "products" p
|
||||
WHERE p.locale IS NOT NULL
|
||||
ON CONFLICT ("_locale", "_parent_id") DO NOTHING
|
||||
`);
|
||||
|
||||
// ── 11. Drop old columns from products ───────────────────────────────────────
|
||||
await db.execute(sql`ALTER TABLE "products" DROP COLUMN IF EXISTS "title"`);
|
||||
await db.execute(sql`ALTER TABLE "products" DROP COLUMN IF EXISTS "description"`);
|
||||
await db.execute(sql`ALTER TABLE "products" DROP COLUMN IF EXISTS "application"`);
|
||||
await db.execute(sql`ALTER TABLE "products" DROP COLUMN IF EXISTS "content"`);
|
||||
await db.execute(sql`ALTER TABLE "products" DROP COLUMN IF EXISTS "locale"`);
|
||||
|
||||
// ── 12. Version tables (_posts_v, _products_v, _pages_v) locale columns ──────
|
||||
await db.execute(sql`ALTER TABLE "_posts_v" ADD COLUMN IF NOT EXISTS "published_locale" "enum__posts_v_published_locale"`);
|
||||
await db.execute(sql`ALTER TABLE "_products_v" ADD COLUMN IF NOT EXISTS "published_locale" "enum__products_v_published_locale"`);
|
||||
await db.execute(sql`ALTER TABLE "_pages_v" ADD COLUMN IF NOT EXISTS "published_locale" "enum__pages_v_published_locale"`);
|
||||
|
||||
// ── 13. Create _posts_v_locales ──────────────────────────────────────────────
|
||||
await db.execute(sql`
|
||||
CREATE TABLE IF NOT EXISTS "_posts_v_locales" (
|
||||
"version_title" varchar, "version_slug" varchar, "version_excerpt" varchar,
|
||||
"version_category" varchar, "version_content" jsonb,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "enum__locales" NOT NULL, "_parent_id" integer NOT NULL
|
||||
)
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_posts_v_locales" ADD CONSTRAINT "_posts_v_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_posts_v_locales" ADD CONSTRAINT "_posts_v_locales_parent_id_fk"
|
||||
FOREIGN KEY ("_parent_id") REFERENCES "_posts_v"("id") ON DELETE cascade;
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
|
||||
// ── 14. Create _products_v_locales ───────────────────────────────────────────
|
||||
await db.execute(sql`
|
||||
CREATE TABLE IF NOT EXISTS "_products_v_locales" (
|
||||
"version_title" varchar, "version_description" varchar,
|
||||
"version_application" jsonb, "version_content" jsonb,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "enum__locales" NOT NULL, "_parent_id" integer NOT NULL
|
||||
)
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_products_v_locales" ADD CONSTRAINT "_products_v_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_products_v_locales" ADD CONSTRAINT "_products_v_locales_parent_id_fk"
|
||||
FOREIGN KEY ("_parent_id") REFERENCES "_products_v"("id") ON DELETE cascade;
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
|
||||
// ── 15. Create _pages_v_locales ──────────────────────────────────────────────
|
||||
await db.execute(sql`
|
||||
CREATE TABLE IF NOT EXISTS "_pages_v_locales" (
|
||||
"version_title" varchar, "version_slug" varchar,
|
||||
"version_excerpt" varchar, "version_content" jsonb,
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"_locale" "enum__locales" NOT NULL, "_parent_id" integer NOT NULL
|
||||
)
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_pages_v_locales" ADD CONSTRAINT "_pages_v_locales_locale_parent_id_unique" UNIQUE("_locale", "_parent_id");
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
await db.execute(sql`
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_pages_v_locales" ADD CONSTRAINT "_pages_v_locales_parent_id_fk"
|
||||
FOREIGN KEY ("_parent_id") REFERENCES "_pages_v"("id") ON DELETE cascade;
|
||||
EXCEPTION WHEN duplicate_object THEN null; END $$
|
||||
`);
|
||||
|
||||
// ── 16. Drop the now-redundant old locale enum ───────────────────────────────
|
||||
await db.execute(sql`DROP TYPE IF EXISTS "public"."enum_pages_locale"`);
|
||||
await db.execute(sql`DROP TYPE IF EXISTS "public"."enum_posts_locale"`);
|
||||
await db.execute(sql`DROP TYPE IF EXISTS "public"."enum_products_locale"`);
|
||||
}
|
||||
|
||||
export async function down({ db }: MigrateDownArgs): Promise<void> {
|
||||
await db.execute(sql`DROP TABLE IF EXISTS "pages_locales" CASCADE`);
|
||||
await db.execute(sql`DROP TABLE IF EXISTS "_pages_v_locales" CASCADE`);
|
||||
await db.execute(sql`DROP TABLE IF EXISTS "posts_locales" CASCADE`);
|
||||
await db.execute(sql`DROP TABLE IF EXISTS "_posts_v_locales" CASCADE`);
|
||||
await db.execute(sql`DROP TABLE IF EXISTS "products_locales" CASCADE`);
|
||||
await db.execute(sql`DROP TABLE IF EXISTS "_products_v_locales" CASCADE`);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as migration_20260223_195005_products_collection from './20260223_195005_products_collection';
|
||||
import * as migration_20260223_195151_remove_sku_unique from './20260223_195151_remove_sku_unique';
|
||||
import * as migration_20260225_003500_add_pages_collection from './20260225_003500_add_pages_collection';
|
||||
import * as migration_20260225_175000_native_localization from './20260225_175000_native_localization';
|
||||
|
||||
export const migrations = [
|
||||
{
|
||||
@@ -18,4 +19,9 @@ export const migrations = [
|
||||
down: migration_20260225_003500_add_pages_collection.down,
|
||||
name: '20260225_003500_add_pages_collection',
|
||||
},
|
||||
{
|
||||
up: migration_20260225_175000_native_localization.up,
|
||||
down: migration_20260225_175000_native_localization.down,
|
||||
name: '20260225_175000_native_localization',
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user