2018-04-05 22:15:08 +02:00
const EventEmitter = require ( 'events' )
class Migrator extends EventEmitter {
2017-01-12 10:17:05 +01:00
constructor ( opts = { } ) {
2018-04-05 22:15:08 +02:00
super ( )
2017-04-27 06:05:45 +02:00
const migrations = opts . migrations || [ ]
2017-05-12 03:15:59 +02:00
// sort migrations by version
2017-01-12 10:17:05 +01:00
this . migrations = migrations . sort ( ( a , b ) => a . version - b . version )
2017-05-12 03:15:59 +02:00
// grab migration with highest version
2017-04-27 06:05:45 +02:00
const lastMigration = this . migrations . slice ( - 1 ) [ 0 ]
2017-01-12 10:17:05 +01:00
// use specified defaultVersion or highest migration version
2017-01-12 11:24:33 +01:00
this . defaultVersion = opts . defaultVersion || ( lastMigration && lastMigration . version ) || 0
2017-01-12 10:17:05 +01:00
}
// run all pending migrations on meta in place
2017-05-12 03:15:59 +02:00
async migrateData ( versionedData = this . generateInitialState ( ) ) {
2018-04-05 22:15:08 +02:00
// get all migrations that have not yet been run
2017-05-12 03:15:59 +02:00
const pendingMigrations = this . migrations . filter ( migrationIsPending )
2018-04-05 22:15:08 +02:00
// perform each migration
2017-05-28 20:18:07 +02:00
for ( const index in pendingMigrations ) {
const migration = pendingMigrations [ index ]
2018-04-05 22:15:08 +02:00
try {
// attempt migration and validate
const migratedData = await migration . migrate ( versionedData )
if ( ! migratedData . data ) throw new Error ( 'Migrator - migration returned empty data' )
if ( migratedData . version !== undefined && migratedData . meta . version !== migration . version ) throw new Error ( 'Migrator - Migration did not update version number correctly' )
// accept the migration as good
versionedData = migratedData
} catch ( err ) {
2018-04-05 22:38:34 +02:00
// rewrite error message to add context without clobbering stack
const originalErrorMessage = err . message
err . message = ` MetaMask Migration Error # ${ migration . version } : ${ originalErrorMessage } `
console . warn ( err . stack )
2018-04-05 22:15:08 +02:00
// emit error instead of throw so as to not break the run (gracefully fail)
2018-04-05 22:38:34 +02:00
this . emit ( 'error' , err )
2018-04-05 22:15:08 +02:00
// stop migrating and use state as is
return versionedData
}
2017-05-12 03:15:59 +02:00
}
2017-05-11 10:46:17 +02:00
2017-05-12 03:15:59 +02:00
return versionedData
2017-01-12 10:17:05 +01:00
2017-05-12 03:15:59 +02:00
// migration is "pending" if it has a higher
2017-01-12 10:17:05 +01:00
// version number than currentVersion
2017-04-27 06:05:45 +02:00
function migrationIsPending ( migration ) {
2017-01-12 11:24:33 +01:00
return migration . version > versionedData . meta . version
}
}
generateInitialState ( initState ) {
return {
meta : {
version : this . defaultVersion ,
} ,
data : initState ,
2017-01-12 10:17:05 +01:00
}
}
}
module . exports = Migrator