fix: skip orphan links on import and transfer

* fix: show warning on foreign key constraint error
* fix: remove todo
* fix: improve error handling
* fix: typo
* fix: uncomment necessary code
* fix: move error message check to its corresponding function
* fix: move error message check to its corresponding function
* fix: add the onwarning function to the import command
* fix: add nested transactions to links transfer
This commit is contained in:
Christian 2024-01-15 16:15:43 +01:00 committed by GitHub
parent 37dd1e3ff2
commit 6cfcadfee1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 7 deletions

View File

@ -1,6 +1,7 @@
import type { LoadedStrapi } from '@strapi/types';
import { isObject } from 'lodash/fp';
import chalk from 'chalk';
import {
buildTransferTable,
DEFAULT_IGNORED_CONTENT_TYPES,
@ -104,6 +105,7 @@ export default async (opts: CmdOptions) => {
};
const destination = createLocalStrapiDestinationProvider(destinationOptions);
destination.onWarning = (message) => console.warn(`\n${chalk.yellow('warn')}: ${message}`);
const engine = createTransferEngine(source, destination, engineOptions);

View File

@ -45,6 +45,8 @@ class LocalStrapiDestinationProvider implements IDestinationProvider {
uploadsBackupDirectoryName: string;
onWarning?: ((message: string) => void) | undefined;
/**
* The entities mapper is used to map old entities to their new IDs
*/
@ -413,7 +415,7 @@ class LocalStrapiDestinationProvider implements IDestinationProvider {
const mapID = (uid: string, id: number): number | undefined => this.#entitiesMapper[uid]?.[id];
if (strategy === 'restore') {
return restore.createLinksWriteStream(mapID, this.strapi, this.transaction);
return restore.createLinksWriteStream(mapID, this.strapi, this.transaction, this.onWarning);
}
throw new ProviderValidationError(`Invalid strategy ${strategy}`, {

View File

@ -4,10 +4,31 @@ import { ProviderTransferError } from '../../../../../errors/providers';
import { ILink, Transaction } from '../../../../../../types';
import { createLinkQuery } from '../../../../queries/link';
interface ErrorWithCode extends Error {
code: string;
}
const isErrorWithCode = (error: any): error is ErrorWithCode => {
return error && typeof error.code === 'string';
};
const isForeignKeyConstraintError = (e: Error) => {
const MYSQL_FK_ERROR_CODES = ['1452', '1557', '1216', '1217', '1451'];
const POSTGRES_FK_ERROR_CODE = '23503';
const SQLITE_FK_ERROR_CODE = 'SQLITE_CONSTRAINT_FOREIGNKEY';
if (isErrorWithCode(e) && e.code) {
return [SQLITE_FK_ERROR_CODE, POSTGRES_FK_ERROR_CODE, ...MYSQL_FK_ERROR_CODES].includes(e.code);
}
return e.message.toLowerCase().includes('foreign key constraint');
};
export const createLinksWriteStream = (
mapID: (uid: string, id: number) => number | undefined,
strapi: LoadedStrapi,
transaction?: Transaction
transaction?: Transaction,
onWarning?: (message: string) => void
) => {
return new Writable({
objectMode: true,
@ -16,14 +37,23 @@ export const createLinksWriteStream = (
const { left, right } = link;
const query = createLinkQuery(strapi, trx);
const originalLeftRef = left.ref;
const originalRightRef = right.ref;
// Map IDs if needed
left.ref = mapID(left.type, left.ref) ?? left.ref;
right.ref = mapID(right.type, right.ref) ?? right.ref;
left.ref = mapID(left.type, originalLeftRef) ?? originalLeftRef;
right.ref = mapID(right.type, originalRightRef) ?? originalRightRef;
try {
await query().insert(link);
} catch (e) {
if (e instanceof Error) {
if (isForeignKeyConstraintError(e)) {
onWarning?.(
`Skipping link ${left.type}:${originalLeftRef} -> ${right.type}:${originalRightRef} due to a foreign key constraint.`
);
return callback(null);
}
return callback(e);
}

View File

@ -264,12 +264,12 @@ export const createLinkQuery = (strapi: LoadedStrapi, trx?: Knex.Transaction) =>
}
assignOrderColumns();
const qb = connection.insert(payload).into(addSchema(joinTable.name));
if (trx) {
qb.transacting(trx);
await trx.transaction(async (nestedTrx) => {
await qb.transacting(nestedTrx);
});
}
await qb;
}
};

View File

@ -452,6 +452,11 @@ export const createPushController = handlerControllerFactory<Partial<PushHandler
getStrapi: () => strapi as LoadedStrapi,
});
this.provider.onWarning = (message) => {
// TODO send a warning message to the client
strapi.log.warn(message);
};
return { transferID: this.transferID };
},

View File

@ -48,6 +48,7 @@ export interface IDestinationProvider extends IProvider {
rollback?<T extends Error = Error>(e: T): MaybePromise<void>;
setMetadata?(target: ProviderType, metadata: IMetadata): IDestinationProvider;
onWarning?: (message: string) => void;
createEntitiesWriteStream?(): MaybePromise<Writable>;
createLinksWriteStream?(): MaybePromise<Writable>;