Use Uuids for id

This commit is contained in:
jaina heartles 2022-07-12 21:16:33 -07:00
parent 20af2c82c8
commit ad6f1454a6
4 changed files with 34 additions and 17 deletions

View file

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

View file

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

View file

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

View file

@ -1,4 +1,6 @@
const Uuid = @import("util").Uuid;
pub const Note = struct {
id: []const u8,
id: Uuid,
content: []const u8,
};