add middleware for schema diff handling

This commit is contained in:
Ben Irvin 2023-05-07 15:48:14 +02:00
parent b012dc6e78
commit 9cbdad0a70
2 changed files with 73 additions and 10 deletions

View File

@ -27,7 +27,11 @@ import type { Diff } from '../utils/json';
import { compareSchemas, validateProvider } from './validation';
import { filter, map } from '../utils/stream';
import { TransferEngineError, TransferEngineValidationError } from './errors';
import {
TransferEngineError,
TransferEngineInitializationError,
TransferEngineValidationError,
} from './errors';
import {
createDiagnosticReporter,
IDiagnosticReporter,
@ -76,6 +80,27 @@ export const DEFAULT_SCHEMA_STRATEGY = 'strict';
type SchemaMap = Record<string, Schema>;
type SchemaDiffHandlerContext = {
diffs: Record<string, Diff[]>;
source: ISourceProvider;
destination: IDestinationProvider;
};
type SchemaDiffHandler = (data: SchemaDiffHandlerContext, next: SchemaDiffHandler) => void;
// TODO: clean this up
type Next = (context: any) => void | Promise<void>;
type Middleware<T> = (context: T, next: Next) => Promise<void> | void;
async function runMiddleware<T>(context: T, middlewares: Middleware<T>[]): Promise<void> {
if (!middlewares.length) {
return;
}
const cb = middlewares[0];
await cb(context, async (newContext) => {
await runMiddleware(newContext, middlewares.slice(1));
});
}
class TransferEngine<
S extends ISourceProvider = ISourceProvider,
D extends IDestinationProvider = IDestinationProvider
@ -99,6 +124,16 @@ class TransferEngine<
diagnostics: IDiagnosticReporter;
#handlers: {
schemaDiff: SchemaDiffHandler[];
} = {
schemaDiff: [],
};
onSchemaDiff(handler: SchemaDiffHandler) {
this.#handlers?.schemaDiff?.push(handler);
}
// Save the currently open stream so that we can access it at any time
#currentStream?: Writable;
@ -616,15 +651,24 @@ class TransferEngine<
if (error instanceof TransferEngineValidationError) {
this.#schemaDiffs = error.details?.details?.diffs as Record<string, Diff[]>;
// TODO: implement a confirmation callback to confirm or reject the error
Object.entries(this.#schemaDiffs).forEach(([uid, diffs]) => {
for (const diff of diffs) {
this.#reportWarning(`${diff.path.join('.')} for ${uid}`, 'Schema Integrity Check');
// await new Promise((resolve, reject) => {
// this.confirm('Continue with diffs ?', resolve, reject);
// });
}
});
const context = {
diffs: this.#schemaDiffs,
source: this.sourceProvider,
destination: this.destinationProvider,
};
await runMiddleware(context, this.#handlers.schemaDiff);
if (Object.keys(context.diffs).length) {
console.log('DIFFS REMAINING', context.diffs);
Object.entries(context.diffs).forEach(([uid, diffs]) => {
for (const diff of diffs) {
this.#reportWarning(`${diff.path.join('.')} for ${uid}`, 'Schema Integrity Check');
this.#panic(
new TransferEngineInitializationError('Unresolved differences in schema')
);
}
});
}
return;
}
throw error;

View File

@ -11,6 +11,7 @@ const {
} = require('@strapi/data-transfer');
const { isObject } = require('lodash/fp');
const inquirer = require('inquirer');
const {
buildTransferTable,
@ -111,6 +112,24 @@ module.exports = async (opts) => {
const { updateLoader } = loadersFactory();
engine.onSchemaDiff(async (context, next) => {
// TODO: work with "force"
// TODO: yes/no prompt should look like commander prompt
const answers = await inquirer.prompt([
{
type: 'confirm',
message: 'Are you sure you want to continue?',
name: 'confirmSchemaDiff',
},
]);
if (answers.confirmSchemaDiff) {
// diffs have been resolved by user
context.diffs = [];
}
return next(context);
});
progress.on(`stage::start`, ({ stage, data }) => {
updateLoader(stage, data).start();
});