diff --git a/templates/.gitignore b/templates/.gitignore index c5f93722..c50eb7de 100644 --- a/templates/.gitignore +++ b/templates/.gitignore @@ -41,3 +41,14 @@ node_modules/ !starter/.gitignore !starter/package.json !starter/build.zig + +# database-pg template +!database-pg/.gitignore +!database-pg/build.zig +!database-pg/build.zig.zon +!database-pg/README.md +!database-pg/app/Context.zig +!database-pg/app/db/**/* +!database-pg/app/main.zig +!database-pg/app/pages/page.zx + diff --git a/templates/database-pg/.gitignore b/templates/database-pg/.gitignore new file mode 100644 index 00000000..2d7873eb --- /dev/null +++ b/templates/database-pg/.gitignore @@ -0,0 +1,3 @@ +.zig-cache/ +zig-out/ +node_modules/ diff --git a/templates/database-pg/README.md b/templates/database-pg/README.md new file mode 100644 index 00000000..bb29582b --- /dev/null +++ b/templates/database-pg/README.md @@ -0,0 +1,95 @@ +# Ziex App with Postgres + +>This is a starter template for building web applications with [Ziex](https://ziex.dev), a full-stack web framework for Zig. + +**[Documentation →](https://ziex.dev)** + +## Getting Started + +### 1. Install ZX CLI + +#### Linux/macOS +```bash +curl -fsSL https://ziex.dev/install | bash +``` + +#### Windows +```powershell +powershell -c "irm ziex.dev/install.ps1 | iex" +``` + +### 2. Install Zig +```bash +brew install zig # macOS +winget install -e --id zig.zig # Windows +``` +[_Other platforms →_](https://ziglang.org/learn/getting-started/) + + +## Project + +``` +├── app/ +│ ├── assets/ # Static assets (CSS, images, etc) +│ ├── main.zig # Zig entrypoint +│ ├── pages/ # Pages (Zig/ZX) +│ │ ├── layout.zx # Root layout +│ │ ├── page.zx # Home page +│ │ ├── client.zx # Client side counter component +│ │ └── ... +│ └── public/ # Public static files (favicon, etc) +├── build.zig # Zig build script +├── build.zig.zon # Zig package manager config +└── README.md # Project info +``` + +## Usage + +### Development +```bash +zig build dev +``` +App will be available at [`http://localhost:3000`](http://localhost:3000). with hot reload enabled. + +### Serve Production Build +```bash +zig build serve --release=fast +``` + +### Exporting as Static Site +```bash +zig build zx -- export +``` +This will create a `dist/` directory with the static export of your app. You can deploy the contents of `dist/` to any static hosting provider (Netlify, Vercel, GitHub Pages, etc) or serve it with any static file server. + +### Deployment + +```bash +zig build zx -- bundle +``` + +This will create a `bundle/` directory with the binary and static assets needed to run your app. You can deploy the contents of `bundle/` to any VPS. + + +### [ZX CLI](https://ziex.dev/reference#cli) Commands +```bash +zig build zx -- [command] [options] +``` + +All ZX CLI commands are available under `zig build zx -- [command]`. For example, to run auto formatter: +```bash +zig build zx -- fmt . +``` + +## Contributing + +Contributions are welcome! Feel free to open issues or pull requests. For feature requests, bug reports, or questions, see the [Ziex Repo](https://github.com/ziex-dev/ziex). + +## Links + +- [Documentation](https://ziex.dev) +- [Discord](https://ziex.dev/r/discord) +- [Topic on Ziggit](https://ziex.dev/r/ziggit) +- [Project on Zig Discord Community](https://ziex.dev/r/zig-discord) (Join Zig Discord first: https://discord.gg/zig) +- [GitHub](https://github.com/nurulhudaapon/ziex) +- [Zig Language](https://ziglang.org/) \ No newline at end of file diff --git a/templates/database-pg/app/Context.zig b/templates/database-pg/app/Context.zig new file mode 100644 index 00000000..285f31f3 --- /dev/null +++ b/templates/database-pg/app/Context.zig @@ -0,0 +1,3 @@ +const Database = @import("db/Database.zig"); + +db: Database diff --git a/templates/database-pg/app/db/Database.zig b/templates/database-pg/app/db/Database.zig new file mode 100644 index 00000000..e5fc99bc --- /dev/null +++ b/templates/database-pg/app/db/Database.zig @@ -0,0 +1,41 @@ +const std = @import("std"); +const pg = @import("pg"); + +const Database = @This(); + +pool: *pg.Pool, + +pub fn getCount(self: Database) !i64 { + var result = try self.pool.query("SELECT count FROM ziex", .{}); + defer result.deinit(); + + if (try result.next()) |row| + return row.get(i64, 0); + + _ = try self.pool.exec("INSERT INTO ziex (count) VALUES (0)", .{}); + return 0; +} + +pub fn setCount(self: Database, count: i64) !void { + _ = try self.pool.exec("UPDATE ziex SET count = $1", .{count}); +} + +pub fn setup(self: Database) !void { + _ = try self.pool.exec(@embedFile("migrations/init.sql"), .{}); +} + +pub fn init(allocator: std.mem.Allocator, uri: []const u8) !Database { + if (uri.len == 0) return error.InvalidDatabaseUrl; + + const pgUri = try std.Uri.parse(uri); + std.log.info("DB: {s}", .{try pgUri.getHostAlloc(allocator)}); + const pool = try pg.Pool.initUri(allocator, pgUri, .{ .size = 4 }); + + const db: Database = .{ .pool = pool }; + try db.setup(); + return db; +} + +pub fn deinit(self: *Database) void { + self.db_pool.deinit(); +} diff --git a/templates/database-pg/app/db/migrations/init.sql b/templates/database-pg/app/db/migrations/init.sql new file mode 100644 index 00000000..32e09d20 --- /dev/null +++ b/templates/database-pg/app/db/migrations/init.sql @@ -0,0 +1,5 @@ +-- Initialize the database schema +CREATE TABLE IF NOT EXISTS ziex ( + id SERIAL PRIMARY KEY, + count BIGINT NOT NULL +); \ No newline at end of file diff --git a/templates/database-pg/app/main.zig b/templates/database-pg/app/main.zig new file mode 100644 index 00000000..2369d4c9 --- /dev/null +++ b/templates/database-pg/app/main.zig @@ -0,0 +1,24 @@ +const std = @import("std"); +const zx = @import("zx"); +const Context = @import("Context.zig"); + +pub fn main() !void { + if (zx.platform == .browser) return zx.Client.run(); + if (zx.platform == .edge) return zx.Edge.run(); + + var gpa = std.heap.DebugAllocator(.{}){}; + const allocator = gpa.allocator(); + defer _ = gpa.deinit(); + + const db_uri = std.process.getEnvVarOwned(allocator, "DATABASE_URL") catch + "postgresql://postgres:db_password@localhost:5432/ziex"; + + var ctx: Context = .{ .db = try .init(allocator, db_uri) }; + const app = try zx.Server(*Context).init(allocator, .{}, &ctx); + defer app.deinit(); + + app.info(); + try app.start(); +} + +pub const std_options = zx.std_options; diff --git a/templates/database-pg/app/pages/page.zx b/templates/database-pg/app/pages/page.zx new file mode 100644 index 00000000..55c58f6e --- /dev/null +++ b/templates/database-pg/app/pages/page.zx @@ -0,0 +1,37 @@ +pub const options = zx.PageOptions{ .methods = &.{ .GET, .POST } }; +const Context = @import("../Context.zig"); + +pub fn Page(ctx: zx.PageCtx(Context, void)) zx.Component { + const query = ctx.request.searchParams; + + count = ctx.app.db.getCount() catch -1; + + if (query.get("reset")) |_| + count = 0 + else if (query.get("increment")) |_| + count += 1 + else if (query.get("decrement")) |_| + count -= 1 + else + count += 1; + + ctx.app.db.setCount(count) catch |err| { + zx.log.err("setting {s}", .{@errorName(err)}); + }; + + return ( +
+

