Add createNote endpoint
This commit is contained in:
parent
d8f8a3ec89
commit
255a11bc8b
2 changed files with 72 additions and 6 deletions
|
@ -15,9 +15,7 @@ fn clone(alloc: std.mem.Allocator, val: anytype) !@TypeOf(val) {
|
||||||
|
|
||||||
inline for (std.meta.fields(@TypeOf(val))) |f| {
|
inline for (std.meta.fields(@TypeOf(val))) |f| {
|
||||||
if (f.field_type == []u8 or f.field_type == []const u8) {
|
if (f.field_type == []u8 or f.field_type == []const u8) {
|
||||||
var copy = try alloc.alloc(u8, @field(val, f.name).len);
|
@field(result, f.name) = try cloneString(alloc, @field(val, f.name));
|
||||||
std.mem.copy(u8, copy, @field(val, f.name));
|
|
||||||
@field(result, f.name) = copy;
|
|
||||||
} else {
|
} else {
|
||||||
@compileError("unsupported field type " ++ @typeName(f.field_type));
|
@compileError("unsupported field type " ++ @typeName(f.field_type));
|
||||||
}
|
}
|
||||||
|
@ -26,6 +24,12 @@ fn clone(alloc: std.mem.Allocator, val: anytype) !@TypeOf(val) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cloneString(alloc: std.mem.Allocator, str: []const u8) ![]const u8 {
|
||||||
|
var result = try alloc.alloc(u8, str.len);
|
||||||
|
std.mem.copy(u8, result, str);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Frees a struct and its fields returned by clone
|
// Frees a struct and its fields returned by clone
|
||||||
pub fn free(alloc: std.mem.Allocator, val: anytype) void {
|
pub fn free(alloc: std.mem.Allocator, val: anytype) void {
|
||||||
inline for (std.meta.fields(@TypeOf(val))) |f| {
|
inline for (std.meta.fields(@TypeOf(val))) |f| {
|
||||||
|
@ -55,20 +59,36 @@ pub const Database = struct {
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Database) void {
|
||||||
|
var iter = self.notes.iterator();
|
||||||
|
while (iter.next()) |it| {
|
||||||
|
free(self.internal_alloc, it.value_ptr.*);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.notes.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn containsNote(self: *Database, id: Id) !bool {
|
pub fn containsNote(self: *Database, id: Id) !bool {
|
||||||
return self.notes.contains(id);
|
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: Id, alloc: std.mem.Allocator) !?models.Note {
|
||||||
const note = self.notes.get(id) orelse return null;
|
const note = self.notes.get(id) orelse return null;
|
||||||
return try clone(alloc, note);
|
return try clone(alloc, note);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn putNote(self: *Database, note: models.Note) !void {
|
pub fn putNote(self: *Database, note: models.Note) !void {
|
||||||
if (try self.containsNote(note.id)) unreachable;
|
|
||||||
|
|
||||||
const copy = try clone(self.internal_alloc, note);
|
const copy = try clone(self.internal_alloc, note);
|
||||||
try self.notes.put(copy.id, copy);
|
errdefer free(self.internal_alloc, copy);
|
||||||
|
|
||||||
|
const key = copy.id;
|
||||||
|
|
||||||
|
if (self.notes.fetchRemove(key)) |e| {
|
||||||
|
free(self.internal_alloc, e.value);
|
||||||
|
}
|
||||||
|
try self.notes.put(key, copy);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,3 +101,36 @@ test "clone" {
|
||||||
const copy = try clone(std.testing.allocator, T{ .name = "myName", .value = "myValue" });
|
const copy = try clone(std.testing.allocator, T{ .name = "myName", .value = "myValue" });
|
||||||
free(std.testing.allocator, copy);
|
free(std.testing.allocator, copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "db" {
|
||||||
|
var db = try Database.init(std.testing.allocator);
|
||||||
|
defer db.deinit();
|
||||||
|
|
||||||
|
try db.putNote(.{
|
||||||
|
.id = "100",
|
||||||
|
.content = "content",
|
||||||
|
});
|
||||||
|
|
||||||
|
const note = (try db.getNote("100", std.testing.allocator)).?;
|
||||||
|
free(std.testing.allocator, note);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "db" {
|
||||||
|
var db = try Database.init(std.testing.allocator);
|
||||||
|
defer db.deinit();
|
||||||
|
|
||||||
|
try db.putNote(.{
|
||||||
|
.id = "100",
|
||||||
|
.content = "content",
|
||||||
|
});
|
||||||
|
|
||||||
|
try db.putNote(.{
|
||||||
|
.id = "100",
|
||||||
|
.content = "content",
|
||||||
|
});
|
||||||
|
|
||||||
|
try db.putNote(.{
|
||||||
|
.id = "100",
|
||||||
|
.content = "content",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const http = @import("http");
|
const http = @import("http");
|
||||||
const db = @import("./db.zig");
|
const db = @import("./db.zig");
|
||||||
|
const models = @import("./models.zig");
|
||||||
|
|
||||||
// this thing is overcomplicated and weird. stop this
|
// this thing is overcomplicated and weird. stop this
|
||||||
const Router = http.Router(*RequestServer);
|
const Router = http.Router(*RequestServer);
|
||||||
|
@ -11,6 +12,7 @@ const router = Router{
|
||||||
.routes = &[_]Route{
|
.routes = &[_]Route{
|
||||||
Route.new(.GET, "/healthcheck", healthcheck),
|
Route.new(.GET, "/healthcheck", healthcheck),
|
||||||
Route.new(.GET, "/:id", getNote),
|
Route.new(.GET, "/:id", getNote),
|
||||||
|
Route.new(.POST, "/", createNote),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,6 +46,17 @@ fn respondJson(ctx: *http.server.Context, status: http.Status, value: anytype, a
|
||||||
try stream.finish();
|
try stream.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn createNote(srv: *RequestServer, ctx: *http.server.Context, _: RouteArgs) !void {
|
||||||
|
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(models.Note, &tokens, .{ .allocator = srv.alloc });
|
||||||
|
defer std.json.parseFree(models.Note, note, .{ .allocator = srv.alloc });
|
||||||
|
|
||||||
|
try srv.db.putNote(note);
|
||||||
|
|
||||||
|
try respondJson(ctx, .created, note, srv.alloc);
|
||||||
|
}
|
||||||
|
|
||||||
fn getNote(srv: *RequestServer, ctx: *http.server.Context, args: RouteArgs) !void {
|
fn getNote(srv: *RequestServer, ctx: *http.server.Context, args: RouteArgs) !void {
|
||||||
const id = args.get("id") orelse return error.NotFound;
|
const id = args.get("id") orelse return error.NotFound;
|
||||||
const note = (try srv.db.getNote(id, srv.alloc)) orelse return error.NotFound;
|
const note = (try srv.db.getNote(id, srv.alloc)) orelse return error.NotFound;
|
||||||
|
|
Loading…
Reference in a new issue