diff --git a/src/api/lib.zig b/src/api/lib.zig index a48170a..c13d981 100644 --- a/src/api/lib.zig +++ b/src/api/lib.zig @@ -276,7 +276,10 @@ fn ApiConn(comptime DbConn: type) type { username, password, self.community.id, - .{ .invite_id = if (maybe_invite) |inv| inv.id else null, .email = opt.email }, + .{ + .invite_id = if (maybe_invite) |inv| @as(?Uuid, inv.id) else null, + .email = opt.email, + }, self.arena.allocator(), ); diff --git a/src/api/services/actors.zig b/src/api/services/actors.zig index ee7c38d..2a7f964 100644 --- a/src/api/services/actors.zig +++ b/src/api/services/actors.zig @@ -94,7 +94,8 @@ pub const Actor = struct { created_at: DateTime, }; -pub fn get(db: anytype, id: Uuid, alloc: std.mem.Allocator) !Actor { +pub const GetError = error{ NotFound, DatabaseFailure }; +pub fn get(db: anytype, id: Uuid, alloc: std.mem.Allocator) GetError!Actor { return db.queryRow( Actor, \\SELECT diff --git a/src/api/services/communities.zig b/src/api/services/communities.zig index 8f0e21d..1187fef 100644 --- a/src/api/services/communities.zig +++ b/src/api/services/communities.zig @@ -83,11 +83,12 @@ pub fn create(db: anytype, origin: []const u8, options: CreateOptions, alloc: st else => return error.DatabaseFailure, } + const name = options.name orelse host; db.insert("community", .{ .id = id, .owner_id = null, .host = host, - .name = options.name orelse host, + .name = name, .scheme = scheme, .kind = options.kind, .created_at = DateTime.now(), @@ -262,14 +263,20 @@ pub fn query(db: anytype, args: QueryArgs, alloc: std.mem.Allocator) !QueryResul _ = try builder.array.appendSlice("\nLIMIT $7"); - const query_args = .{ - args.owner_id, - args.like, - args.created_before, - args.created_after, - if (args.prev) |prev| prev.order_val else null, - if (args.prev) |prev| prev.id else null, - max_items, + const query_args = blk: { + const ord_val = + if (args.prev) |prev| @as(?QueryArgs.OrderVal, prev.order_val) else null; + const id = + if (args.prev) |prev| @as(?Uuid, prev.id) else null; + break :blk .{ + args.owner_id, + args.like, + args.created_before, + args.created_after, + ord_val, + id, + max_items, + }; }; try builder.array.append(0); diff --git a/src/api/services/invites.zig b/src/api/services/invites.zig index 09a156c..2a58354 100644 --- a/src/api/services/invites.zig +++ b/src/api/services/invites.zig @@ -71,7 +71,7 @@ pub fn create(db: anytype, created_by: Uuid, community_id: ?Uuid, options: Invit .max_uses = options.max_uses, .created_at = created_at, .expires_at = if (options.lifespan) |lifespan| - created_at.add(lifespan) + @as(?DateTime, created_at.add(lifespan)) else null, diff --git a/src/http/request/parser.zig b/src/http/request/parser.zig index b7f0c31..57fae33 100644 --- a/src/http/request/parser.zig +++ b/src/http/request/parser.zig @@ -32,7 +32,7 @@ pub fn parse(alloc: std.mem.Allocator, reader: anytype) !Request(@TypeOf(reader) // discard \r\n switch (try reader.readByte()) { - '\r' => if (try reader.readByte() != '\n') return error.BadRequest, + '\r' => if ((try reader.readByte()) != '\n') return error.BadRequest, '\n' => {}, else => return error.BadRequest, } diff --git a/src/http/socket.zig b/src/http/socket.zig index cae032a..eab1a1d 100644 --- a/src/http/socket.zig +++ b/src/http/socket.zig @@ -30,7 +30,7 @@ pub fn handshake(alloc: std.mem.Allocator, req: *http.Request, res: *http.Respon if (std.ascii.indexOfIgnoreCase(connection, "Upgrade") == null) return error.BadHandshake; const key_hdr = req.headers.get("Sec-WebSocket-Key") orelse return error.BadHandshake; - if (try std.base64.standard.Decoder.calcSizeForSlice(key_hdr) != 16) return error.BadHandshake; + if ((try std.base64.standard.Decoder.calcSizeForSlice(key_hdr)) != 16) return error.BadHandshake; var key: [16]u8 = undefined; std.base64.standard.Decoder.decode(&key, key_hdr) catch return error.BadHandshake; @@ -164,15 +164,15 @@ fn writeFrame(writer: anytype, header: FrameInfo, buf: []const u8) !void { const initial_len: u7 = if (header.len < 126) @intCast(u7, header.len) else if (std.math.cast(u16, header.len)) |_| - 126 + @as(u7, 126) else - 127; + @as(u7, 127); var hdr_buf = [2]u8{ 0, 0 }; - hdr_buf[0] |= if (header.is_final) 0b1000_0000 else 0; + hdr_buf[0] |= if (header.is_final) @as(u8, 0b1000_0000) else 0; hdr_buf[0] |= @as(u8, header.rsv) << 4; hdr_buf[0] |= @enumToInt(header.opcode); - hdr_buf[1] |= if (header.masking_key) |_| 0b1000_0000 else 0; + hdr_buf[1] |= if (header.masking_key) |_| @as(u8, 0b1000_0000) else 0; hdr_buf[1] |= initial_len; try writer.writeAll(&hdr_buf); if (initial_len == 126) diff --git a/src/main/controllers/communities.zig b/src/main/controllers/communities.zig index f6b4c69..b7d33e9 100644 --- a/src/main/controllers/communities.zig +++ b/src/main/controllers/communities.zig @@ -151,31 +151,37 @@ fn formatQueryParams( return formatRecursive("", params, writer); } +fn formatField(comptime name: []const u8, val: anytype, writer: anytype) !void { + // TODO: percent-encode this + _ = try switch (@TypeOf(val)) { + []const u8 => blk: { + break :blk std.fmt.format(writer, "{s}={s}&", .{ name, val }); + }, + + else => |U| blk: { + if (comptime std.meta.trait.isContainer(U) and std.meta.trait.hasFn("format")(U)) { + break :blk std.fmt.format(writer, "{s}={}&", .{ name, val }); + } + + break :blk switch (@typeInfo(U)) { + .Enum => std.fmt.format(writer, "{s}={s}&", .{ name, @tagName(val) }), + .Struct => formatRecursive(name ++ ".", val, writer), + else => std.fmt.format(writer, "{s}={}&", .{ name, val }), + }; + }, + }; +} + fn formatRecursive(comptime prefix: []const u8, params: anytype, writer: anytype) !void { inline for (std.meta.fields(@TypeOf(params))) |field| { const val = @field(params, field.name); - const is_optional = comptime std.meta.trait.is(.Optional)(field.field_type); - const present = if (comptime is_optional) val != null else true; - if (present) { - const unwrapped = if (is_optional) val.? else val; - // TODO: percent-encode this - _ = try switch (@TypeOf(unwrapped)) { - []const u8 => blk: { - break :blk std.fmt.format(writer, "{s}{s}={s}&", .{ prefix, field.name, unwrapped }); - }, - - else => |U| blk: { - if (comptime std.meta.trait.isContainer(U) and std.meta.trait.hasFn("format")(U)) { - break :blk std.fmt.format(writer, "{s}{s}={}&", .{ prefix, field.name, unwrapped }); - } - - break :blk switch (@typeInfo(U)) { - .Enum => std.fmt.format(writer, "{s}{s}={s}&", .{ prefix, field.name, @tagName(unwrapped) }), - .Struct => formatRecursive(field.name ++ ".", unwrapped, writer), - else => std.fmt.format(writer, "{s}{s}={}&", .{ prefix, field.name, unwrapped }), - }; - }, - }; + const name = prefix ++ field.name; + if (comptime std.meta.trait.is(.Optional)(field.field_type)) { + if (val) |v| { + try formatField(name, v, writer); + } + } else { + try formatField(name, val, writer); } } } diff --git a/src/sql/engines/postgres.zig b/src/sql/engines/postgres.zig index a7afd95..6bff648 100644 --- a/src/sql/engines/postgres.zig +++ b/src/sql/engines/postgres.zig @@ -186,10 +186,19 @@ pub const Db = struct { var arena = std.heap.ArenaAllocator.init(alloc orelse return error.AllocatorRequired); defer arena.deinit(); const params = try arena.allocator().alloc(?[*:0]const u8, args.len); + // TODO: The following is a fix for the stage1 compiler. remove this //inline for (args) |arg, i| { inline for (std.meta.fields(@TypeOf(args))) |field, i| { const arg = @field(args, field.name); - params[i] = if (try common.prepareParamText(&arena, arg)) |slice| + + // The stage1 compiler has issues with runtime branches that in any + // way involve compile time values + const maybe_slice = if (@import("builtin").zig_backend == .stage1) + common.prepareParamText(&arena, arg) catch unreachable + else + try common.prepareParamText(&arena, arg); + + params[i] = if (maybe_slice) |slice| slice.ptr else null; diff --git a/src/sql/engines/sqlite.zig b/src/sql/engines/sqlite.zig index 081cb4b..e2bb697 100644 --- a/src/sql/engines/sqlite.zig +++ b/src/sql/engines/sqlite.zig @@ -118,6 +118,7 @@ pub const Db = struct { }; if (@TypeOf(args) != void) { + // TODO: Fix for stage1 compiler //inline for (args) |arg, i| { inline for (std.meta.fields(@TypeOf(args))) |field, i| { const arg = @field(args, field.name);