Ziex is a framework for building web applications with Zig.

+ See Ziex Docs → +
+ +
+
+ Navigate to About Page +
+ ); +} +var count: i64 = 0; + +const zx = @import("zx"); +pub const CounterComponent = @import("./client.zig").CounterComponent; diff --git a/templates/database-pg/build.zig b/templates/database-pg/build.zig new file mode 100644 index 00000000..19499ea4 --- /dev/null +++ b/templates/database-pg/build.zig @@ -0,0 +1,27 @@ +const std = @import("std"); +const zx = @import("zx"); + +pub fn build(b: *std.Build) !void { + // --- Target and Optimize from `zig build` arguments --- + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + // -- Modules -- // + const pg_module = b.dependency("pg", .{}).module("pg"); + + // --- ZX App Executable --- + const app_exe = b.addExecutable(.{ + .name = "ziex_app", + .root_module = b.createModule(.{ + .root_source_file = b.path("app/main.zig"), + .target = target, + .optimize = optimize, + .imports = &.{ + .{ .name = "pg", .module = pg_module }, + }, + }), + }); + + // --- ZX setup: wires dependencies and adds `zx`/`dev` build steps --- + _ = try zx.init(b, app_exe, .{}); +} diff --git a/templates/database-pg/build.zig.zon b/templates/database-pg/build.zig.zon new file mode 100644 index 00000000..317fa5f1 --- /dev/null +++ b/templates/database-pg/build.zig.zon @@ -0,0 +1,20 @@ +.{ + .name = .ziex_app, + .version = "0.0.0", + .fingerprint = 0x7246d8c908f650a4, + .minimum_zig_version = "0.15.2", + .dependencies = .{ + .zx = .{ + .path = "../../", + }, + .pg = .{ + .url = "git+https://github.com/karlseguin/pg.zig?ref=master#e58b318b7867ef065b3135983f829219c5eef891", + .hash = "pg-0.0.0-Wp_7gXFoBgD0fQ72WICKa-bxLga03AXXQ3BbIsjjohQ3", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "app", + }, +}