1- import Ajv from 'ajv' ;
1+ import Ajv , { ValidateFunction } from 'ajv' ;
22import { SchemaMigration } from '../types/SchemaMigration' ;
33import { SchemaType } from '../types/SchemaType' ;
44import { last } from '../helpers/ArrayHelper' ;
5-
6- enum ErrorCodes {
7- NoMigrations ,
8- NoZeroMigration ,
9- IncorrectMigrationsOrder ,
10- }
5+ import MigrationErrorCodes from '../types/MigrationErrorCodes' ;
116
127export default class MigrationRunner {
138 private schemaMigrations : SchemaMigration [ ] = [ ] ;
149 private ajv : Ajv ;
15- private genErrorMsg = ( error : ErrorCodes | undefined , message : string ) =>
16- `[MigrationRunner] ${ error ?? - 1 } ${ message } ` ;
10+ private genErrorMsg = (
11+ error : MigrationErrorCodes | undefined ,
12+ message : string
13+ ) => `[MigrationRunner] [error=${ error ?? - 1 } ] ${ message } ` ;
14+ private genValidationErrors = (
15+ validate : ValidateFunction < unknown > ,
16+ toVersion : number
17+ ) =>
18+ this . genErrorMsg (
19+ MigrationErrorCodes . ValidationFailed ,
20+ `Migration to version=${ toVersion } . Schema validation error. Found next errors:\n${ validate . errors
21+ ?. map (
22+ ( e ) => `"${ e . instancePath ? e . instancePath : '/' } ": "${ e . message } "`
23+ )
24+ ?. join ( '\n' ) } `
25+ ) ;
1726
1827 constructor ( schemaMigrations : SchemaMigration [ ] ) {
1928 const schemaMigrationsSorted = schemaMigrations . slice ( ) ;
@@ -22,15 +31,16 @@ export default class MigrationRunner {
2231 if ( ! schemaMigrationsSorted . length ) {
2332 throw new Error (
2433 this . genErrorMsg (
25- ErrorCodes . NoMigrations ,
26- ' schemaMigrations can` t be empty'
34+ MigrationErrorCodes . NoMigrations ,
35+ ` schemaMigrations can' t be empty`
2736 )
2837 ) ;
2938 }
3039
3140 if ( ! schemaMigrationsSorted . find ( ( i ) => i . version === 0 ) ) {
3241 throw new Error (
3342 this . genErrorMsg (
43+ MigrationErrorCodes . NoZeroMigration ,
3444 'schemaMigrations should have migration for `version=0`'
3545 )
3646 ) ;
@@ -41,7 +51,10 @@ export default class MigrationRunner {
4151 ) ;
4252 if ( ! hasAllVersions ) {
4353 throw new Error (
44- this . genErrorMsg ( 'Each version should go one after the other' )
54+ this . genErrorMsg (
55+ MigrationErrorCodes . IncorrectMigrationsOrder ,
56+ 'Each version should go one after the other'
57+ )
4558 ) ;
4659 }
4760
@@ -54,44 +67,45 @@ export default class MigrationRunner {
5467 const lastVersion = last ( this . schemaMigrations ) ?. version ;
5568
5669 if ( lastVersion === undefined ) {
57- throw new Error ( 'There are no migrations' ) ;
70+ throw new Error (
71+ this . genErrorMsg (
72+ MigrationErrorCodes . NoMigrations ,
73+ 'There are no migrations'
74+ )
75+ ) ;
5876 }
5977
60- const firstMigration = this . schemaMigrations . find ( ( i ) => i . version === 0 ) ;
78+ const zeroVersion = 0 ;
79+ const firstMigration = this . schemaMigrations . find (
80+ ( i ) => i . version === zeroVersion
81+ ) ;
6182 if ( ! firstMigration ) {
6283 throw new Error ( ) ;
6384 }
85+
6486 const validate = this . ajv . compile ( firstMigration . schema ) ;
6587 const validateResult = validate ( newData ) ;
6688 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- ) ;
89+ throw new Error ( this . genValidationErrors ( validate , zeroVersion ) ) ;
7790 }
7891
79- let nextVersion =
80- newData . __version !== undefined ? newData . __version + 1 : 1 ;
92+ let fromVersion = newData . __version ;
93+ let toVersion = fromVersion !== undefined ? fromVersion + 1 : 1 ;
8194
8295 while ( true ) {
83- if ( nextVersion > lastVersion ) {
96+ if ( toVersion > lastVersion ) {
8497 return newData ;
8598 }
8699
87100 const migration = this . schemaMigrations . find (
88- ( m ) => m . version === nextVersion
101+ ( m ) => m . version === toVersion
89102 ) ;
90103
91104 if ( ! migration ) {
92105 throw new Error (
93106 this . genErrorMsg (
94- `Migration from ${ newData . __version } to ${ nextVersion } not found`
107+ MigrationErrorCodes . MigrationNotFound ,
108+ `Migration from ${ fromVersion } to ${ toVersion } not found`
95109 )
96110 ) ;
97111 }
@@ -107,19 +121,13 @@ export default class MigrationRunner {
107121 }
108122
109123 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- ) ;
124+ const validateResult = validate ( nextData ) ;
125+ if ( ! validateResult ) {
126+ throw new Error ( this . genValidationErrors ( validate , toVersion ) ) ;
119127 }
120128
121129 newData = nextData ;
122- nextVersion = nextData . __version + 1 ;
130+ toVersion = nextData . __version + 1 ;
123131 }
124132 }
125133 }
0 commit comments