Fix parsing for enum and boolean values

This commit is contained in:
jaina heartles 2022-11-26 23:28:00 -08:00
parent 29a38240d9
commit d0e08e4b04

View file

@ -66,10 +66,6 @@ const QueryIter = @import("util").QueryIter;
/// Would be used to parse a query string like
/// `?foo.baz=12345`
///
/// Compound types cannot currently be nullable, and must be structs.
///
/// TODO: values are currently case-sensitive, and are not url-decoded properly.
/// This should be fixed.
pub fn parseQuery(alloc: std.mem.Allocator, comptime T: type, query: []const u8) !T {
if (comptime !std.meta.trait.isContainer(T)) @compileError("T must be a struct");
var iter = QueryIter.from(query);
@ -88,7 +84,7 @@ pub fn parseQuery(alloc: std.mem.Allocator, comptime T: type, query: []const u8)
return (try parse(alloc, T, "", "", fields)) orelse error.NoQuery;
}
fn decodeString(alloc: std.mem.Allocator, val: []const u8) ![]const u8 {
fn decodeString(alloc: std.mem.Allocator, val: []const u8) ![]u8 {
var list = try std.ArrayList(u8).initCapacity(alloc, val.len);
errdefer list.deinit();
@ -266,20 +262,23 @@ fn parseQueryValueNotNull(alloc: std.mem.Allocator, comptime T: type, value: []c
if (comptime std.meta.trait.isZigString(T)) return decoded;
defer alloc.free(decoded);
const result = if (comptime std.meta.trait.isIntegral(T))
try std.fmt.parseInt(T, decoded, 0)
else if (comptime std.meta.trait.isFloat(T))
try std.fmt.parseFloat(T, decoded)
else if (comptime std.meta.trait.is(.Enum)(T))
std.meta.stringToEnum(T, decoded) orelse return error.InvalidEnumValue
else if (T == bool)
bool_map.get(value) orelse return error.InvalidBool
else if (comptime std.meta.trait.hasFn("parse")(T))
else if (comptime std.meta.trait.is(.Enum)(T)) blk: {
_ = std.ascii.lowerString(decoded, decoded);
break :blk std.meta.stringToEnum(T, decoded) orelse return error.InvalidEnumValue;
} else if (T == bool) blk: {
_ = std.ascii.lowerString(decoded, decoded);
break :blk bool_map.get(decoded) orelse return error.InvalidBool;
} else if (comptime std.meta.trait.hasFn("parse")(T))
try T.parse(value)
else
@compileError("Invalid type " ++ @typeName(T));
alloc.free(decoded);
return result;
}
@ -359,7 +358,7 @@ fn format(comptime prefix: []const u8, comptime name: []const u8, params: anytyp
}
}
test {
test "parseQuery" {
const TestQuery = struct {
int: usize = 3,
boolean: bool = false,
@ -370,11 +369,11 @@ test {
.int = 3,
.boolean = false,
.str_enum = null,
}, try parseQuery(TestQuery, ""));
}, try parseQuery(std.testing.allocator, TestQuery, ""));
try std.testing.expectEqual(TestQuery{
.int = 5,
.boolean = true,
.str_enum = .foo,
}, try parseQuery(TestQuery, "?int=5&boolean=yes&str_enum=foo"));
}, try parseQuery(std.testing.allocator, TestQuery, "?int=5&boolean=yes&str_enum=foo"));
}