mirror of
https://github.com/strapi/strapi.git
synced 2025-12-24 21:54:24 +00:00
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:
parent
37dd1e3ff2
commit
6cfcadfee1
@ -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);
|
||||
|
||||
|
||||
@ -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}`, {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -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 };
|
||||
},
|
||||
|
||||
|
||||
@ -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>;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user