Migrations
JetQuery provides a framework for managing database migrations.
The table jetquery_migrations is used to track pending/applied migrations. This table is automatically created the first time you run a migration.
The details below cover how migrations work and the structure of a migration file. It is recommended to use the Command Line Tools to create and run migrations.
Migration Format
A migration is file named with a timestamp prefix followed by an underscore and an arbitrary string with a .zig extension. Jetzig migrations are located in src/app/database/migrations/.
A migration file contains two Zig functions:
- up
- down
Both functions receive a Repo which is then used to issue Data Definition Language (DDL) commands.
These functions can be used anywhere that you have access to a Repo. It is recommended that you limit migrations to DDL commands but there are no hard restrictions on how you use the Repo within a migration.
up
The up function is called when a migration is applied. Use this function to create tables and indexes.
down
The down function is called when a migration is rolled back. This function should undo the changes introduced by up, e.g. if you create a table in up then you should drop the table in down.
Example Migration
The following example is taken from this website's migrations:
const std = @import("std");
const jetquery = @import("jetquery");
const t = jetquery.schema.table;
pub fn up(repo: anytype) !void {
try repo.createTable(
"blogs",
&.{
t.primaryKey("id", .{}),
t.column("title", .string, .{ .unique = true }),
t.column("content", .text, .{}),
t.timestamps(.{}),
},
.{},
);
}
pub fn down(repo: anytype) !void {
try repo.dropTable("blogs", .{});
}
createTable
pub fn createTable(
self: *AdaptedRepo,
comptime name: []const u8,
comptime columns: []const jetquery.schema.Column,
comptime options: jetquery.CreateTableOptions,
) !void
Pass a table name, a slice of column definitions, and options.
Options
pub const CreateTableOptions = struct { if_not_exists: bool = false };
column
pub fn column(
name: []const u8,
column_type: Column.Type,
options: Column.Options,
) Column
Options
pub const Options = struct {
optional: bool = false, // Specify a `NOT NULL` constraint when `false`
index: bool = false, // Create an index when `true`
index_name: ?[]const u8 = null, // Override auto-generated index name
unique: bool = false, // Apply a unique constraint when `true`
reference: ?Reference = null, // Create a foreign key, e.g. `.{"blogs", "id"}`
length: ?u16 = null, // Specify column length (string columns default to `255`)
};
dropTable
pub fn dropTable(
self: *AdaptedRepo,
comptime name: []const u8,
comptime options: jetquery.DropTableOptions,
) !void
Options
pub const DropTableOptions = struct { if_exists: bool = false };
alterTable
pub fn alterTable(
self: *AdaptedRepo,
comptime name: []const u8,
comptime options: jetquery.AlterTableOptions,
) !void
Options
pub const AlterTableOptions = struct {
columns: AlterTableColumnOptions = .{},
rename: ?[]const u8 = null,
pub const AlterTableColumnOptions = struct {
add: []const schema.Column = &.{},
drop: []const []const u8 = &.{},
rename: ?RenameColumn = null,
pub const RenameColumn = struct { from: []const u8, to: []const u8 };
};
};
createDatabase
pub fn createDatabase(
self: *AdaptedRepo,
comptime name: []const u8,
options: struct {},
) !void
dropDatabase
pub fn dropDatabase(
self: *AdaptedRepo,
comptime name: []const u8,
options: jetquery.DropDatabaseOptions,
) !void
Options
pub const DropDatabaseOptions = struct { if_exists: bool = false };