126 lines
3.9 KiB
JavaScript
Raw Normal View History

2021-02-18 18:42:28 +01:00
'use strict';
2021-03-02 17:09:35 +01:00
const { shouldBeProcesseed, getUpdatesInfo } = require('./utils');
2021-02-18 18:42:28 +01:00
2021-02-25 17:40:14 +01:00
const BATCH_SIZE = 1000;
2021-03-02 16:42:17 +01:00
const TMP_TABLE_NAME = '__tmp__i18n_field_migration';
const batchInsertInTmpTable = async (updatesInfo, trx) => {
const tmpEntries = [];
updatesInfo.forEach(({ entriesIdsToUpdate, attributesValues }) => {
entriesIdsToUpdate.forEach(id => {
tmpEntries.push({ id, ...attributesValues });
});
});
await trx.batchInsert(TMP_TABLE_NAME, tmpEntries, 100);
2021-03-01 11:26:44 +01:00
};
2021-03-02 16:42:17 +01:00
const batchUpdate = async (updatesInfo, trx, model) => {
const promises = updatesInfo.map(({ entriesIdsToUpdate, attributesValues }) =>
trx
.from(model.collectionName)
.update(attributesValues)
.whereIn('id', entriesIdsToUpdate)
);
await Promise.all(promises);
};
2021-03-01 11:26:44 +01:00
2021-03-02 16:42:17 +01:00
const updateFromTmpTable = async ({ model, trx, attributesToMigrate }) => {
const collectionName = model.collectionName;
let bindings = [];
if (model.client === 'pg') {
const substitutes = attributesToMigrate.map(() => '?? = ??.??').join(',');
bindings.push(collectionName);
attributesToMigrate.forEach(attr => bindings.push(attr, TMP_TABLE_NAME, attr));
bindings.push(TMP_TABLE_NAME, collectionName, TMP_TABLE_NAME);
await trx.raw(`UPDATE ?? SET ${substitutes} FROM ?? WHERE ??.id = ??.id;`, bindings);
} else if (model.client === 'mysql') {
const substitutes = attributesToMigrate.map(() => '??.?? = ??.??').join(',');
bindings.push(collectionName, TMP_TABLE_NAME, collectionName, TMP_TABLE_NAME);
attributesToMigrate.forEach(attr => bindings.push(collectionName, attr, TMP_TABLE_NAME, attr));
await trx.raw(`UPDATE ?? JOIN ?? ON ??.id = ??.id SET ${substitutes};`, bindings);
}
};
2021-02-25 17:40:14 +01:00
2021-03-02 16:42:17 +01:00
const createTmpTable = async ({ ORM, attributesToMigrate, model }) => {
2021-02-25 17:40:14 +01:00
const columnsToCopy = ['id', ...attributesToMigrate];
await ORM.knex.schema.dropTableIfExists(TMP_TABLE_NAME);
await ORM.knex.raw(`CREATE TABLE ?? AS ??`, [
TMP_TABLE_NAME,
ORM.knex
.select(columnsToCopy)
.from(model.collectionName)
.whereRaw('?', 0),
]);
2021-03-02 16:42:17 +01:00
};
2021-02-25 17:40:14 +01:00
2021-03-02 16:42:17 +01:00
const deleteTmpTable = ({ ORM }) => ORM.knex.schema.dropTableIfExists(TMP_TABLE_NAME);
const migrateForBookshelf = async ({ ORM, model, attributesToMigrate, locales }) => {
// The migration is custom for pg and mysql for better perfomance
const isPgOrMysql = ['pg', 'mysql'].includes(model.client);
if (isPgOrMysql) {
await createTmpTable({ ORM, attributesToMigrate, model });
}
2021-02-25 17:40:14 +01:00
2021-03-02 16:42:17 +01:00
const trx = await ORM.knex.transaction();
2021-02-25 17:40:14 +01:00
try {
const processedLocaleCodes = [];
for (const locale of locales) {
let offset = 0;
2021-03-02 16:42:17 +01:00
// eslint-disable-next-line no-constant-condition
while (true) {
2021-02-25 17:40:14 +01:00
const batch = await trx
.select([...attributesToMigrate, 'locale', 'localizations'])
.from(model.collectionName)
.where('locale', locale.code)
.orderBy('id')
.offset(offset)
2021-03-01 11:26:44 +01:00
.limit(BATCH_SIZE);
2021-02-18 18:42:28 +01:00
2021-03-02 16:42:17 +01:00
offset += BATCH_SIZE;
2021-03-01 11:26:44 +01:00
// postgres automatically parses JSON, but not sqlite nor mysql
2021-02-25 17:40:14 +01:00
batch.forEach(entry => {
if (typeof entry.localizations === 'string') {
entry.localizations = JSON.parse(entry.localizations);
}
});
2021-03-01 11:26:44 +01:00
const entriesToProcess = batch.filter(shouldBeProcesseed(processedLocaleCodes));
2021-03-02 16:42:17 +01:00
const updatesInfo = getUpdatesInfo({ entriesToProcess, locale, attributesToMigrate });
2021-02-25 17:40:14 +01:00
2021-03-02 16:42:17 +01:00
if (isPgOrMysql) {
await batchInsertInTmpTable(updatesInfo, trx);
} else {
await batchUpdate(updatesInfo, trx, model);
}
2021-02-25 17:40:14 +01:00
2021-03-02 16:42:17 +01:00
if (batch.length < BATCH_SIZE) {
break;
}
2021-02-25 17:40:14 +01:00
}
processedLocaleCodes.push(locale.code);
}
2021-03-02 16:42:17 +01:00
if (isPgOrMysql) {
await updateFromTmpTable({ model, trx, attributesToMigrate });
}
2021-02-25 17:40:14 +01:00
await trx.commit();
2021-03-02 16:42:17 +01:00
if (isPgOrMysql) {
await deleteTmpTable({ ORM });
}
2021-02-25 17:40:14 +01:00
} catch (e) {
await trx.rollback();
throw e;
}
};
2021-03-02 17:09:35 +01:00
module.exports = migrateForBookshelf;