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

Commit b64dc78

Browse files
committed
WIP
1 parent 8914df9 commit b64dc78

File tree

2 files changed

+80
-16
lines changed

2 files changed

+80
-16
lines changed

src/base/MigrationRunner.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,35 @@ describe('MigrationRunner tests', () => {
9696
const resultData = mr.runMigration(dataV0);
9797
expect(resultData).toStrictEqual(expectedData);
9898
});
99+
100+
test('Test when there is schema validation error', () => {
101+
type TypeV0 = { data: number; text: string; prop: { test: 1 } };
102+
const schemaV0: JSONSchemaType<TypeV0> = {
103+
type: 'object',
104+
properties: {
105+
data: { type: 'number' },
106+
text: { type: 'string' },
107+
prop: {
108+
type: 'object',
109+
properties: { test: { type: 'number' } },
110+
required: ['test'],
111+
},
112+
},
113+
required: ['data', 'text'],
114+
};
115+
const migrations: SchemaMigration[] = [{ version: 0, schema: schemaV0 }];
116+
117+
const dataV0 = { fakeData: 77, text: 123, prop: { testFail: 1 } };
118+
const mr = new MigrationRunner(migrations);
119+
120+
expect(() => mr.runMigration(dataV0)).toThrow(
121+
[
122+
'[MigrationRunner] Schema validation error "version=0". Found next errors:',
123+
'"/": "must have required property \'data\'"',
124+
'"/text": "must be string"',
125+
'"/prop": "must have required property \'test\'"',
126+
].join('\n')
127+
);
128+
});
99129
});
100130
});

src/base/MigrationRunner.ts

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
1+
import Ajv from 'ajv';
12
import { SchemaMigration } from '../types/SchemaMigration';
23
import { SchemaType } from '../types/SchemaType';
34
import { last } from '../helpers/ArrayHelper';
45

6+
enum ErrorCodes {
7+
NoMigrations,
8+
NoZeroMigration,
9+
IncorrectMigrationsOrder,
10+
}
11+
512
export default class MigrationRunner {
613
private schemaMigrations: SchemaMigration[] = [];
7-
private genErrorMsg = (message: string) => `[MigrationRunner] ${message}`;
14+
private ajv: Ajv;
15+
private genErrorMsg = (error: ErrorCodes | undefined, message: string) =>
16+
`[MigrationRunner] ${error ?? -1} ${message}`;
817

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

1322
if (!schemaMigrationsSorted.length) {
14-
throw new Error(this.genErrorMsg('schemaMigrations can`t be empty'));
23+
throw new Error(
24+
this.genErrorMsg(
25+
ErrorCodes.NoMigrations,
26+
'schemaMigrations can`t be empty'
27+
)
28+
);
1529
}
1630

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

3448
this.schemaMigrations = schemaMigrationsSorted;
49+
this.ajv = new Ajv({ allErrors: true });
3550
}
3651

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

45-
// if (!('__version' in data)) {
46-
// const migration = this.schemaMigrations.find((i) => i.version === 1);
47-
// if (!migration) {
48-
// throw new Error();
49-
// }
50-
// newData = migration.migration?.(data);
51-
// } else {
52-
// newData = data;
53-
// }
54-
55-
// if (newData === undefined || newData.__version === undefined) {
56-
// throw new Error();
57-
// }
60+
const firstMigration = this.schemaMigrations.find((i) => i.version === 0);
61+
if (!firstMigration) {
62+
throw new Error();
63+
}
64+
const validate = this.ajv.compile(firstMigration.schema);
65+
const validateResult = validate(newData);
66+
if (!validateResult) {
67+
throw new Error(
68+
this.genErrorMsg(
69+
`Schema validation error "version=0". Found next errors:\n${validate.errors
70+
?.map(
71+
(e) =>
72+
`"${e.instancePath ? e.instancePath : '/'}": "${e.message}"`
73+
)
74+
?.join('\n')}`
75+
)
76+
);
77+
}
5878

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

7191
if (!migration) {
7292
throw new Error(
73-
`Migration from ${newData.__version} to ${nextVersion} not found`
93+
this.genErrorMsg(
94+
`Migration from ${newData.__version} to ${nextVersion} not found`
95+
)
7496
);
7597
}
7698

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

109+
const validate = this.ajv.compile(migration.schema);
110+
const validateObj = validate(nextData);
111+
if (!validateObj) {
112+
throw new Error(
113+
this.genErrorMsg(
114+
`Schema validation error. version=${nextVersion}: ${validate.errors?.join(
115+
', '
116+
)}`
117+
)
118+
);
119+
}
120+
87121
newData = nextData;
88122
nextVersion = nextData.__version + 1;
89123
}

0 commit comments

Comments
 (0)