Initial comit / Pre db simplification
This commit is contained in:
commit
54d504c3de
|
@ -0,0 +1,3 @@
|
||||||
|
* text=auto
|
||||||
|
*.zig text eol=lf
|
||||||
|
zigmod.* text eol=lf
|
|
@ -0,0 +1,3 @@
|
||||||
|
zig-*
|
||||||
|
.zigmod
|
||||||
|
deps.zig
|
|
@ -0,0 +1,39 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.build.Builder) void {
|
||||||
|
// Standard target options allows the person running `zig build` to choose
|
||||||
|
// what target to build for. Here we do not override the defaults, which
|
||||||
|
// means any target is allowed, and the default is native. Other options
|
||||||
|
// for restricting supported target set are available.
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
|
||||||
|
// Standard release options allow the person running `zig build` to select
|
||||||
|
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
||||||
|
const mode = b.standardReleaseOptions();
|
||||||
|
|
||||||
|
// Import autogenerated zigmod dependencies
|
||||||
|
const deps = @import("deps.zig");
|
||||||
|
|
||||||
|
const exe = b.addExecutable("uos", "src/main.zig");
|
||||||
|
exe.use_stage1 = true; // for sqlite
|
||||||
|
deps.addAllTo(exe); // zigmod dependencies
|
||||||
|
exe.setTarget(target);
|
||||||
|
exe.setBuildMode(mode);
|
||||||
|
exe.install();
|
||||||
|
|
||||||
|
const run_cmd = exe.run();
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
|
||||||
|
const exe_tests = b.addTest("src/main.zig");
|
||||||
|
exe_tests.setTarget(target);
|
||||||
|
exe_tests.setBuildMode(mode);
|
||||||
|
|
||||||
|
const test_step = b.step("test", "Run unit tests");
|
||||||
|
test_step.dependOn(&exe_tests.step);
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const sqlite = @import("sqlite");
|
||||||
|
|
||||||
|
const ObjectError = error{
|
||||||
|
IncompatibleObjectType, // No ?u32 "id" field
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn persist(db: *sqlite.Db, obj: anytype) !void {
|
||||||
|
const T = @TypeOf(obj);
|
||||||
|
|
||||||
|
// Check that object is a valid type for the DB system.
|
||||||
|
// It should have an "id" field and be of type "?u32"
|
||||||
|
if (!@hasField(T, "id") or @TypeOf(@field(obj, "id")) != ?u32) {
|
||||||
|
return ObjectError.IncompatibleObjectType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tried to persist something that is already persisted
|
||||||
|
if (@field(obj, "id") != null) {
|
||||||
|
std.debug.print("Can't persist an object with an id.\n", .{});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = std.meta.fields(T);
|
||||||
|
|
||||||
|
const query_init = "INSTERT INTO " ++ @typeName(T) ++ " (";
|
||||||
|
|
||||||
|
const sep = ", ";
|
||||||
|
var buf: [1024]u8 = .{0} ** 1024;
|
||||||
|
var offset: usize = 0;
|
||||||
|
|
||||||
|
std.mem.copy(u8, buf[offset..], query_init);
|
||||||
|
offset += query_init.len;
|
||||||
|
|
||||||
|
// Keep track of how many fields to instert
|
||||||
|
comptime var count: u8 = 0;
|
||||||
|
inline for (fields) |field_i| {
|
||||||
|
// Do not input "id" field.
|
||||||
|
comptime if (std.mem.eql(u8, field_i.name, "id")) {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Do not input array fields (they got their own table)
|
||||||
|
comptime switch (@typeInfo(field_i.field_type)) {
|
||||||
|
.Array => continue,
|
||||||
|
.Pointer => |info| switch (info.size) {
|
||||||
|
.One => {},
|
||||||
|
.Many, .C, .Slice => continue,
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
count += 1;
|
||||||
|
|
||||||
|
std.mem.copy(u8, buf[offset..], field_i.name);
|
||||||
|
offset += field_i.name.len;
|
||||||
|
std.mem.copy(u8, buf[offset..], sep);
|
||||||
|
offset += sep.len;
|
||||||
|
}
|
||||||
|
offset -= sep.len;
|
||||||
|
|
||||||
|
const query_end = ") VALUES (" ++ ("?, " ** (count - 1)) ++ "?);";
|
||||||
|
|
||||||
|
std.mem.copy(u8, buf[offset..], query_end);
|
||||||
|
offset += query_end.len;
|
||||||
|
|
||||||
|
std.debug.print("{s}\n", .{buf[0..offset]});
|
||||||
|
|
||||||
|
_ = db;
|
||||||
|
|
||||||
|
//const query = "INSERT INTO item (name) VALUES (?);";
|
||||||
|
|
||||||
|
//try db.exec(query, .{}, .{ .name = name });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn queryTest(db: *sqlite.Db) ![]const u8 {
|
||||||
|
const row = try db.one(
|
||||||
|
struct {
|
||||||
|
version: [128:0]u8,
|
||||||
|
},
|
||||||
|
"SELECT sqlite_version();",
|
||||||
|
.{},
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (row) |row_i| {
|
||||||
|
return std.mem.sliceTo(&row_i.version, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() !sqlite.Db {
|
||||||
|
var db = try sqlite.Db.init(.{
|
||||||
|
.mode = .{ .File = "/tmp/data.db" },
|
||||||
|
.open_flags = .{
|
||||||
|
.write = true,
|
||||||
|
.create = true,
|
||||||
|
},
|
||||||
|
.threading_mode = .MultiThread,
|
||||||
|
});
|
||||||
|
|
||||||
|
try migrate(&db);
|
||||||
|
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Make a proper migration system.
|
||||||
|
fn migrate(db: *sqlite.Db) !void {
|
||||||
|
try db.exec(
|
||||||
|
\\ CREATE TABLE IF NOT EXISTS item (
|
||||||
|
\\ id INTEGER PRIMARY KEY,
|
||||||
|
\\ name TEXT NOT NULL
|
||||||
|
\\ );
|
||||||
|
\\
|
||||||
|
\\ CREATE TABLE IF NOT EXISTS tag (
|
||||||
|
\\ id INTEGER PRIMARY KEY,
|
||||||
|
\\ name TEXT NOT NULL
|
||||||
|
\\ );
|
||||||
|
\\
|
||||||
|
\\ CREATE TABLE IF NOT EXISTS item_tag (
|
||||||
|
\\ item INTEGER,
|
||||||
|
\\ tag INTEGER,
|
||||||
|
\\
|
||||||
|
\\ PRIMARY KEY (item, tag),
|
||||||
|
\\
|
||||||
|
\\ FOREIGN KEY (item) REFERENCES item(id) ON DELETE CASCADE,
|
||||||
|
\\ FOREIGN KEY (tag) REFERENCES tag(id) ON DELETE CASCADE
|
||||||
|
\\ );
|
||||||
|
,
|
||||||
|
.{},
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const Db = @import("Db.zig");
|
||||||
|
const Tag = @import("Tag.zig");
|
||||||
|
|
||||||
|
id: ?u32, // If null, the object hasn't been persisted
|
||||||
|
name: []const u8,
|
||||||
|
tags: ?[]Tag,
|
|
@ -0,0 +1,7 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const Db = @import("Db.zig");
|
||||||
|
const Item = @import("Item.zig");
|
||||||
|
|
||||||
|
id: ?u32,
|
||||||
|
name: []const u8,
|
||||||
|
items: ?[]Item,
|
|
@ -0,0 +1,15 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const sqlite = @import("sqlite");
|
||||||
|
|
||||||
|
const Db = @import("Db.zig");
|
||||||
|
const Item = @import("Item.zig");
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var db = try Db.init();
|
||||||
|
|
||||||
|
const item = Item{ .name = "hola", .id = null, .tags = null };
|
||||||
|
try Db.persist(&db, item);
|
||||||
|
|
||||||
|
const version = try Db.queryTest(&db);
|
||||||
|
std.debug.print("Version: {s}\n", .{version});
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
2
|
||||||
|
git https://github.com/getty-zig/json commit-0c2e645fc1304ab57f9819445b91ea064da0b27b
|
||||||
|
git https://github.com/getty-zig/getty commit-102f17a
|
||||||
|
git https://github.com/ibokuri/concepts commit-05c7368
|
||||||
|
git https://github.com/vrischmann/zig-sqlite commit-5b8b472276829f75dced4dc405b66b7b986498b3
|
|
@ -0,0 +1,7 @@
|
||||||
|
id: xstmgop7lwvcrkd18q3u95noqfk3oromr3vixj1ud67rhbwl
|
||||||
|
name: uos
|
||||||
|
license: AGPLv3
|
||||||
|
description: Tagging system with a JSON API
|
||||||
|
root_dependencies:
|
||||||
|
- src: git https://github.com/vrischmann/zig-sqlite branch-master
|
||||||
|
- src: git https://github.com/getty-zig/json
|
Loading…
Reference in New Issue