Skip to content

Commit

Permalink
Added support for custom migration and seed templates (#145)
Browse files Browse the repository at this point in the history
* Added support for custom migration and seed templates

* Updated cli usage of the template flags

* Updated ci

* Added examples and updated readme

* Updated changelog
  • Loading branch information
halvardssm authored Oct 31, 2021
1 parent 72c1d0d commit 840a32b
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 29 deletions.
36 changes: 18 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ jobs:
cli:
name: Test CLI
runs-on: ubuntu-latest
env:
URL_PATH: ${{github.event.pull_request.head.repo.full_name||github.repository}}/${{github.event.pull_request.head.ref||'main'}}

steps:
- name: Install deno
Expand All @@ -65,50 +67,48 @@ jobs:

- name: Nessie Init
run: deno run -A --unstable https://raw.githubusercontent.com/$URL_PATH/cli.ts init --dialect sqlite
env:
URL_PATH: ${{github.event.pull_request.head.repo.full_name||github.repository}}/${{github.event.pull_request.head.ref||'main'}}

- run: sed -i "s|from \".*\"|from \"https://raw.githubusercontent.com/$URL_PATH/mod.ts\"|" nessie.config.ts && cat nessie.config.ts
env:
URL_PATH: ${{github.event.pull_request.head.repo.full_name||github.repository}}/${{github.event.pull_request.head.ref||'main'}}

- name: Create migration
run: deno run -A --unstable https://raw.githubusercontent.com/$URL_PATH/cli.ts make test
env:
URL_PATH: ${{github.event.pull_request.head.repo.full_name||github.repository}}/${{github.event.pull_request.head.ref||'main'}}

- name: Create migration
run: deno run -A --unstable https://raw.githubusercontent.com/$URL_PATH/cli.ts make:migration test2
env:
URL_PATH: ${{github.event.pull_request.head.repo.full_name||github.repository}}/${{github.event.pull_request.head.ref||'main'}}

- name: Create seed
run: deno run -A --unstable https://raw.githubusercontent.com/$URL_PATH/cli.ts make:seed test
env:
URL_PATH: ${{github.event.pull_request.head.repo.full_name||github.repository}}/${{github.event.pull_request.head.ref||'main'}}

- run: echo "test" >> test_template

- name: Create migration from custom template
run: |
deno run -A --unstable https://raw.githubusercontent.com/$URL_PATH/cli.ts make:migration --migrationTemplate test_template test_migration_template
TEMPLATE_PATH=$(find db/migrations -type f -name "*test_migration_template.ts")
TEMPLATE_CONTENT=$(cat $TEMPLATE_PATH)
if [[ $TEMPLATE_CONTENT != "test" ]]; then echo "File $TEMPLATE_PATH was not correct, was:\n$TEMPLATE_CONTENT" && exit 1; fi
- name: Create seed from custom template
run: |
deno run -A --unstable https://raw.githubusercontent.com/$URL_PATH/cli.ts make:seed --seedTemplate test_template test_seed_template
TEMPLATE_PATH=$(find db/seeds -type f -name "test_seed_template.ts")
TEMPLATE_CONTENT=$(cat $TEMPLATE_PATH)
if [[ $TEMPLATE_CONTENT != "test" ]]; then echo "File $TEMPLATE_PATH was not correct, was:\n$TEMPLATE_CONTENT" && exit 1; fi
- name: Clean files and folders
run: rm -rf db && rm -rf nessie.config.ts

- name: Init with mode and pg
run: deno run -A --unstable https://raw.githubusercontent.com/$URL_PATH/cli.ts init --mode config --dialect pg
env:
URL_PATH: ${{github.event.pull_request.head.repo.full_name||github.repository}}/${{github.event.pull_request.head.ref||'main'}}

- name: Init with mode and mysql
run: deno run -A --unstable https://raw.githubusercontent.com/$URL_PATH/cli.ts init --mode config --dialect mysql
env:
URL_PATH: ${{github.event.pull_request.head.repo.full_name||github.repository}}/${{github.event.pull_request.head.ref||'main'}}

- name: Init with mode and sqlite
run: deno run -A --unstable https://raw.githubusercontent.com/$URL_PATH/cli.ts init --mode config --dialect sqlite
env:
URL_PATH: ${{github.event.pull_request.head.repo.full_name||github.repository}}/${{github.event.pull_request.head.ref||'main'}}

- name: Init with folders only
run: deno run -A --unstable https://raw.githubusercontent.com/$URL_PATH/cli.ts init --mode folders
env:
URL_PATH: ${{github.event.pull_request.head.repo.full_name||github.repository}}/${{github.event.pull_request.head.ref||'main'}}

cli-migrations:
name: Test CLI Migrations
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Nessie Change Log

## Next

- Added support for custom seed and migration templates

## Version 2.0.3 - 2021-10-30

- Deno v1.15.3
Expand Down
44 changes: 41 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,19 +116,29 @@ information.
```
- `make:migration [name]` & `make [name]`: Create migration, `name` has to be
snake- and lowercase, it can also include numbers.
snake- and lowercase, it can also include numbers. You can also provide the
flag `--migrationTemplate <template path or url>` or use the
`migrationTemplate` property in the config file to tell Nessie which template
to use when generating a new migration.

```shell
deno run -A --unstable https://deno.land/x/nessie/cli.ts make:migration create_users

deno run -A --unstable https://deno.land/x/nessie/cli.ts make create_users

deno run -A --unstable https://deno.land/x/nessie/cli.ts make --migrationTemplate some_custom_template create_users
```

- `make:seed [name]`: Create seed, `name` has to be snake- and lowercase, it can
also include numbers.
also include numbers. You can also provide the flag
`--seedTemplate <template path or url>` or use the `seedTemplate` property in
the config file to tell Nessie which template to use when generating a new
migration.

```shell
deno run -A --unstable https://deno.land/x/nessie/cli.ts make:seed add_users

deno run -A --unstable https://deno.land/x/nessie/cli.ts make:seed --seedTemplate some_custom_template add_users
```

- `migrate [amount?]`: Run migration - will migrate your migrations in your
Expand Down Expand Up @@ -207,7 +217,11 @@ information.
### Flags

- `-c, --config`: Path to config file, will default to `./nessie.config.ts`
- `-d, --debug`: Enables verbose output
- `-d, --debug`: Enables verbose output.
- `--migrationTemplate`: Path or URL to a custom migration template. Only used
together with the `make` commands.
- `--seedTemplate`: Path or URL to a custom seed template. Only used together
with the `make` commands.

### Deno flags and Permissions

Expand Down Expand Up @@ -257,6 +271,10 @@ export interface NessieConfig {
* Can be any format supported by `import()` e.g. remote url or path
*/
additionalSeedFiles?: string[];
/** Custom migration template, can be path or url. When also using the CLI flag `--migrationTemplate`, it will have precidence. */
migrationTemplate?: string;
/** Custom seed template, can be path or url. When also using the CLI flag `--seedTemplate`, it will have precidence. */
seedTemplate?: string;
/** Enables verbose output for debugging */
debug?: boolean;
}
Expand All @@ -270,13 +288,31 @@ example via ftp or using api's like gihub or gitlab. Any input which can be
given to the dynamic `import()` can be provided.

```ts
// nessie.config.ts
...
additionalMigrationFiles: ['https://example.com/some_migration_file.ts'],
additionalSeedFiles: ['https://example.com/some_seed_file.ts'],
...
```

See the [example folder](./examples) for more examples.

### Custom Migration or Seed templates

As your project grows, or you are starting to have multiple project but want the
same logic across the migrations, you might find it tedious to change the seed
and migration files after creating them. To get around this, you can provide the
options `migrationTemplate` and `seedTemplate` in the config file, or use the
corresponding flags from the command line. There are no restrictions to what the
file has to contain, so you can even provide an empty file if that is your
preferred starting point.

A general usecase for providing custom templates is in the case that you use a
custom `AbstractMigration` or `AbstractSeed` class, and want to use this for all
your future migrations and seeds.

See the [example folder](./examples) for more examples.

## Docker usage

See the specific [Nessie image docs](./image/README.md) for using Nessie with a
Expand Down Expand Up @@ -329,6 +365,8 @@ const config: NessieConfig = {
seedFolders: ["./db/seeds"],
additionalMigrationFiles: [],
additionalSeedFiles: [],
migrationTemplate: undefined,
seedTemplate: undefined,
debug: false,
};

Expand Down
22 changes: 18 additions & 4 deletions cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {
AmountRollbackT,
CommandOptions,
CommandOptionsInit,
CommandOptionsMakeMigration,
CommandOptionsMakeSeed,
CommandOptionsStatus,
} from "./types.ts";
import { getConfigTemplate } from "./cli/templates.ts";
Expand All @@ -50,12 +52,22 @@ const cli = async () => {
.name("Nessie Migrations")
.version(VERSION)
.description("A database migration tool for Deno.\n" + SPONSOR_NOTICE)
.option("-d, --debug", "Enables verbose output", { global: true })
.option("-d, --debug", "Enables verbose output.", { global: true })
.option(
"-c, --config <config:string>",
"Path to config file.",
{ global: true, default: `./${DEFAULT_CONFIG_FILE}` },
)
.option(
"--seedTemplate <template:string>",
"Path or URL to a custom seed template. Only used together with the `make` commands.",
{ global: true },
)
.option(
"--migrationTemplate <template:string>",
"Path or URL to a custom migration template. Only used together with the `make` commands.",
{ global: true },
)
.command("init", "Generates the config file.")
.option(
"--mode <mode:string>",
Expand Down Expand Up @@ -200,15 +212,17 @@ const initNessie: TCliffyAction<any[], CommandOptionsInit> = async (
console.info(SPONSOR_NOTICE);
};

const makeMigration: TCliffyAction = async (
// deno-lint-ignore no-explicit-any
const makeMigration: TCliffyAction<any[], CommandOptionsMakeMigration> = async (
options,
fileName: string,
) => {
const state = await State.init(options);
await state.makeMigration(fileName);
};

const makeSeed: TCliffyAction = async (
// deno-lint-ignore no-explicit-any
const makeSeed: TCliffyAction<any[], CommandOptionsMakeSeed> = async (
options,
fileName: string,
) => {
Expand Down Expand Up @@ -370,4 +384,4 @@ const run = async () => {
}
};

run();
await run();
19 changes: 15 additions & 4 deletions cli/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
isUrl,
} from "./utils.ts";
import type {
CommandOptions,
AllCommandOptions,
FileEntryT,
LoggerFn,
NessieConfig,
Expand Down Expand Up @@ -66,7 +66,7 @@ export class State {
}

/** Initializes the state with a client */
static async init(options: CommandOptions) {
static async init(options: AllCommandOptions) {
if (options.debug) console.log("Checking config path");

const path = isUrl(options.config)
Expand Down Expand Up @@ -95,6 +95,13 @@ export class State {
config.client.migrationFiles = migrationFiles;
config.client.seedFiles = seedFiles;

if (options.migrationTemplate) {
config.migrationTemplate = options.migrationTemplate;
}
if (options.seedTemplate) {
config.seedTemplate = options.seedTemplate;
}

return new State({
config,
debug: options.debug,
Expand Down Expand Up @@ -251,7 +258,9 @@ export class State {
this.#migrationFolders.filter((folder) => !isUrl(folder)),
);

const template = getMigrationTemplate(this.client.dialect);
const template = this.#config.migrationTemplate
? await Deno.readTextFile(this.#config.migrationTemplate)
: getMigrationTemplate(this.client.dialect);

const filePath = resolve(selectedFolder, fileName);

Expand Down Expand Up @@ -281,7 +290,9 @@ export class State {
this.#seedFolders.filter((folder) => !isUrl(folder)),
);

const template = getSeedTemplate(this.client.dialect);
const template = this.#config.seedTemplate
? await Deno.readTextFile(this.#config.seedTemplate)
: getSeedTemplate(this.client.dialect);

const filePath = resolve(selectedFolder, fileName);

Expand Down
4 changes: 4 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ If you want to include external migrations, check out these examples:
- [With GitHub API](./config-remote-migration-files-github-api.ts) - this
example uses the github api to get the folder content and parse migration
files from it.
- [With custom templates](./config-custom-templates.ts) - this example uses
custom templates and shows how to deal with custom abstract classes.

## Migration files

- [Basic migration](./migration.ts)
- [Migration using Dex](./migration-dex.ts)
- [Custom AbstractMigration](./abstract-classes-extended.ts)

## Seed files

- [Basic seed](./seed.ts)
- [Custom AbstractSeed](./abstract-classes-extended.ts)
21 changes: 21 additions & 0 deletions examples/abstract-classes-extended.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {
AbstractClient,
AbstractMigration,
AbstractSeed,
ClientPostgreSQL,
} from "https://deno.land/x/nessie/mod.ts";

// This is a custom abstract migration class which can be used in the migration files
export class CustomAbstractMigration<T extends AbstractClient<any> = any>
extends AbstractMigration<T> {
someHelperFunction() {
console.log("Hey, I am available to all child classes!");
}
}

// I want to always use postres client in this class
export class CustomAbstractSeed extends AbstractSeed<ClientPostgreSQL> {
someHelperFunction() {
console.log("Hey, I am available to all child classes!");
}
}
9 changes: 9 additions & 0 deletions examples/config-custom-templates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ClientSQLite, NessieConfig } from "https://deno.land/x/nessie/mod.ts";

const config: NessieConfig = {
client: new ClientSQLite("sqlite.db"),
migrationTemplate: "./migration-template.ts",
seedTemplate: "./seed-template.ts",
};

export default config;
17 changes: 17 additions & 0 deletions examples/migration-template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {
ClientPostgreSQL,
Info,
//As this is a custom template, I want to lock the nessie version to 2.0.0
} from "https://deno.land/x/[email protected]/mod.ts";
// I can import what I want to be used in this template
import { CustomAbstractMigration } from "./abstract-classes-extended.ts";

export default class extends CustomAbstractMigration<ClientPostgreSQL> {
async up({ dialect }: Info): Promise<void> {
this.someHelperFunction();
}

async down({ dialect }: Info): Promise<void> {
// For this custom template, I do not want the down method to be predefined,
}
}
13 changes: 13 additions & 0 deletions examples/seed-template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {
ClientPostgreSQL,
Info,
//As this is a custom template, I want to lock the nessie version to 2.0.0
} from "https://deno.land/x/[email protected]/mod.ts";
// I can import what I want to be used in this template
import { CustomAbstractSeed } from "./abstract-classes-extended.ts";

export default class extends CustomAbstractSeed {
async run({ dialect }: Info): Promise<void> {
this.someHelperFunction();
}
}
Loading

0 comments on commit 840a32b

Please sign in to comment.