2017-01-12 10:17:05 +01:00
const asyncQ = require ( 'async-q' )
class Migrator {
constructor ( opts = { } ) {
let migrations = opts . migrations || [ ]
this . migrations = migrations . sort ( ( a , b ) => a . version - b . version )
let lastMigration = this . migrations . slice ( - 1 ) [ 0 ]
// 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-01-12 11:24:33 +01:00
migrateData ( versionedData = this . generateInitialState ( ) ) {
2017-01-12 10:17:05 +01:00
let remaining = this . migrations . filter ( migrationIsPending )
return (
2017-02-03 23:00:30 +01:00
asyncQ . eachSeries ( remaining , ( migration ) => this . runMigration ( versionedData , migration ) )
2017-01-12 11:24:33 +01:00
. then ( ( ) => versionedData )
2017-01-12 10:17:05 +01:00
)
// migration is "pending" if hit has a higher
// version number than currentVersion
function migrationIsPending ( migration ) {
2017-01-12 11:24:33 +01:00
return migration . version > versionedData . meta . version
}
}
2017-02-03 23:00:30 +01:00
runMigration ( versionedData , migration ) {
return (
migration . migrate ( versionedData )
. then ( ( versionedData ) => {
if ( ! versionedData . data ) return Promise . reject ( new Error ( 'Migrator - Migration returned empty data' ) )
if ( migration . version !== undefined && versionedData . meta . version !== migration . version ) return Promise . reject ( new Error ( 'Migrator - Migration did not update version number correctly' ) )
return Promise . resolve ( versionedData )
} )
)
}
2017-01-12 11:24:33 +01:00
generateInitialState ( initState ) {
return {
meta : {
version : this . defaultVersion ,
} ,
data : initState ,
2017-01-12 10:17:05 +01:00
}
}
}
module . exports = Migrator