Nessie
A modular database migration tool for Deno inspired by Laravel and Phinx. Supports PostgreSQL, MySQL (& MariaDB) and SQLite.
🚨 Version 2.0.0 is soon to be released: Follow the release candidates to try out the new features, assist with finding bugs, and give feedback! V2.0.0 is available on the branch v2 until release.
If you would like to see your DB flavor supported, take a look at how to make a client plugin with examples in the clients folder or in the section How to make a client.
See documentation for the clients.
Nessie is available through:
- https://deno.land/x/nessie
- https://raw.githubusercontent.com/halvardssm/deno-nessie
- https://nest.land/package/Nessie
- https://hub.docker.com/repository/docker/halvardm/nessie
CLI Usage
init
: Generates anessie.config.ts
file and also thedb
folder where migration and seed files will be placed. Two options are available:--mode
and--dialect
.--mode
can be one ofconfig
orfolders
. If mode is not set, it will create anessie.config.ts
file and thedb
folder structure, otherwise it will create the selected one.--dialect
is used for the config file and can be one ofpg
,mysql
orsqlite
. If not set, it will create a general config file including all three dialects, otherwise it will include only the selected one.deno run -A --unstable https://deno.land/x/nessie/cli.ts init deno run -A --unstable https://deno.land/x/nessie/cli.ts init --mode folders deno run -A --unstable https://deno.land/x/nessie/cli.ts init --mode config --dialect pg
make:migration [name]
&make [name]
: Create migration,name
has to be snake- and lowercase, it can also include numbers.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
make:seed [name]
: Create seed,name
has to be snake- and lowercase, it can also include numbers.deno run -A --unstable https://deno.land/x/nessie/cli.ts make:seed add_users
migrate [amount?]
: Run migration - will migrate your migrations in your migration folder (sorted by timestamp) newer than the latest migration in your db. Amount defines how many migrations, defaults to all available if not set.deno run -A --unstable https://deno.land/x/nessie/cli.ts migrate deno run -A --unstable https://deno.land/x/nessie/cli.ts migrate 1 deno run -A --unstable https://deno.land/x/nessie/cli.ts migrate -c ./nessie.config.ts
rollback [amount?]
: Rollback - will rollback your migrations. Amount defines how many migrations, defaults to 1 if not set.deno run -A --unstable https://deno.land/x/nessie/cli.ts rollback deno run -A --unstable https://deno.land/x/nessie/cli.ts rollback 2 deno run -A --unstable https://deno.land/x/nessie/cli.ts rollback all
seed [matcher?]
: Seed - will seed your database. Optional matcher will match all files in your seed folder by string literal or RegExp.deno run -A --unstable https://deno.land/x/nessie/cli.ts seed deno run -A --unstable https://deno.land/x/nessie/cli.ts seed seed_file.js deno run -A --unstable https://deno.land/x/nessie/cli.ts seed ".+.ts"
update_timestamps
: Update timestamps - will update timestamps to the new format. Will only update timestamps where the value is less than 1672531200000 (2023-01-01) so that the timestamps won't be updated multiple times.deno run -A --unstable https://deno.land/x/nessie/cli.ts update_timestamps
Flags
-c, --config
: Path to config file, will default to./nessie.config.ts
-d, --debug
: Enables verbose output
Deno flags and Permissions
While the examples simply show -A
as the permission flag, you can also limit
the permissions according to your needs. Bellow you will see what Nessie
actually needs.
--unstable
: Needed by std/fs/copy as it usesDeno.utimeSync
andDeno.utime
which are still unstable--allow-read
: Nessie needs read access to be able to read the migration and seed folders, it also checks for the presence of the config file.--allow-write
: When initiating Nessie or creating a new migration or seed file, write access is required.--allow-net
: If you use a remote config or migration files, this flag is needed to get access.
Config file
The config interface is exported from mod.ts
as NessieConfig
.
export interface NessieConfig {
/** Can be any class which extends `AbstractClient`. */
client: AbstractClient<any>;
/**
* The folders where migration files are located.
* Can be a relative path or an absolute path.
* Defaults to ['./db/migrations/'] if additionalMigrationFiles is not populated
*/
migrationFolders?: string[];
/**
* The folders where seed files are located.
* Can be a relative path or an absolute path.
* Defaults to ['./db/seeds/'] if additionalSeedFiles is not populated
*/
seedFolders?: string[];
/**
* Additional migration files which will be added to the
* list to parse when running the migrate or rollback command.
* Can be any format supported by `import()` e.g. url or path
*/
additionalMigrationFiles?: string[];
/**
* Additional seed files which will be added to the list to
* match against when running the seed command.
* Can be any format supported by `import()` e.g. remote url or path
*/
additionalSeedFiles?: string[];
/** Enables verbose output for debugging */
debug?: boolean;
}
Remote Migration or Seed files
With the introduction of additionalMigrationFiles
and additionalSeedFiles
,
you can now include remote migration and seed files which you can fetch for
example via ftp or using api's like gihub or gitlab. Any input which can be
given to the dynamic import()
can be provided.
...
additionalMigrationFiles: ['https://example.com/some_migration_file.ts'],
...
See the example folder for more examples.
Docker usage
See the specific Nessie image docs for using Nessie with a docker image.
Contributing
All contributions are welcome, make sure to read the contribution guideline.
Uses
- Cliffy
- Deno Postgres
- Deno MySQL - Currently it works with password for 5.*, but for >=8 you have to send a blank password, see issue 37
- Deno SQLite
Examples
See example repo for a REST API which uses Oak and Nessie.
Nessie uses the AbstractMigration
class which you can extend to access the
client and its properties. This enables better flexibility in migrations and
seeds and allows a more complex workflow.
nessie.config.ts
with all default values
import {
ClientPostgreSQL,
NessieConfig,
} from "https://deno.land/x/nessie/mod.ts";
const clientPg = new ClientPostgreSQL({
database: "nessie",
hostname: "localhost",
port: 5432,
user: "root",
password: "pwd",
});
const config: NessieConfig = {
client: clientPg,
migrationFolders: ["./db/migrations"],
seedFolders: ["./db/seeds"],
additionalMigrationFiles: [],
additionalSeedFiles: [],
debug: false,
};
export default config;
Minimal example of a migration file
import {
AbstractMigration,
ClientPostgreSQL,
Info,
} from "https://deno.land/x/nessie/mod.ts";
export default class extends AbstractMigration<ClientPostgreSQL> {
async up({ dialect }: Info): Promise<void> {
await this.client.queryArray("CREATE TABLE table1 (id int)");
}
async down({ dialect }: Info): Promise<void> {
await this.client.queryArray("DROP TABLE table1");
}
}
Seed file
import {
AbstractSeed,
ClientPostgreSQL,
Info,
} from "https://deno.land/x/nessie/mod.ts";
export default class extends AbstractSeed<ClientPostgreSQL> {
async run({ dialect }: Info): Promise<void> {
await this.client.queryArray("INSERT INTO table1 VALUES (1234)");
}
}
See the example folder for more
How to make a client
A client needs to extend AbstractClient.
query
: Takes a query string or array of query strings and sends them of to the
database for execution. Should return whatever the database responds.
prepare
: Will be run when the migration or rollback commands are executed.
This should create the connection, set up the nessie_migrations
table and
prepare the database for incoming migrations.
migrate
: Takes a number as an optional input, will default to all files if not
set. Will run Math.min(amount, numberOfFiles)
migration files. Only handles
the up
method.
rollback
: Takes a number as an optional input, will default to 1 if not set.
Will run Math.min(amount, numberOfFiles)
migration files. Only handles the
down
method.
seed
: Takes an optional matcher as input. Matcher can be regex or string. Will
seed the database. Handles the run
method in seed files.
close
: Will be the last method run before the program is finished. This should
close the database connection.