Browse Source

Merge pull request #834 from gre/migration

Add a migration system
master
Gaëtan Renaudeau 7 years ago
committed by GitHub
parent
commit
b327705a35
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/helpers/db/db.js
  2. 15
      src/migrations/README.md
  3. 59
      src/migrations/index.js
  4. 6
      src/migrations/types.js
  5. 3
      src/renderer/init.js

2
src/helpers/db/db.js

@ -7,7 +7,7 @@ import get from 'lodash/get'
import { decodeAccountsModel, encodeAccountsModel } from 'reducers/accounts'
type DBKey = 'settings' | 'accounts' | 'countervalues' | 'user'
type DBKey = 'settings' | 'accounts' | 'countervalues' | 'user' | 'migrations'
const encryptionKey = {}

15
src/migrations/README.md

@ -0,0 +1,15 @@
## Migrations system
this folder contains all the migration scripts.
Migrations works with a nonce, number we increment.
An app instance saves the nonce after running the migrations.
To know what migrations need to be performed, we simply need to run all migrations that have an index higher that this nonce and then save it.
The migration are run before the app starts and the idea is you need to perform everything on the db and maybe on the libcore with the commands.
### Add a migration
To add a migration, simply add one more item in the migrations array of index.js
If a migration throw an exception, it's considered to be a critical error and app will crash forever. so make sure you only throw if necessary (user can always Hard Reset at the end)

59
src/migrations/index.js

@ -0,0 +1,59 @@
// @flow
import logger from 'logger'
import db from 'helpers/db'
import { delay } from 'helpers/promise'
import type { Migration } from './types'
export const migrations: Migration[] = [
/*
// TODO release when libcore will fix the issue (ensure it does everyting that is needed)
{
doc: 'libcore fixed an important bug on BCH that needs a cache clear',
run: async () => {
// Clear out accounts operations because will need a full refresh
const accounts: mixed = db.get('accounts')
if (accounts && Array.isArray(accounts)) {
for (const acc of accounts) {
if (acc && typeof acc === 'object') {
acc.operations = []
acc.pendingOperations = []
}
}
db.set('accounts', accounts)
}
db.cleanCache()
// await delay(500)
},
},
*/
]
// Logic to run all the migrations based on what was not yet run:
export const runMigrations = async (): Promise<void> => {
const current = db.get('migrations')
let { nonce } = current || { nonce: migrations.length }
const outdated = migrations.length - nonce
if (!outdated) {
if (!current) {
db.set('migrations', { nonce })
}
return
}
try {
await delay(1000) // wait a bit the logger to be ready.
while (nonce < migrations.length) {
const m = migrations[nonce]
logger.log(`migration ${nonce}: ${m.doc}`)
await m.run()
nonce++
}
logger.log(`${outdated} migration(s) performed.`)
} finally {
db.set('migrations', { nonce })
}
}

6
src/migrations/types.js

@ -0,0 +1,6 @@
// @flow
export type Migration = {
doc: string,
run: () => Promise<void>,
}

3
src/renderer/init.js

@ -7,6 +7,7 @@ import { render } from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import createHistory from 'history/createHashHistory'
import moment from 'moment'
import { runMigrations } from 'migrations'
import createStore from 'renderer/createStore'
import events from 'renderer/events'
@ -42,6 +43,8 @@ async function init() {
await hardReset()
}
await runMigrations()
// Init db with defaults if needed
db.init('settings', {})

Loading…
Cancel
Save