Skip to content
This repository has been archived by the owner on Dec 26, 2022. It is now read-only.

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Yadro committed Jan 2, 2022
1 parent 8914df9 commit b64dc78
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 16 deletions.
30 changes: 30 additions & 0 deletions src/base/MigrationRunner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,35 @@ describe('MigrationRunner tests', () => {
const resultData = mr.runMigration(dataV0);
expect(resultData).toStrictEqual(expectedData);
});

test('Test when there is schema validation error', () => {
type TypeV0 = { data: number; text: string; prop: { test: 1 } };
const schemaV0: JSONSchemaType<TypeV0> = {
type: 'object',
properties: {
data: { type: 'number' },
text: { type: 'string' },
prop: {
type: 'object',
properties: { test: { type: 'number' } },
required: ['test'],
},
},
required: ['data', 'text'],
};
const migrations: SchemaMigration[] = [{ version: 0, schema: schemaV0 }];

const dataV0 = { fakeData: 77, text: 123, prop: { testFail: 1 } };
const mr = new MigrationRunner(migrations);

expect(() => mr.runMigration(dataV0)).toThrow(
[
'[MigrationRunner] Schema validation error "version=0". Found next errors:',
'"/": "must have required property \'data\'"',
'"/text": "must be string"',
'"/prop": "must have required property \'test\'"',
].join('\n')
);
});
});
});
66 changes: 50 additions & 16 deletions src/base/MigrationRunner.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
import Ajv from 'ajv';
import { SchemaMigration } from '../types/SchemaMigration';
import { SchemaType } from '../types/SchemaType';
import { last } from '../helpers/ArrayHelper';

enum ErrorCodes {
NoMigrations,
NoZeroMigration,
IncorrectMigrationsOrder,
}

export default class MigrationRunner {
private schemaMigrations: SchemaMigration[] = [];
private genErrorMsg = (message: string) => `[MigrationRunner] ${message}`;
private ajv: Ajv;
private genErrorMsg = (error: ErrorCodes | undefined, message: string) =>
`[MigrationRunner] ${error ?? -1} ${message}`;

constructor(schemaMigrations: SchemaMigration[]) {
const schemaMigrationsSorted = schemaMigrations.slice();
schemaMigrationsSorted.sort((a, b) => a.version - b.version);

if (!schemaMigrationsSorted.length) {
throw new Error(this.genErrorMsg('schemaMigrations can`t be empty'));
throw new Error(
this.genErrorMsg(
ErrorCodes.NoMigrations,
'schemaMigrations can`t be empty'
)
);
}

if (!schemaMigrationsSorted.find((i) => i.version === 0)) {
Expand All @@ -32,6 +46,7 @@ export default class MigrationRunner {
}

this.schemaMigrations = schemaMigrationsSorted;
this.ajv = new Ajv({ allErrors: true });
}

runMigration<T extends SchemaType>(data: T) {
Expand All @@ -42,19 +57,24 @@ export default class MigrationRunner {
throw new Error('There are no migrations');
}

// if (!('__version' in data)) {
// const migration = this.schemaMigrations.find((i) => i.version === 1);
// if (!migration) {
// throw new Error();
// }
// newData = migration.migration?.(data);
// } else {
// newData = data;
// }

// if (newData === undefined || newData.__version === undefined) {
// throw new Error();
// }
const firstMigration = this.schemaMigrations.find((i) => i.version === 0);
if (!firstMigration) {
throw new Error();
}
const validate = this.ajv.compile(firstMigration.schema);
const validateResult = validate(newData);
if (!validateResult) {
throw new Error(
this.genErrorMsg(
`Schema validation error "version=0". Found next errors:\n${validate.errors
?.map(
(e) =>
`"${e.instancePath ? e.instancePath : '/'}": "${e.message}"`
)
?.join('\n')}`
)
);
}

let nextVersion =
newData.__version !== undefined ? newData.__version + 1 : 1;
Expand All @@ -70,7 +90,9 @@ export default class MigrationRunner {

if (!migration) {
throw new Error(
`Migration from ${newData.__version} to ${nextVersion} not found`
this.genErrorMsg(
`Migration from ${newData.__version} to ${nextVersion} not found`
)
);
}

Expand All @@ -84,6 +106,18 @@ export default class MigrationRunner {
throw new Error();
}

const validate = this.ajv.compile(migration.schema);
const validateObj = validate(nextData);
if (!validateObj) {
throw new Error(
this.genErrorMsg(
`Schema validation error. version=${nextVersion}: ${validate.errors?.join(
', '
)}`
)
);
}

newData = nextData;
nextVersion = nextData.__version + 1;
}
Expand Down

0 comments on commit b64dc78

Please sign in to comment.