Skip to content

Commit e26ed7b

Browse files
committed
docs(core): Show a concrete example migration for deduplicateTranslations
1 parent 9c891ee commit e26ed7b

1 file changed

Lines changed: 41 additions & 7 deletions

File tree

packages/core/src/migration-utils/translation-deduplication.ts

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,62 @@ import { QueryRunner } from 'typeorm';
1313
* existing database that already contains such duplicates without first removing them.
1414
*
1515
* Call this from your migration's `up()` method **before** the unique constraint on the
16-
* translation table is created.
16+
* translation table is created, once per affected table. `vendure migrate generate` will
17+
* generate the DDL that creates the constraints; you only need to add the
18+
* `deduplicateTranslations` calls ahead of it. On Postgres this looks like (constraint names
19+
* are deterministic, so `vendure migrate generate` will produce these exact names):
1720
*
1821
* ```ts
1922
* import { MigrationInterface, QueryRunner } from 'typeorm';
2023
* import { deduplicateTranslations } from '\@vendure/core';
2124
*
22-
* export class AddTranslationUniqueConstraint1234567890 implements MigrationInterface {
25+
* export class AddTranslationUniqueConstraints1234567890 implements MigrationInterface {
2326
* public async up(queryRunner: QueryRunner): Promise<any> {
24-
* // --- Remove any pre-existing duplicate rows ---
27+
* // --- Remove any pre-existing duplicate rows, one call per translation table ---
2528
* await deduplicateTranslations(queryRunner, 'product_translation');
29+
* await deduplicateTranslations(queryRunner, 'product_variant_translation');
30+
* await deduplicateTranslations(queryRunner, 'product_option_translation');
31+
* await deduplicateTranslations(queryRunner, 'product_option_group_translation');
32+
* await deduplicateTranslations(queryRunner, 'collection_translation');
33+
* await deduplicateTranslations(queryRunner, 'facet_translation');
34+
* await deduplicateTranslations(queryRunner, 'facet_value_translation');
35+
* await deduplicateTranslations(queryRunner, 'asset_translation');
36+
* await deduplicateTranslations(queryRunner, 'api_key_translation');
37+
* await deduplicateTranslations(queryRunner, 'payment_method_translation');
38+
* await deduplicateTranslations(queryRunner, 'promotion_translation');
39+
* await deduplicateTranslations(queryRunner, 'region_translation');
40+
* await deduplicateTranslations(queryRunner, 'shipping_method_translation');
2641
*
27-
* // --- Auto-generated DDL continues ---
28-
* // (Create the unique index/constraint)
29-
* // ...
42+
* // --- Auto-generated DDL continues (Postgres) ---
43+
* await queryRunner.query(`ALTER TABLE "product_translation" ADD CONSTRAINT "UQ_dcc35f0d2b8d422634e878b813c" UNIQUE ("languageCode", "baseId")`);
44+
* await queryRunner.query(`ALTER TABLE "product_variant_translation" ADD CONSTRAINT "UQ_33042b9e7ea5dcf5ec09a5a4130" UNIQUE ("languageCode", "baseId")`);
45+
* await queryRunner.query(`ALTER TABLE "product_option_translation" ADD CONSTRAINT "UQ_bd426ff614344b6759d327fe58c" UNIQUE ("languageCode", "baseId")`);
46+
* await queryRunner.query(`ALTER TABLE "product_option_group_translation" ADD CONSTRAINT "UQ_bb3992fff02944c061363d9d015" UNIQUE ("languageCode", "baseId")`);
47+
* await queryRunner.query(`ALTER TABLE "collection_translation" ADD CONSTRAINT "UQ_858c112351f7714960a2dfcff91" UNIQUE ("languageCode", "baseId")`);
48+
* await queryRunner.query(`ALTER TABLE "facet_translation" ADD CONSTRAINT "UQ_c9174d39ac643e5f14b73ad6cb5" UNIQUE ("languageCode", "baseId")`);
49+
* await queryRunner.query(`ALTER TABLE "facet_value_translation" ADD CONSTRAINT "UQ_084f223aa69bcd7683e727e3130" UNIQUE ("languageCode", "baseId")`);
50+
* await queryRunner.query(`ALTER TABLE "asset_translation" ADD CONSTRAINT "UQ_0dad4e3837a685fea5062da3d96" UNIQUE ("languageCode", "baseId")`);
51+
* await queryRunner.query(`ALTER TABLE "api_key_translation" ADD CONSTRAINT "UQ_0a5a4e1c3fb9547a20f34ef2240" UNIQUE ("languageCode", "baseId")`);
52+
* await queryRunner.query(`ALTER TABLE "payment_method_translation" ADD CONSTRAINT "UQ_5ee20e71a427f7d86e921083777" UNIQUE ("languageCode", "baseId")`);
53+
* await queryRunner.query(`ALTER TABLE "promotion_translation" ADD CONSTRAINT "UQ_0d74bcbf35d65e5d7c2a7947ae1" UNIQUE ("languageCode", "baseId")`);
54+
* await queryRunner.query(`ALTER TABLE "region_translation" ADD CONSTRAINT "UQ_fc1a4a3618bcd16cc50dd50dfeb" UNIQUE ("languageCode", "baseId")`);
55+
* await queryRunner.query(`ALTER TABLE "shipping_method_translation" ADD CONSTRAINT "UQ_6f2a231486b87fd9d337bf9d60b" UNIQUE ("languageCode", "baseId")`);
3056
* }
3157
*
3258
* public async down(queryRunner: QueryRunner): Promise<any> {
33-
* // Auto-generated reverse DDL
59+
* // Auto-generated reverse DDL — drops the constraints added above.
60+
* // ...
3461
* }
3562
* }
3663
* ```
3764
*
65+
* On MySQL/MariaDB, unique constraints are implemented as unique indexes, so the generated DDL
66+
* instead looks like `` CREATE UNIQUE INDEX `UQ_dcc35f0d2b8d422634e878b813c` ON `product_translation`
67+
* (`languageCode`, `baseId`) `` (same deterministic names as above). On SQLite, adding a unique
68+
* constraint requires TypeORM to recreate the whole table, so the generated migration will
69+
* contain a much longer sequence of statements for each table — call `deduplicateTranslations`
70+
* before that generated block in the same way.
71+
*
3872
* @docsCategory migration
3973
*/
4074
export async function deduplicateTranslations(

0 commit comments

Comments
 (0)