Skip to content

Commit

Permalink
Merge pull request #53 from halvardssm/cli/expose-qb-in-up-down
Browse files Browse the repository at this point in the history
Expose qb in down/up
  • Loading branch information
halvardssm authored Jun 4, 2020
2 parents 3661d3f + 4611b84 commit bfd3826
Show file tree
Hide file tree
Showing 29 changed files with 337 additions and 285 deletions.
53 changes: 27 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,24 +79,29 @@ All contributions are welcome, make sure to read the [contributing guideline](./

## Examples

`nessie.config.ts`
`nessie.config.ts` with all default values

```ts
import { ClientPostgreSQL, nessieConfig } from "https://deno.land/x/nessie/mod.ts";

const migrationFolder = "./migrations";

const config: nessieConfig = {
client: new ClientPostgreSQL(migrationFolder, {
database: "nessie",
hostname: "localhost",
port: 5432,
user: "root",
password: "pwd",
}),
import { ClientPostgreSQL } from "./clients/ClientPostgreSQL.ts";

const nessieOptions = {
migrationFolder: "./db/migrations",
seedFolder: "./db/seeds",
};

const connectionOptions = {
database: "nessie",
hostname: "localhost",
port: 5432,
user: "root",
password: "pwd",
};

export default {
client: new ClientPostgreSQL(nessieOptions, connectionOptions),
exposeQueryBuilder: false,
};

export default config;
```

Minimal example of a migration file
Expand All @@ -113,34 +118,30 @@ export const down: Migration = () => {
};
```

Using the native query builder
Using the native query builder (`exposeQueryBuilder: true`)

```ts
import { Migration } from "https://deno.land/x/nessie/mod.ts";
import { Schema, dbDialects } from "https://deno.land/x/nessie/qb.ts";
import { Schema } from "https://deno.land/x/nessie/qb.ts";

const dialect: dbDialects = "mysql"

export const up: Migration = () => {
const queryArray: string[] = new Schema(dialect).create("users", (table) => {
export const up: Migration<Schema> = ({ queryBuilder }) => {
queryBuilder.create("users", (table) => {
table.id();
table.string("name", 100).nullable();
table.boolean("is_true").default("false");
table.custom("custom_column int default 1");
table.timestamps();
});

const queryString = new Schema(dialect).queryString(
queryBuilder.queryString(
"INSERT INTO users VALUES (DEFAULT, 'Deno', true, 2, DEFAULT, DEFAULT);",
)

queryArray.push(queryString);

return queryArray
return queryBuilder.query
};

export const down: Migration = () => {
return new Schema(dialect).drop("users");
export const down: Migration<Schema> = ({ queryBuilder }) => {
return queryBuilder.drop("users");
};
```

Expand Down
17 changes: 8 additions & 9 deletions cli/state.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import {
AbstractClient,
ClientI,
nessieConfig,
} from "../clients/AbstractClient.ts";
import { AbstractClient } from "../clients/AbstractClient.ts";
import { ClientPostgreSQL } from "../clients/ClientPostgreSQL.ts";
import { Denomander } from "../deps.ts";
import { parsePath } from "./utils.ts";

export type loggerFn = (output?: any, title?: string) => void;
import { NessieConfig, ClientI } from "../types.ts";

const STD_CONFIG_FILE = "nessie.config.ts";

Expand All @@ -19,7 +14,7 @@ const STD_CLIENT_OPTIONS = {
export class State {
private enableDebug: boolean;
private configFile: string;
private config?: nessieConfig;
private config?: NessieConfig;
client?: ClientI;

constructor(prog: Denomander) {
Expand Down Expand Up @@ -52,7 +47,11 @@ export class State {
this.client = this.config.client;
}

this.client?.setLogger(this.logger.bind(this));
if (this.config?.exposeQueryBuilder) {
this.client.exposeQueryBuilder = this.config.exposeQueryBuilder;
}

this.client.setLogger(this.logger.bind(this));

return this;
}
Expand Down
125 changes: 59 additions & 66 deletions clients/AbstractClient.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,16 @@
import { parsePath } from "../cli/utils.ts";
import { resolve } from "../deps.ts";
import { loggerFn } from "../cli/state.ts";
import { Migration } from "../types.ts";

export type QueryWithString = (string: string) => string;

export type amountMigrateT = number | undefined;
export type amountRollbackT = amountMigrateT | "all";
export type queryT = string | string[];
export type QueryHandler = (query: queryT) => Promise<any>;
export type MigrationFile = {
up: Migration;
down: Migration;
};

export interface ClientI {
migrationFolder: string;
seedFolder: string;
migrationFiles: Deno.DirEntry[];
seedFiles: Deno.DirEntry[];
prepare: () => Promise<void>;
close: () => Promise<void>;
migrate: (amount: amountMigrateT) => Promise<void>;
rollback: (amount: amountRollbackT) => Promise<void>;
seed: (matcher?: string) => Promise<void>;
query: QueryHandler;
setLogger: loggerFn;
}

export interface nessieConfig {
client: ClientI;
}

export interface ClientOptions {
migrationFolder: string;
seedFolder: string;
[option: string]: any;
}

import {
LoggerFn,
QueryWithString,
ClientOptions,
AmountMigrateT,
QueryHandler,
MigrationFile,
AmountRollbackT,
Info,
DBDialects,
} from "../types.ts";
export class AbstractClient {
static readonly MAX_FILE_NAME_LENGTH = 100;

Expand All @@ -46,11 +19,13 @@ export class AbstractClient {
protected COL_CREATED_AT = "created_at";
protected REGEX_MIGRATION_FILE_NAME = /^\d{10,14}-.+.ts$/;
protected regexFileName = new RegExp(this.REGEX_MIGRATION_FILE_NAME);
protected logger: loggerFn = () => undefined;
protected logger: LoggerFn = () => undefined;
migrationFiles: Deno.DirEntry[];
seedFiles: Deno.DirEntry[];
migrationFolder: string;
seedFolder: string;
exposeQueryBuilder: boolean = false;
dialect?: DBDialects;

protected QUERY_GET_LATEST =
`SELECT ${this.COL_FILE_NAME} FROM ${this.TABLE_MIGRATIONS} ORDER BY ${this.COL_FILE_NAME} DESC LIMIT 1;`;
Expand All @@ -71,9 +46,9 @@ export class AbstractClient {
this.seedFolder = resolve("./db/seeds");
} else {
this.migrationFolder = resolve(
options.migrationFolder || "./db/migrations",
options?.migrationFolder || "./db/migrations",
);
this.seedFolder = resolve(options.seedFolder || "./db/seeds");
this.seedFolder = resolve(options?.seedFolder || "./db/seeds");
}

try {
Expand All @@ -92,7 +67,7 @@ export class AbstractClient {
}

protected async migrate(
amount: amountMigrateT,
amount: AmountMigrateT,
latestMigration: string | undefined,
queryHandler: QueryHandler,
) {
Expand All @@ -113,18 +88,8 @@ export class AbstractClient {

for (let i = 0; i < amount; i++) {
const file = this.migrationFiles[i];
let { up }: MigrationFile = await import(
parsePath(this.migrationFolder, file.name)
);

let query = await up();

if (!query) query = [];
else if (typeof query === "string") query = [query];

query.push(this.QUERY_MIGRATION_INSERT(file.name));

await queryHandler(query);
await this._migrationHandler(file.name, queryHandler);

console.info(`Migrated ${file.name}`);
}
Expand All @@ -145,7 +110,7 @@ export class AbstractClient {
}

async rollback(
amount: amountRollbackT,
amount: AmountRollbackT,
allMigrations: string[] | undefined,
queryHandler: QueryHandler,
) {
Expand All @@ -164,18 +129,8 @@ export class AbstractClient {

for (let i = 0; i < amount; i++) {
const fileName = allMigrations[i];
let { down }: MigrationFile = await import(
parsePath(this.migrationFolder, fileName)
);

let query = await down();

if (!query) query = [];
else if (typeof query === "string") query = [query];

query.push(this.QUERY_MIGRATION_DELETE(fileName));

await queryHandler(query);
await this._migrationHandler(fileName, queryHandler, true);

console.info(`Rolled back ${fileName}`);
}
Expand All @@ -188,7 +143,7 @@ export class AbstractClient {
return query.split(";").filter((el) => el.trim() !== "");
}

setLogger(fn: loggerFn) {
setLogger(fn: LoggerFn) {
this.logger = fn;
}

Expand All @@ -215,4 +170,42 @@ export class AbstractClient {
console.info("Seeding complete");
}
}

private async _migrationHandler(
fileName: string,
queryHandler: QueryHandler,
isDown: boolean = false,
) {
let { up, down }: MigrationFile = await import(
parsePath(this.migrationFolder, fileName)
);

const exposedObject: Info = {
dialect: this.dialect!,
};

if (this.exposeQueryBuilder) {
const { Schema } = await import("https://deno.land/x/nessie/qb.ts");
exposedObject.queryBuilder = new Schema(this.dialect);
}

let query: string | string[];

if (isDown) {
query = await down(exposedObject);
} else {
query = await up(exposedObject);
}

if (!query) query = [];
else if (typeof query === "string") query = [query];

if (isDown) {
query.push(this.QUERY_MIGRATION_DELETE(fileName));
} else {
query.push(this.QUERY_MIGRATION_INSERT(fileName));
}

await queryHandler(query);
}
}
18 changes: 10 additions & 8 deletions clients/ClientMySQL.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { Client, ClientConfig } from "https://deno.land/x/mysql@2.2.0/mod.ts";
import { AbstractClient } from "./AbstractClient.ts";
import {
AbstractClient,
amountMigrateT,
amountRollbackT,
AmountMigrateT,
AmountRollbackT,
ClientI,
queryT,
QueryT,
ClientOptions,
} from "./AbstractClient.ts";
DBDialects,
} from "../types.ts";

export class ClientMySQL extends AbstractClient implements ClientI {
private client: Client;
private clientOptions: ClientConfig;
dialect: DBDialects = "mysql";

private QUERY_MIGRATION_TABLE_EXISTS =
// `show tables like '${this.TABLE_MIGRATIONS}';`;
Expand Down Expand Up @@ -39,7 +41,7 @@ export class ClientMySQL extends AbstractClient implements ClientI {
}
}

async query(query: queryT) {
async query(query: QueryT) {
if (typeof query === "string") query = this.splitAndTrimQueries(query);
const ra = [];

Expand Down Expand Up @@ -69,7 +71,7 @@ export class ClientMySQL extends AbstractClient implements ClientI {
await this.client.close();
}

async migrate(amount: amountMigrateT) {
async migrate(amount: AmountMigrateT) {
const latestMigration = await this.query(this.QUERY_GET_LATEST);
await super.migrate(
amount,
Expand All @@ -78,7 +80,7 @@ export class ClientMySQL extends AbstractClient implements ClientI {
);
}

async rollback(amount: amountRollbackT) {
async rollback(amount: AmountRollbackT) {
const allMigrations = await this.query(this.QUERY_GET_ALL);

const parsedMigrations: string[] = allMigrations?.[0].map((el: any) =>
Expand Down
Loading

0 comments on commit bfd3826

Please sign in to comment.