Use Uuids for id
This commit is contained in:
parent
20af2c82c8
commit
ad6f1454a6
4 changed files with 34 additions and 17 deletions
|
@ -1,10 +1,11 @@
|
|||
const std = @import("std");
|
||||
const util = @import("util");
|
||||
|
||||
const db = @import("./db.zig");
|
||||
|
||||
pub const models = @import("./models.zig");
|
||||
pub const free = db.free;
|
||||
pub const Id = []const u8;
|
||||
pub const Uuid = util.Uuid;
|
||||
|
||||
pub fn CreateInfo(comptime T: type) type {
|
||||
const t_fields = std.meta.fields(T);
|
||||
|
@ -26,7 +27,7 @@ pub fn CreateInfo(comptime T: type) type {
|
|||
} });
|
||||
}
|
||||
|
||||
fn reify(comptime T: type, id: Id, val: CreateInfo(T)) T {
|
||||
fn reify(comptime T: type, id: Uuid, val: CreateInfo(T)) T {
|
||||
var result: T = undefined;
|
||||
result.id = id;
|
||||
inline for (std.meta.fields(CreateInfo(T))) |f| {
|
||||
|
@ -35,23 +36,25 @@ fn reify(comptime T: type, id: Id, val: CreateInfo(T)) T {
|
|||
return result;
|
||||
}
|
||||
|
||||
const ApiServer = struct {
|
||||
pub const ApiServer = struct {
|
||||
db: db.Database,
|
||||
prng: std.rand.DefaultPrng,
|
||||
last_id: u64 = 0,
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) !ApiServer {
|
||||
return ApiServer{
|
||||
.db = try db.Database.init(alloc),
|
||||
.prng = std.rand.DefaultPrng.init(1998),
|
||||
};
|
||||
}
|
||||
|
||||
fn genId(self: *ApiServer, alloc: std.mem.Allocator) ![]const u8 {
|
||||
fn genUuid(self: *ApiServer, alloc: std.mem.Allocator) ![]const u8 {
|
||||
self.last_id += 1;
|
||||
return std.fmt.allocPrint(alloc, "{}", .{self.last_id});
|
||||
}
|
||||
|
||||
pub fn createNote(self: *ApiServer, info: CreateInfo(models.Note), alloc: std.mem.Allocator) !models.Note {
|
||||
const id = try self.genId(alloc);
|
||||
pub fn createNote(self: *ApiServer, info: CreateInfo(models.Note)) !Uuid {
|
||||
const id = Uuid.randV4(self.prng.random());
|
||||
|
||||
const note = reify(models.Note, id, info);
|
||||
try self.db.putNote(note);
|
||||
|
@ -59,7 +62,7 @@ const ApiServer = struct {
|
|||
return id;
|
||||
}
|
||||
|
||||
pub fn getNote(self: *ApiServer, id: Id, alloc: std.mem.Allocator) !?models.Note {
|
||||
pub fn getNote(self: *ApiServer, id: Uuid, alloc: std.mem.Allocator) !?models.Note {
|
||||
return self.db.getNote(id, alloc);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
const std = @import("std");
|
||||
const util = @import("util");
|
||||
const Uuid = util.Uuid;
|
||||
|
||||
const models = @import("./models.zig");
|
||||
const Id = []const u8;
|
||||
|
||||
// Clones a struct and its fields to a single layer of depth.
|
||||
// Caller owns memory, can be freed using free below
|
||||
|
@ -14,8 +15,11 @@ fn clone(alloc: std.mem.Allocator, val: anytype) !@TypeOf(val) {
|
|||
}
|
||||
|
||||
inline for (std.meta.fields(@TypeOf(val))) |f| {
|
||||
// TODO
|
||||
if (f.field_type == []u8 or f.field_type == []const u8) {
|
||||
@field(result, f.name) = try cloneString(alloc, @field(val, f.name));
|
||||
} else if (f.field_type == Uuid) {
|
||||
@field(result, f.name) = @field(val, f.name);
|
||||
} else {
|
||||
@compileError("unsupported field type " ++ @typeName(f.field_type));
|
||||
}
|
||||
|
@ -33,8 +37,11 @@ fn cloneString(alloc: std.mem.Allocator, str: []const u8) ![]const u8 {
|
|||
// Frees a struct and its fields returned by clone
|
||||
pub fn free(alloc: std.mem.Allocator, val: anytype) void {
|
||||
inline for (std.meta.fields(@TypeOf(val))) |f| {
|
||||
// TODO
|
||||
if (f.field_type == []u8 or f.field_type == []const u8) {
|
||||
alloc.free(@field(val, f.name));
|
||||
} else if (f.field_type == Uuid) {
|
||||
// nothing
|
||||
} else {
|
||||
@compileError("unsupported field type " ++ @typeName(f.field_type));
|
||||
}
|
||||
|
@ -43,16 +50,16 @@ pub fn free(alloc: std.mem.Allocator, val: anytype) void {
|
|||
|
||||
pub const Database = struct {
|
||||
internal_alloc: std.mem.Allocator,
|
||||
notes: std.StringHashMap(models.Note),
|
||||
notes: std.AutoHashMap(Uuid, models.Note),
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) !Database {
|
||||
var db = Database{
|
||||
.internal_alloc = alloc,
|
||||
.notes = std.StringHashMap(models.Note).init(alloc),
|
||||
.notes = std.AutoHashMap(Uuid, models.Note).init(alloc),
|
||||
};
|
||||
|
||||
try db.putNote(models.Note{
|
||||
.id = "1",
|
||||
.id = Uuid{ .data = @bitCast([16]u8, @as(u128, 1)) },
|
||||
.content = "abcd",
|
||||
});
|
||||
|
||||
|
@ -68,13 +75,13 @@ pub const Database = struct {
|
|||
self.notes.deinit();
|
||||
}
|
||||
|
||||
pub fn containsNote(self: *Database, id: Id) !bool {
|
||||
pub fn containsNote(self: *Database, id: Uuid) !bool {
|
||||
return self.notes.contains(id);
|
||||
}
|
||||
|
||||
// returns a copy of the note data from storage. memory is allocated with the provided
|
||||
// allocator. can be freed using free() above
|
||||
pub fn getNote(self: *Database, id: Id, alloc: std.mem.Allocator) !?models.Note {
|
||||
pub fn getNote(self: *Database, id: Uuid, alloc: std.mem.Allocator) !?models.Note {
|
||||
const note = self.notes.get(id) orelse return null;
|
||||
return try clone(alloc, note);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const http = @import("http");
|
||||
const util = @import("util");
|
||||
|
||||
const api = @import("./api.zig");
|
||||
const models = @import("./models.zig");
|
||||
const Uuid = util.Uuid;
|
||||
|
||||
// this thing is overcomplicated and weird. stop this
|
||||
const Router = http.Router(*RequestServer);
|
||||
|
@ -50,15 +53,17 @@ fn createNote(srv: *RequestServer, ctx: *http.server.Context, _: RouteArgs) !voi
|
|||
const body = ctx.request.body orelse return respondJson(ctx, .bad_request, .{ .@"error" = "no note body provided" }, srv.alloc);
|
||||
var tokens = std.json.TokenStream.init(body);
|
||||
const note = try std.json.parse(api.CreateInfo(models.Note), &tokens, .{ .allocator = srv.alloc });
|
||||
defer std.json.parseFree(models.Note, note, .{ .allocator = srv.alloc });
|
||||
defer std.json.parseFree(api.CreateInfo(models.Note), note, .{ .allocator = srv.alloc });
|
||||
|
||||
try srv.api.createNote(note);
|
||||
// TODO
|
||||
_ = try srv.api.createNote(note);
|
||||
|
||||
try respondJson(ctx, .created, note, srv.alloc);
|
||||
}
|
||||
|
||||
fn getNote(srv: *RequestServer, ctx: *http.server.Context, args: RouteArgs) !void {
|
||||
const id = args.get("id") orelse return error.NotFound;
|
||||
const id_str = args.get("id") orelse return error.NotFound;
|
||||
const id = Uuid.parse(id_str) catch return respondJson(ctx, .bad_request, .{ .@"error" = "invalid id" }, srv.alloc);
|
||||
const note = (try srv.api.getNote(id, srv.alloc)) orelse return error.NotFound;
|
||||
defer api.free(srv.alloc, note);
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
const Uuid = @import("util").Uuid;
|
||||
|
||||
pub const Note = struct {
|
||||
id: []const u8,
|
||||
id: Uuid,
|
||||
content: []const u8,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue