Check user handle is available

This commit is contained in:
jaina heartles 2022-07-16 12:30:47 -07:00
parent 1d6f7bfa08
commit b80eba6fcf
3 changed files with 59 additions and 43 deletions

View file

@ -73,13 +73,9 @@ pub const ApiServer = struct {
pub fn createUser(self: *ApiServer, info: CreateInfo(models.User)) !models.User { pub fn createUser(self: *ApiServer, info: CreateInfo(models.User)) !models.User {
const id = Uuid.randV4(self.prng.random()); const id = Uuid.randV4(self.prng.random());
// check for handle dupes if (try self.db.existsWhereEq(models.User, .handle, info.handle)) {
//while (iter.next()) |it| { return error.HandleNotAvailable;
//if (std.mem.eql(u8, it.value_ptr.handle, info.handle)) { }
//return error.DuplicateHandle;
//}
//}
// TODO: check for id dupes
const user = reify(models.User, id, info); const user = reify(models.User, id, info);
try self.db.insert(models.User, user); try self.db.insert(models.User, user);
@ -88,10 +84,10 @@ pub const ApiServer = struct {
} }
pub fn getNote(self: *ApiServer, id: Uuid, alloc: std.mem.Allocator) !?models.Note { pub fn getNote(self: *ApiServer, id: Uuid, alloc: std.mem.Allocator) !?models.Note {
return self.db.getById(models.Note, id, alloc); return self.db.getBy(models.Note, .id, id, alloc);
} }
pub fn getUser(self: *ApiServer, id: Uuid, alloc: std.mem.Allocator) !?models.User { pub fn getUser(self: *ApiServer, id: Uuid, alloc: std.mem.Allocator) !?models.User {
return self.db.getById(models.User, id, alloc); return self.db.getBy(models.User, .id, id, alloc);
} }
}; };

View file

@ -65,7 +65,10 @@ pub fn createUser(srv: *RequestServer, ctx: *http.server.Context, _: RouteArgs)
const info = try utils.parseRequestBody(api.CreateInfo(models.User), ctx, srv.alloc); const info = try utils.parseRequestBody(api.CreateInfo(models.User), ctx, srv.alloc);
defer utils.freeRequestBody(info, srv.alloc); defer utils.freeRequestBody(info, srv.alloc);
const user = try srv.api.createUser(info); const user = srv.api.createUser(info) catch |err| switch (err) {
error.HandleNotAvailable => return try utils.respondJson(ctx, .bad_request, .{ .@"error" = "handle not available" }, srv.alloc),
else => return err,
};
try utils.respondJson(ctx, .created, user, srv.alloc); try utils.respondJson(ctx, .created, user, srv.alloc);
} }

View file

@ -30,13 +30,14 @@ const Query = struct {
select: []const String, select: []const String,
from: String, from: String,
where: String = "id = ?", where: String = "id = ?",
limit: usize = 1, limit: ?usize = null,
pub fn str(comptime self: Query) String { pub fn str(comptime self: Query) String {
comptime { comptime {
const limit_expr = if (self.limit == null) "" else std.fmt.comptimePrint(" LIMIT {}", .{self.limit});
return std.fmt.comptimePrint( return std.fmt.comptimePrint(
"SELECT {s} FROM {s} WHERE {s} LIMIT {};", "SELECT {s} FROM {s} WHERE {s}{s};",
.{ join(self.select, ", "), self.from, self.where, self.limit }, .{ join(self.select, ", "), self.from, self.where, limit_expr },
); );
} }
} }
@ -123,36 +124,6 @@ pub const Database = struct {
self.db.close(); self.db.close();
} }
pub fn getByIdOld(self: *Database, comptime T: type, id: Uuid, alloc: std.mem.Allocator) !?T {
const fields = comptime fieldsExcept(T, &.{"id"});
const q = comptime (Query{
.select = fields,
.from = tableName(T),
.where = "id = ?",
.limit = 1,
}).str();
var stmt = try self.db.prepare(q);
defer stmt.finalize();
const id_str = id.toCharArray();
try stmt.bindText(1, &id_str);
const row = (try stmt.step()) orelse return null;
var val: T = undefined;
val.id = id;
inline for (fields) |f, i| {
@field(val, f) = switch (@TypeOf(@field(val, f))) {
// TODO: Handle allocation failures gracefully
[]const u8 => row.getTextAlloc(i, alloc) catch unreachable,
else => @compileError("unknown type"),
};
}
return val;
}
pub fn getById(self: *Database, comptime T: type, id: Uuid, alloc: std.mem.Allocator) !?T { pub fn getById(self: *Database, comptime T: type, id: Uuid, alloc: std.mem.Allocator) !?T {
return self.getBy(T, .id, id, alloc); return self.getBy(T, .id, id, alloc);
} }
@ -193,6 +164,52 @@ pub const Database = struct {
return result; return result;
} }
pub fn countWhereEq(
self: *Database,
comptime T: type,
comptime field: std.meta.FieldEnum(T),
val: std.meta.fieldInfo(T, field).field_type,
) !usize {
const field_name = std.meta.fieldInfo(T, field).name;
const q = comptime (Query{
.select = &.{"COUNT()"},
.from = tableName(T),
.where = field_name ++ " = ?",
}).str();
var stmt = try self.db.prepare(q);
defer stmt.finalize();
try stmt.bind(1, val);
const row = (try stmt.step()) orelse unreachable;
return @intCast(usize, try row.getI64(0));
}
// TODO: don't super like this query
pub fn existsWhereEq(
self: *Database,
comptime T: type,
comptime field: std.meta.FieldEnum(T),
val: std.meta.fieldInfo(T, field).field_type,
) !bool {
const field_name = std.meta.fieldInfo(T, field).name;
const q = comptime (Query{
.select = &.{"COUNT(1)"},
.from = tableName(T),
.where = field_name ++ " = ?",
.limit = 1,
}).str();
var stmt = try self.db.prepare(q);
defer stmt.finalize();
try stmt.bind(1, val);
const row = (try stmt.step()) orelse unreachable;
return (try row.getI64(0)) > 0;
}
pub fn getNoteById(self: *Database, id: Uuid, alloc: std.mem.Allocator) !?models.Note { pub fn getNoteById(self: *Database, id: Uuid, alloc: std.mem.Allocator) !?models.Note {
return self.getById(models.Note, id, alloc); return self.getById(models.Note, id, alloc);
} }