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)()
@antho1404
Copy link
Author

In your project just add a db/migrations folder and put this file in db

Also you need to add in your types.graphql a new model that will ensure that your migration run only one time

type Migration @model {
  id: ID! @isUnique
  migrationName: String! @isUnique
}

then you can run the following commands

  • node db/migration create migration-name: This will create a new file in db/migrations and you can write your migration in it, the client given in parameter will be configured to access the graphcool project according to your .graphcoolrc file

  • node db/migration migrate [target]: This will run all the migrations that hasn't been deployed yet, you can give the target in parameter and it will by default use the default you have in your .graphcoolrc file

@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