Skip to content

Instantly share code, notes, and snippets.

@antho1404
Last active September 25, 2018 07:07
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antho1404/576642a12f07f09f853a42ecf67a45f3 to your computer and use it in GitHub Desktop.
Save antho1404/576642a12f07f09f853a42ecf67a45f3 to your computer and use it in GitHub Desktop.
A script to be able to execute some data migrations with graphcool framework
const fs = require('fs')
const os = require('os')
const vm = require('vm')
const yaml = require('js-yaml')
const { paramCase } = require('change-case')
const { GraphQLClient } = require('graphql-request')
const cmd = process.argv[2]
const MIGRATION_PATH = `./db/migrations`
const isLocalTarget = target => target.startsWith('local/')
const endpoint = (target, defaultConf) => isLocalTarget(target) ? defaultConf.clusters.local.host : 'https://api.graph.cool'
const projectId = target => target.split('/')[1]
const authorization = (target, defaultConf) => isLocalTarget(target)
? defaultConf.clusters.local.clusterSecret
: defaultConf.platformToken
const migrationName = file => file.replace(/.[jt]s$/, '')
const checkMigration = async (file, client) => {
const { allMigrations } = await client.request(`{
allMigrations(first: 1, filter: { migrationName: "${migrationName(file)}" }) {
id
}
}`)
return allMigrations.length > 0
}
const migrateFile = async (filename, client) => {
const code = fs.readFileSync(`${MIGRATION_PATH}/${filename}`, 'utf8')
const sandboxedFunc = vm.runInContext(code, vm.createContext({
console,
require,
module
}))
await sandboxedFunc(client)
const { createMigration } = await client.request(`mutation {
createMigration(migrationName: "${migrationName(filename)}") {
id
migrationName
}
}`)
return createMigration
}
const migrateFiles = async (files, client) => {
for (let i = 0; i < files.length; i++) {
const file = files[i]
const migrated = await checkMigration(file, client)
if (!migrated) {
const { migrationName } = await migrateFile(file, client)
console.log(`Migrations ${migrationName} applied`)
}
}
}
const migrate = () => {
const { targets } = yaml.safeLoad(fs.readFileSync('./.graphcoolrc', 'utf8'))
const defaultConf = yaml.safeLoad(fs.readFileSync(`${os.homedir()}/.graphcoolrc`, 'utf8'))
const target = targets[process.argv[3] || 'dev']
const api = `${endpoint(target, defaultConf)}/simple/v1/${projectId(target)}`
const client = new GraphQLClient(api, { headers: { 'Authorization': `Bearer ${authorization(target, defaultConf)}` } })
console.log(`Migration in progress for ${api}`)
fs.readdir(MIGRATION_PATH, (err, files) => err
? console.error(err)
: migrateFiles(files, client)
)
}
const create = () => {
const name = process.argv[3]
if (!name) throw new Error('You should give a name to your migration')
const time = (new Date()).toISOString()
const filename = [time, paramCase(name)].join('_')
const content = `module.exports = async client => {}`
const path = `${MIGRATION_PATH}/${filename}.js`
fs.writeFile(path, content, err => err
? console.error(err)
: console.log(`migration file written at ${path}`)
)
}
;({
create,
migrate
}[cmd] || migrate)()
@tamlyn
Copy link

tamlyn commented Nov 22, 2017

You may be able to simplify this using umzug which is a really nice unopinionated migration runner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment