Skip to content

Commit

Permalink
chore: add document-id migration
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandrebodin committed Feb 15, 2024
1 parent c0d411a commit 79d39f9
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/core/database/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"watch": "pack-up watch"
},
"dependencies": {
"@paralleldrive/cuid2": "2.2.2",
"@strapi/utils": "4.20.0",
"date-fns": "2.30.0",
"debug": "4.3.4",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { createId } from '@paralleldrive/cuid2';
import type { Knex } from 'knex';

import { Relation } from '../../types';
import type { Migration } from '../common';
import type { Database } from '../..';
import type { Meta } from '../../metadata';

const QUERIES = {
postgres: `
SELECT :tableName:.id as id, string_agg(DISTINCT :inverseJoinColumn:, ',') as otherIds
FROM :tableName:
LEFT JOIN :joinTableName: ON :tableName:.id = :joinTableName:.:joinColumn:
WHERE document_id IS NULL
GROUP BY :joinColumn:
LIMIT 1;
`,
mysql: `
SELECT :tableName:.id as id, group_concat(DISTINCT :inverseJoinColumn:) as otherIds
FROM :tableName:
LEFT JOIN :joinTableName: ON :tableName:.id = :joinTableName:.:joinColumn:
WHERE document_id IS NULL
GROUP BY :joinColumn:
LIMIT 1;
`,
sqlite: `
SELECT :tableName:.id as id, group_concat(DISTINCT :inverseJoinColumn:) as otherIds
FROM :tableName:
LEFT JOIN :joinTableName: ON :tableName:.id = :joinTableName:.:joinColumn:
WHERE document_id IS NULL
GROUP BY :joinColumn:
LIMIT 1;
`,
};

const getNextIdsToCreateDocumentId = async (
db: Database,
knex: Knex,
{
joinColumn,
inverseJoinColumn,
tableName,
joinTableName,
}: {
joinColumn: string;
inverseJoinColumn: string;
tableName: string;
joinTableName: string;
}
): Promise<number[]> => {
const res = await knex.raw(QUERIES[db.dialect.client as keyof typeof QUERIES], {
joinColumn,
inverseJoinColumn,
tableName,
joinTableName,
});

if (res.length > 0) {
const row = res[0];
const otherIds = row.otherIds
? row.otherIds.split(',').map((v: string) => parseInt(v, 10))
: [];

return [row.id, ...otherIds];
}

return [];
};

// Migrate document ids for tables that have localizations
const migrateDocumentIdsWithLocalizations = async (db: Database, knex: Knex, meta: Meta) => {
const joinColumn = `${meta.singularName.toLowerCase()}_id`;
const inverseJoinColumn = `inv_${meta.singularName.toLowerCase()}_id`;

let ids: number[];

do {
ids = await getNextIdsToCreateDocumentId(db, knex, {
joinColumn,
inverseJoinColumn,
tableName: meta.tableName,
joinTableName: `${meta.tableName}_localizations_links`,
});

if (ids.length > 0) {
await knex(meta.tableName).update({ document_id: createId() }).whereIn('id', ids);
}
} while (ids.length > 0);
};

// Migrate document ids for tables that don't have localizations
const migrationDocumentIds = async (db: Database, knex: Knex, meta: Meta) => {
let res;
do {
res = await knex.select('id').from(meta.tableName).whereNull('document_id').limit(1).first();

if (res) {
await knex(meta.tableName).update({ document_id: createId() }).whereIn('id', res.id);
}
} while (res !== null);
};

const createDocumentIdColumn = async (knex: Knex, tableName: string) => {
await knex.schema.alterTable(tableName, (table) => {
table.string('document_id');
});
};

const hasLocalizationsJoinTable = async (knex: Knex, tableName: string) => {
return knex.schema.hasTable(`${tableName}_localizations_links`);
};

export const createdDocumentId: Migration = {
name: 'created-document-id',
async up(knex, db) {
// do sth
for (const meta of db.metadata.values()) {
if ('documentId' in meta.attributes) {
// add column if doesn't exist
const hasDocumentIdColumn = await knex.schema.hasColumn(meta.tableName, 'document_id');

if (hasDocumentIdColumn) {
continue;
}

await createDocumentIdColumn(knex, meta.tableName);

if (await hasLocalizationsJoinTable(knex, meta.tableName)) {
await migrateDocumentIdsWithLocalizations(db, knex, meta);
} else {
await migrationDocumentIds(db, knex, meta);
}
}
}
},
async down() {
throw new Error('not implemented');
},
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Migration } from '../common';
import { createdDocumentId } from './document-id';

/**
* List of all the internal migrations. The array order will be the order in which they are executed.
Expand All @@ -9,4 +10,4 @@ import type { Migration } from '../common';
* async down(knex: Knex, db: Database) {},
* },
*/
export const internalMigrations: Migration[] = [];
export const internalMigrations: Migration[] = [createdDocumentId];
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9480,6 +9480,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@strapi/database@workspace:packages/core/database"
dependencies:
"@paralleldrive/cuid2": "npm:2.2.2"
"@strapi/pack-up": "npm:4.20.0"
"@strapi/utils": "npm:4.20.0"
date-fns: "npm:2.30.0"
Expand Down

0 comments on commit 79d39f9

Please sign in to comment.