-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: how do we create and run migrations (#28)
- Loading branch information
Showing
8 changed files
with
298 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#! /usr/bin/env node | ||
|
||
const program = require("commander"); | ||
const migrate = require("../dist/migration"); | ||
const pkgjson = require("../package.json"); | ||
|
||
program.version(pkgjson.version); | ||
|
||
program | ||
.command("init") | ||
.description("initialize a new migration project") | ||
.action(() => | ||
migrate | ||
.init() | ||
.then(() => console.log(`Initialization successful. Check out \`${migrate.DEFAULT_CONFIG_FILE_NAME}\` file`)) | ||
.catch(err => { | ||
console.error(`ERROR: ${err.message}`); | ||
process.exit(1); | ||
}) | ||
); | ||
|
||
program | ||
.command("create [description]") | ||
.description("create a new database migration with the provided description") | ||
.option("-f --file <file>", "use a custom config file") | ||
.action((description, options) => { | ||
global.options = options; | ||
migrate | ||
.create(description) | ||
.then(destination => console.log(`Created: ${destination}`)) | ||
.catch(err => { | ||
console.error(`ERROR: ${err.message}`); | ||
process.exit(1); | ||
}); | ||
}); | ||
|
||
program.parse(process.argv); | ||
|
||
if (!program.rawArgs || program.rawArgs.length === 0) { | ||
program.outputHelp(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// In this file you can configure migrate-mongo | ||
|
||
const config = { | ||
// The migrations dir, can be an relative or absolute path. Only edit this when really necessary. | ||
migrationsDir: "dist/migrations", | ||
|
||
// The mongodb collection where the applied changes are stored. Only edit this when really necessary. | ||
changelogCollectionName: "changelog", | ||
|
||
// The file extension to create migrations and search for in migration dir | ||
migrationFileExtension: ".js" | ||
}; | ||
|
||
// Return the config as a promise | ||
module.exports = config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Db, MongoClient } from "mongodb"; | ||
|
||
export async function up(db: Db, conn: MongoClient) { | ||
// TODO write your migration here. | ||
// Example: | ||
// await db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: true}}); | ||
} | ||
|
||
export async function down(db: Db, conn: MongoClient) { | ||
// TODO write the statements to rollback your migration (if possible) | ||
// Example: | ||
// await db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: false}}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import fs from "fs"; | ||
import { down, up, config } from "migrate-mongo"; | ||
import { Connection } from "mongoose"; | ||
import path from "path"; | ||
import format from "date-fns/format"; | ||
|
||
const PREFIX_FORMAT = "yyyyMMddHHmmss"; | ||
export const DEFAULT_MIGRATION_DIR = "src/migrations"; | ||
export const DEFAULT_CONFIG_FILE_NAME = "migrate-mongo-config.js"; | ||
|
||
/** | ||
* Applies all unapplied migrations to the DB. Note that it passes the mongoose | ||
* connection in place of `MongoClient` due to being unable to access | ||
* that from mongoose. | ||
* @param connection mongoose connection to be used for migration | ||
*/ | ||
export function migrateUp(connection: Connection) { | ||
// @ts-ignore wrong typing | ||
return up(connection.db, connection.client); | ||
} | ||
|
||
/** | ||
* Undo the last applied migration. Note that it passes the mongoose | ||
* connection in place of `MongoClient` due to being unable to access | ||
* that from mongoose. | ||
* @param connection mongoose connection to be used for migration | ||
*/ | ||
export function migrateDown(connection: Connection) { | ||
// @ts-ignore wrong typing | ||
return down(connection.db, connection.client); | ||
} | ||
|
||
export async function create(description: string) { | ||
if (!description) { | ||
throw new Error("Missing parameter: description"); | ||
} | ||
|
||
// where should we store the new migration | ||
await config.shouldExist(); | ||
const migrationConfig = await config.read(); | ||
const configuredDir = migrationConfig.migrationsDir?.replace("dist", "src") ?? DEFAULT_MIGRATION_DIR; | ||
const migrationsDir = path.isAbsolute(configuredDir) ? configuredDir : path.join(process.cwd(), configuredDir); | ||
|
||
try { | ||
await fs.promises.access(migrationsDir); | ||
} catch (err) { | ||
throw new Error(`migrations directory does not exist: ${migrationsDir}`); | ||
} | ||
|
||
// construct the file name | ||
const source = path.join(__dirname, "../samples/sample-migration.ts"); | ||
const prefix = format(new Date(), PREFIX_FORMAT); | ||
const filename = `${prefix}-${description.split(" ").join("_")}.ts`; | ||
|
||
// copy sample file to new file | ||
const destination = path.join(migrationsDir, filename); | ||
await fs.promises.copyFile(source, destination); | ||
|
||
return destination; | ||
} | ||
|
||
export async function init() { | ||
const source = path.join(__dirname, `../samples/${DEFAULT_CONFIG_FILE_NAME}`); | ||
const destination = path.join(process.cwd(), DEFAULT_CONFIG_FILE_NAME); | ||
|
||
await fs.promises.copyFile(source, destination); | ||
return fs.promises.mkdir(path.join(process.cwd(), "src/migrations")); | ||
} |
Oops, something went wrong.