feat(tempalte): ziex with postgres

This commit is contained in:
Nurul Huda (Apon) 2026-03-21 19:43:39 +06:00
parent 75595b8dd2
commit 3dfd125b9b
No known key found for this signature in database
GPG Key ID: 5D3F1DE2855A2F79
10 changed files with 266 additions and 0 deletions

11
templates/.gitignore vendored
View File

@ -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

3
templates/database-pg/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.zig-cache/
zig-out/
node_modules/

View File

@ -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/)

View File

@ -0,0 +1,3 @@
const Database = @import("db/Database.zig");
db: Database

View File

@ -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();
}

View File

@ -0,0 +1,5 @@
-- Initialize the database schema
CREATE TABLE IF NOT EXISTS ziex (
id SERIAL PRIMARY KEY,
count BIGINT NOT NULL
);

View File

@ -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;

View File

@ -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 (
<main @allocator={ctx.arena}>
<p>Ziex is a framework for building web applications with Zig.</p>
<a href={zx.info.homepage} target="_blank">See Ziex Docs </a>
<br />
<CounterComponent @rendering={.client} count={count} />
<br />
<hr />
<a href="/about">Navigate to About Page</a>
</main>
);
}
var count: i64 = 0;
const zx = @import("zx");
pub const CounterComponent = @import("./client.zig").CounterComponent;

View File

@ -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, .{});
}

View File

@ -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",
},
}