Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: changed config means without dotenv #3

Merged
merged 2 commits into from
Oct 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
.env
src/.env
.nvmrc
node_modules
yarn-error.log
yarn.lock
coverage
*migrations
.upmigrc.js
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ or
```bash
yarn add pg-upmig
```

## Configuration
Either use environment variables
```bash
UPMIG_PATH=./migrations
UPMIG_TABLE=pg_upmig
```
or use `.upmigrc.js` to set global options:
```javascript
module.exports = {
migrations: "./migrations", // Where to store migrations files
table: "pg_upmig", // Table name where migrations history is stored
};
```
## Migrations folder tree view
```
.
Expand Down Expand Up @@ -54,7 +68,6 @@ Usage: pg-upmig [options] [command]
Options:
-V, --version output the version number
-h, --help display help for command
-e, --env <path> specify environment file path
-m, --migrations <path> specify migrations path (default: "./migrations")
-p, --pgtable <table> specify migration table name (default: "pg_upmig")

Expand Down Expand Up @@ -141,7 +154,6 @@ migration.up({
|options|[Global options](#global-options)|
|connection|[Connection parameters](#connection-parameters) for default `node-postgres` client|
|client|[Custom postgres client](#custom-postgres-client) instance|
|enfFile|Environment file path (.env)|

##### Global options
|Key|Type|Description|Default|
Expand Down Expand Up @@ -244,7 +256,6 @@ function customFunction () {
*Promise*

Creates timestamped migration files (sql file creation is avoided when `nosql` is `true`) using `template.stub` as a template. Filename collision is handled even if this case should not happen.
`name` is

Returns the full name of created file :
`1600775947530_create-table`
Expand Down Expand Up @@ -282,3 +293,4 @@ Returns an array of objects representing migration file:
|name|string|Migration name excluding timestamp.|
## Todo
- [ ] Custom logger implementation
- [ ] Remove dispensable dependencies
15 changes: 13 additions & 2 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
require("dotenv").config({path: "src/.env"});
const fs = require("fs");

module.exports = () => {};
module.exports = async () => {
try {
(await fs.promises.readFile(".env")) // read config file
.toString("utf8") // buffer to string
.split(/\n|\r|\r/) // break by new line
.filter(item => /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/.test(item)) // keep key / val
.map(item => {
const match = item.match(/^\s*([\w.-]+)\s*=\s*(.*)?\s*$/);
if (!Object.prototype.hasOwnProperty.call(process.env, match[1])) process.env[match[1]] = match[2].replace(/^("|')(.*)\1$/, "$2"); // set env
});
} catch (error) {}
};
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pg-upmig",
"version": "0.0.25",
"version": "0.0.26",
"description": "Postgresql migration tool",
"keywords": [
"database",
Expand All @@ -25,7 +25,6 @@
"dependencies": {
"chalk": "^4.1.0",
"commander": "^6.1.0",
"dotenv": "^8.2.0",
"pg": "^8.3.3"
},
"devDependencies": {
Expand Down
27 changes: 13 additions & 14 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@ const migration = require("./index.js");
const pkg = require("../package.json");
const chalk = require("chalk");
const { program } = require("commander");
const path = require("path");

let migrationsPath = process.env.UPMIG_PATH||"./migrations";
let pgTable = process.env.UPMIG_TABLE||"pg_upmig";

try {
const dotConfig = require(path.join(process.cwd(), ".upmigrc.js"));
migrationsPath = dotConfig.migrations?dotConfig.migrations:migrationsPath;
pgTable = dotConfig.table?dotConfig.table:pgTable;
} catch (error) {}

function steps (s) {
const parsed = parseInt(s.replace(/[^0-9]+/g, ""));
Expand All @@ -26,16 +35,9 @@ function migTable (name) {

exports.migTable = migTable;

let envFile = ".env";
let migrationsPath = "./migrations";
let pgTable = "pg_upmig";

function setOpt (namespace) {
return (option) => {
switch (namespace) {
case "env":
envFile = option ? option:envFile;
break;
case "migrations":
migrationsPath = option ? option:migrationsPath;
break;
Expand All @@ -49,25 +51,22 @@ exports.setOpt = setOpt;

exports._env = () => {
return {
envFile,
migrationsPath,
pgTable
};
}

program.on("option:env", setOpt("env"));
program.on("option:migrations", setOpt("migrations"));
program.on("option:pgtable", setOpt("pgtable"));

program.version(pkg.version)
.arguments("<cmd> [opt]")
.usage("<command> [options]")
.option("-e, --env <path>", "specify environment file path")
.option("-m, --migrations <path>", "specify migrations path", "./migrations")
.option("-p, --pgtable <table>", "specify migration table name", "pg-upmig", migTable);

async function up (cmd) {
const mig = new migration({envFile});
const mig = new migration();
await mig.init({
table: pgTable,
migrations: migrationsPath,
Expand Down Expand Up @@ -98,9 +97,9 @@ program
});

async function create (cmd, name){
const mig = new migration({envFile});
const mig = new migration();
await mig.init({migrations: migrationsPath, table: pgTable});
const file = await mig.create(name.join("-"), cmd.nosql);
const file = await mig.create(name?name.join("-"):"", cmd.nosql);
mig.release();
return file;
}
Expand All @@ -119,7 +118,7 @@ program
});

async function pending (cmd) {
const mig = new migration({envFile});
const mig = new migration();
await mig.init({migrations: migrationsPath, table: pgTable, history: cmd.history});
const list = await mig.pending();
mig.release();
Expand Down
29 changes: 11 additions & 18 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/** @module pg-upmig */

const { Client, types } = require("pg");
const dotenv = require("dotenv");
const path = require("path");
const fs = require("fs");

Expand All @@ -12,7 +11,6 @@ const fs = require("fs");
* @param {Object} params Constructor arguments
* @param {Object} params.client Custom database client
* @param {Object} params.connection PG connection params
* @param {String} params.envFile Environment file path
* @param {Object} params.options Global options
* @param {String} params.options.table Migrations table
* @param {String} params.options.migrations Migrations path
Expand Down Expand Up @@ -44,8 +42,8 @@ class migration {
this.isConnected = false;

this.options = {
table: "pg_upmig",
migrations: "./migrations",
table: process.env.UPMIG_TABLE||"pg_upmig",
migrations: process.env.UPMIG_PATH||"./migrations",
transactionnal: true,
queryMethod: "query",
connectMethod: "connect",
Expand All @@ -56,29 +54,24 @@ class migration {
debug: false
};

if (params.options) {
Object.assign(this.options, params.options);
}

// finds environment file path first if defined
try {
const cfg = dotenv.config({path: params.envFile});
if (cfg.error) {
throw new Error("Check for standard environment file (.env)");
}
} catch (error) {
this._debug(error, 1);
dotenv.config();
const dotConfig = require(path.join(process.cwd(),".upmigrc.js"));
this.options.migrations = dotConfig.migrations?dotConfig.migrations:this.options.migrations;
this.options.table = dotConfig.table?dotConfig.table:this.options.table;
} catch (error) { }

if ((params||{}).options) {
Object.assign(this.options, params.options);
}

// Sets custom database client
if (params.client) {
if ((params||{}).client) {
this.client = params.client;
}

// Sets default database client
if (!this.client) {
if (params.connection) {
if ((params||{}).connection) {
// Uses connection params
this.client = new Client(params.connection);
} else {
Expand Down
42 changes: 19 additions & 23 deletions tests/cli.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,12 @@ describe("Core helpers logic", () => {
});

test("setOpt function", () => {
cli.setOpt("env")("");
expect(cli._env().envFile).toBe(".env");
cli.setOpt("env")("null");
expect(cli._env().envFile).toBe("null");
cli.setOpt("migrations")("");
expect(cli._env().migrationsPath).toBe("./migrations");
expect(cli._env().migrationsPath).toBe(fixtures.migrations);
cli.setOpt("migrations")("null");
expect(cli._env().migrationsPath).toBe("null");
cli.setOpt("pgtable")("");
expect(cli._env().pgTable).toBe("pg_upmig");
expect(cli._env().pgTable).toBe(fixtures.pgTable);
cli.setOpt("pgtable")("null");
expect(cli._env().pgTable).toBe("null");
});
Expand Down Expand Up @@ -251,7 +247,7 @@ describe("Create migration file", () => {
});

test("Init and create new migration file", async () => {
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
const line = response.trim();
expect(line).toEqual(expect.stringMatching(/Migration file created:\s+[0-9]+_.+$/i));
const filename = line.replace(/^.+\s([0-9]+_[0-9a-z_\-]+)$/i, "$1");
Expand All @@ -260,7 +256,7 @@ describe("Create migration file", () => {
});

test("Create new migration file without sql placeholder file", async () => {
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.new, fixtures.migrationFile, "-n"], [], {env});
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.new, fixtures.migrationFile, "-n"], [], {env});
const line = response.trim();
expect(line).toEqual(expect.stringMatching(/Migration file created:\s+[0-9]+_.+$/i));
const filename = line.replace(/^.+\s([0-9]+_[0-9a-z_\-]+)$/i, "$1");
Expand All @@ -283,7 +279,7 @@ describe("List pending migrations", () => {
test("List pending migratons without history", async () => {
const details = [];
for (let i = 0; i <= Math.round(Math.random() * 5); i++) {
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
details.push(created.trim().match(/\s([0-9]+)_([0-9a-z_\-]+)$/i));
}
const containing = [];
Expand All @@ -293,17 +289,17 @@ describe("List pending migrations", () => {
}
containing.push(expect.stringMatching(new RegExp(`Pending migrations:\\s+${details.length}$`, "i")));

const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.list], [], {env});
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.list], [], {env});
expect(response.trim().split(EOL)).toEqual(containing);

// Perform left pending migrations
await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.perform], [], {env});
await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.perform], [], {env});
});

test("List pending migratons with history", async () => {
const details = [];
for (let i = 0; i <= Math.round(Math.random() * 5); i++) {
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
details.push(created.trim().match(/\s([0-9]+)_([0-9a-z_\-]+)$/i));
}
const containing = [];
Expand All @@ -313,7 +309,7 @@ describe("List pending migrations", () => {
}
containing.push(expect.stringMatching(new RegExp(`Pending migrations:\\s+${details.length}/\[0\-9\]\+\\s\\(\[0\-9\]\+\\sdone\\)$`, "i")));

const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.list, "-H"], [], {env});
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.list, "-H"], [], {env});
expect(response.trim().split(EOL)).toEqual(containing);
});
});
Expand All @@ -330,9 +326,9 @@ describe("Perform pending migrations", () => {
});

test("Perform all pending migrations", async () => {
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
const details = created.trim().match(/\s([0-9]+)_([0-9a-z_\-]+)$/i);
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.perform], [], {env});
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.perform], [], {env});
expect(response.trim().split(EOL)).toEqual(expect.arrayContaining([
expect.stringMatching(new RegExp(`${details[2]}\\s+${details[1]}$`, "i")),
expect.stringMatching(/Migrations completed:\s+1$/i)
Expand All @@ -342,42 +338,42 @@ describe("Perform pending migrations", () => {
test("Perform specific number of pending migrations", async () => {
const details = [];
for (let i = 0; i < 3; i++) {
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
details.push(created.trim().match(/\s([0-9]+)_([0-9a-z_\-]+)$/i));
}
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.perform, "-s", "2"], [], {env});
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.perform, "-s", "2"], [], {env});
expect(response.trim().split(EOL)).toEqual(expect.arrayContaining([
expect.stringMatching(new RegExp(`${details[0][2]}\\s+${details[0][1]}$`, "i")),
expect.stringMatching(new RegExp(`${details[1][2]}\\s+${details[1][1]}$`, "i")),
expect.stringMatching(/Migrations completed:\s+2$/i)
]));

// Perform left pending migrations
await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.perform], [], {env});
await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.perform], [], {env});
});

test("Perform pending migrations till specific timestamp", async () => {
const details = [];
for (let i = 0; i < 3; i++) {
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
details.push(created.trim().match(/\s([0-9]+)_([0-9a-z_\-]+)$/i));
}
const ts = parseInt(details[1][1], 10) + 1;
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.perform, "-t", ts], [], {env});
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.perform, "-t", ts], [], {env});
expect(response.trim().split(EOL)).toEqual(expect.arrayContaining([
expect.stringMatching(new RegExp(`${details[0][2]}\\s+${details[0][1]}$`, "i")),
expect.stringMatching(new RegExp(`${details[1][2]}\\s+${details[1][1]}$`, "i")),
expect.stringMatching(/Migrations completed:\s+2$/i)
]));

// Perform left pending migrations
await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.perform], [], {env});
await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.perform], [], {env});
});

test("Perform pending migrations first condition reached (steps & timestamp)", async () => {
const details = [];
for (let i = 0; i <= 4; i++) {
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
const created = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.new, fixtures.migrationFile], [], {env});
details.push(created.trim().match(/\s([0-9]+)_([0-9a-z_\-]+)$/i));
}
const byTs = Math.round(Math.random() * 3);
Expand All @@ -391,7 +387,7 @@ describe("Perform pending migrations", () => {
}
containing.push(expect.stringMatching(new RegExp(`Migrations completed:\\s+${min+1}$`, "i")));

const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, "-e", fixtures.envFile, fixtures.cli._cmds.perform, "-t", ts, "-s", bySt+1], [], {env});
const response = await proc.execute(["-m", fixtures.migrations, "-p", fixtures.pgTable, fixtures.cli._cmds.perform, "-t", ts, "-s", bySt+1], [], {env});
expect(response.trim().split(EOL)).toEqual(expect.arrayContaining(containing));
});
});
Loading