diff --git a/build.zig b/build.zig index 95620a6..3cdae76 100644 --- a/build.zig +++ b/build.zig @@ -2,13 +2,6 @@ const std = @import("std"); pub const Routes = @import("src/Routes.zig"); pub const GenerateMimeTypes = @import("src/GenerateMimeTypes.zig"); -// pub const TemplateFn = @import("src/jetzig.zig").TemplateFn; -// pub const StaticRequest = @import("src/jetzig.zig").StaticRequest; -// pub const http = @import("src/jetzig/http.zig"); -// pub const data = @import("src/jetzig/data.zig"); -// pub const views = @import("src/jetzig/views.zig"); -// pub const Route = views.Route; -// pub const Job = @import("src/jetzig.zig").Job; const zmpl_build = @import("zmpl"); @@ -70,6 +63,8 @@ pub fn build(b: *std.Build) !void { b.modules.put("zmpl", zmpl_dep.module("zmpl")) catch @panic("Out of memory"); b.modules.put("zmd", zmd_dep.module("zmd")) catch @panic("Out of memory"); b.modules.put("pg", pg_dep.module("pg")) catch @panic("Out of memory"); + b.modules.put("jetquery", jetquery_dep.module("jetquery")) catch @panic("Out of memory"); + b.modules.put("jetquery_migrate", jetquery_dep.module("jetquery_migrate")) catch @panic("Out of memory"); jetquery_dep.module("jetquery").addImport("pg", pg_dep.module("pg")); const smtp_client_dep = b.dependency("smtp_client", .{ @@ -135,6 +130,8 @@ pub fn jetzigInit(b: *std.Build, exe: *std.Build.Step.Compile, options: JetzigIn const zmpl_module = jetzig_dep.module("zmpl"); const zmd_module = jetzig_dep.module("zmd"); const pg_module = jetzig_dep.module("pg"); + const jetquery_module = jetzig_dep.module("jetquery"); + const jetquery_migrate_module = jetzig_dep.module("jetquery_migrate"); exe.root_module.addImport("jetzig", jetzig_module); exe.root_module.addImport("zmpl", zmpl_module); @@ -271,10 +268,23 @@ pub fn jetzigInit(b: *std.Build, exe: *std.Build.Step.Compile, options: JetzigIn const routes_step = b.step("jetzig:routes", "List all routes in your app"); const exe_routes = b.addExecutable(.{ .name = "routes", - .root_source_file = jetzig_dep.path("src/routes_exe.zig"), + .root_source_file = jetzig_dep.path("src/commands/routes.zig"), .target = target, .optimize = optimize, }); + + const migrate_step = b.step("jetzig:migrate", "Migrate your app's database"); + const exe_migrate = b.addExecutable(.{ + .name = "migrate", + .root_source_file = jetzig_dep.path("src/commands/migrate.zig"), + .target = target, + .optimize = optimize, + }); + exe_migrate.root_module.addImport("jetquery", jetquery_module); + exe_migrate.root_module.addImport("jetquery_migrate", jetquery_migrate_module); + const run_migrate_cmd = b.addRunArtifact(exe_migrate); + migrate_step.dependOn(&run_migrate_cmd.step); + exe_routes.root_module.addImport("jetzig", jetzig_module); exe_routes.root_module.addImport("routes", routes_module); exe_routes.root_module.addImport("app", &exe.root_module); diff --git a/cli/build.zig b/cli/build.zig index f34154e..5e5fe0f 100644 --- a/cli/build.zig +++ b/cli/build.zig @@ -20,6 +20,7 @@ pub fn build(b: *std.Build) !void { .jetquery_migrations_path = @as([]const u8, "src/app/database/migrations"), }); exe.root_module.addImport("jetquery", jetquery_dep.module("jetquery")); + exe.root_module.addImport("jetquery_migrate", jetquery_dep.module("jetquery_migrate")); exe.root_module.addImport("args", zig_args_dep.module("args")); exe.root_module.addImport( diff --git a/cli/cli.zig b/cli/cli.zig index 00be41d..0e88616 100644 --- a/cli/cli.zig +++ b/cli/cli.zig @@ -7,6 +7,7 @@ const server = @import("commands/server.zig"); const routes = @import("commands/routes.zig"); const bundle = @import("commands/bundle.zig"); const tests = @import("commands/tests.zig"); +const database = @import("commands/database.zig"); const Options = struct { help: bool = false, @@ -25,6 +26,7 @@ const Options = struct { .routes = "List all routes in your app", .bundle = "Create a deployment bundle", .@"test" = "Run app tests", + .database = "Manage the application's database", .help = "Print help and exit", }, }; @@ -38,11 +40,13 @@ const Verb = union(enum) { routes: routes.Options, bundle: bundle.Options, @"test": tests.Options, + database: database.Options, g: generate.Options, s: server.Options, r: routes.Options, b: bundle.Options, t: tests.Options, + d: database.Options, }; /// Main entrypoint for `jetzig` executable. Parses command line args and generates a new @@ -76,6 +80,7 @@ pub fn main() !void { \\ server Run a development server. \\ routes List all routes in your app. \\ bundle Create a deployment bundle. + \\ database Manage the application's database. \\ test Run app tests. \\ \\ Pass --help to any command for more information, e.g. `jetzig init --help` @@ -136,6 +141,13 @@ fn run(allocator: std.mem.Allocator, options: args.ParseArgsResult(Options, Verb options.positionals, .{ .help = options.options.help }, ), + .d, .database => |opts| database.run( + allocator, + opts, + writer, + options.positionals, + .{ .help = options.options.help }, + ), }; } } diff --git a/cli/commands/database.zig b/cli/commands/database.zig new file mode 100644 index 0000000..23efb90 --- /dev/null +++ b/cli/commands/database.zig @@ -0,0 +1,39 @@ +const std = @import("std"); +const args = @import("args"); +const util = @import("../util.zig"); +const jetquery = @import("jetquery"); +const Migrate = @import("jetquery_migrate"); + +/// Command line options for the `database` command. +pub const Options = struct { + pub const meta = .{ + .usage_summary = "[migrate]", + .full_text = + \\Manage the application's database. + \\ + \\Pass `--help` to any command for more information, e.g.: + \\ + \\ jetzig database migrate --help + \\ + , + }; +}; + +/// Run the `jetzig generate` command. +pub fn run( + allocator: std.mem.Allocator, + options: Options, + writer: anytype, + positionals: [][]const u8, + other_options: struct { help: bool }, +) !void { + _ = options; + _ = writer; + _ = positionals; + _ = other_options; + try util.execCommand(allocator, &.{ + "zig", + "build", + "jetzig:migrate", + }); +} diff --git a/cli/commands/generate.zig b/cli/commands/generate.zig index b5c971a..bc2917b 100644 --- a/cli/commands/generate.zig +++ b/cli/commands/generate.zig @@ -46,34 +46,17 @@ pub fn run( var available_buf = std.ArrayList([]const u8).init(allocator); defer available_buf.deinit(); - // XXX: 0.12 Compatibility - const map = if (@hasDecl(std, "ComptimeStringMap")) blk: { - const inner_map = std.ComptimeStringMap(Generator, .{ - .{ "view", .view }, - .{ "partial", .partial }, - .{ "layout", .layout }, - .{ "job", .job }, - .{ "mailer", .mailer }, - .{ "middleware", .middleware }, - .{ "secret", .secret }, - .{ "migration", .migration }, - }); - for (inner_map.kvs) |kv| try available_buf.append(kv.key); - break :blk inner_map; - } else if (@hasDecl(std, "StaticStringMap")) blk: { - const inner_map = std.StaticStringMap(Generator).initComptime(.{ - .{ "view", .view }, - .{ "partial", .partial }, - .{ "layout", .layout }, - .{ "job", .job }, - .{ "mailer", .mailer }, - .{ "middleware", .middleware }, - .{ "secret", .secret }, - .{ "migration", .migration }, - }); - for (inner_map.keys()) |key| try available_buf.append(key); - break :blk inner_map; - } else unreachable; + const map = std.StaticStringMap(Generator).initComptime(.{ + .{ "view", .view }, + .{ "partial", .partial }, + .{ "layout", .layout }, + .{ "job", .job }, + .{ "mailer", .mailer }, + .{ "middleware", .middleware }, + .{ "secret", .secret }, + .{ "migration", .migration }, + }); + for (map.keys()) |key| try available_buf.append(key); const available_help = try std.mem.join(allocator, "|", available_buf.items); defer allocator.free(available_help); diff --git a/src/commands/migrate.zig b/src/commands/migrate.zig new file mode 100644 index 0000000..7ef07fd --- /dev/null +++ b/src/commands/migrate.zig @@ -0,0 +1,35 @@ +const std = @import("std"); + +const jetquery = @import("jetquery"); +const Migrate = @import("jetquery_migrate"); +// const migrations = @import("migrations").migrations; + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer std.debug.assert(gpa.deinit() == .ok); + + const gpa_allocator = gpa.allocator(); + var arena = std.heap.ArenaAllocator.init(gpa_allocator); + defer arena.deinit(); + + const allocator = arena.allocator(); + + var repo = try jetquery.Repo.init( + allocator, + .{ + .adapter = .{ + .postgresql = .{ + .database = "postgres", + .username = "postgres", + .hostname = "127.0.0.1", + .password = "password", + .port = 5432, + }, + }, + }, + ); + defer repo.deinit(); + + const migrate = Migrate.init(&repo); + try migrate.run(); +} diff --git a/src/routes_exe.zig b/src/commands/routes.zig similarity index 100% rename from src/routes_exe.zig rename to src/commands/routes.zig