add key schema stuff

This commit is contained in:
Emil Lerch 2024-02-01 10:52:44 -08:00
parent cefefd3cc8
commit 5ffe51e3a0
Signed by: lobo
GPG Key ID: A7B62D657EF764F8
2 changed files with 79 additions and 2 deletions

View File

@ -29,6 +29,27 @@ pub fn handler(request: *AuthenticatedRequest, writer: anytype) ![]const u8 {
var parsed = try std.json.parseFromSlice(std.json.Value, allocator, request.event_data, .{}); var parsed = try std.json.parseFromSlice(std.json.Value, allocator, request.event_data, .{});
defer parsed.deinit(); defer parsed.deinit();
const request_params = try parseRequest(request, parsed, writer); const request_params = try parseRequest(request, parsed, writer);
// Parsing does most validation for us, but we also need to make sure that
// the attributes specified in the key schema actually exist
var found_keys: u2 = if (request_params.table_info.range_key_attribute_name == null) 0b01 else 0b00;
for (request_params.table_info.attribute_definitions) |def| {
if (std.mem.eql(u8, def.name, request_params.table_info.hash_key_attribute_name)) {
found_keys |= 0b10;
continue;
}
if (request_params.table_info.range_key_attribute_name) |n| {
if (std.mem.eql(u8, def.name, n))
found_keys |= 0b01;
}
}
if (found_keys != 0b11)
try returnException(
request,
.bad_request,
error.ValidationException,
writer,
"Attribute names in KeySchema must also exist in AttributeDefinitions",
);
defer { defer {
for (request_params.table_info.attribute_definitions) |d| { for (request_params.table_info.attribute_definitions) |d| {
allocator.free(d.*.name); allocator.free(d.*.name);
@ -133,6 +154,8 @@ fn parseRequest(
.table_info = .{ .table_info = .{
.attribute_definitions = undefined, .attribute_definitions = undefined,
.table_key = undefined, .table_key = undefined,
.hash_key_attribute_name = undefined,
.range_key_attribute_name = null,
}, },
}; };
// This is a new table, so we will generate a random key for table data // This is a new table, so we will generate a random key for table data
@ -233,13 +256,60 @@ fn parseRequest(
writer, writer,
"KeySchema must be an array", "KeySchema must be an array",
); );
if (val.array.items.len == 0) if (val.array.items.len < 1 or val.array.items.len > 2)
try returnException( try returnException(
request, request,
.bad_request, .bad_request,
error.ValidationException, error.ValidationException,
writer, writer,
"KeySchema array cannot be empty", "KeySchema array must consist of only 1 or 2 elements",
);
var found_hash = false;
for (val.array.items) |item| {
// {
// "AttributeName": "Artist",
// "KeyType": "HASH"
// },
if (item != .object)
try returnException(
request,
.bad_request,
error.ValidationException,
writer,
"KeySchemaElement must be an object",
);
const attribute_name = item.object.get("AttributeName");
const key_type = item.object.get("KeyType");
if (attribute_name == null or key_type == null or attribute_name.? != .string or key_type.? != .string)
try returnException(
request,
.bad_request,
error.ValidationException,
writer,
"KeySchemaElement must contain AttributeName and KeyType strings",
);
if (!std.mem.eql(u8, key_type.?.string, "HASH") and !std.mem.eql(u8, key_type.?.string, "RANGE"))
try returnException(
request,
.bad_request,
error.ValidationException,
writer,
"Invalid KeyType. Valid values are HASH | RANGE",
);
const is_hash = std.mem.eql(u8, key_type.?.string, "HASH");
found_hash = found_hash or is_hash;
if (is_hash)
request_params.table_info.hash_key_attribute_name = attribute_name.?.string
else
request_params.table_info.range_key_attribute_name = attribute_name.?.string;
}
if (!found_hash)
try returnException(
request,
.bad_request,
error.ValidationException,
writer,
"KeySchema missing hash key",
); );
continue; continue;
} }

View File

@ -53,6 +53,11 @@ pub const TableInfo = struct {
// gsi_description_list: []const u8, // Not sure how this is used // gsi_description_list: []const u8, // Not sure how this is used
// sqlite_index: []const u8, // Not sure how this is used // sqlite_index: []const u8, // Not sure how this is used
table_key: [encryption.encoded_key_length]u8, table_key: [encryption.encoded_key_length]u8,
// DDB Local is using sqlite_index here, which seems very much overkill
// as everything can be determined by just the name...
hash_key_attribute_name: []const u8,
range_key_attribute_name: ?[]const u8,
}; };
pub const TableArray = struct { pub const TableArray = struct {
@ -287,6 +292,8 @@ fn testCreateTable(allocator: std.mem.Allocator, account_id: []const u8) !sqlite
var table_info: TableInfo = .{ var table_info: TableInfo = .{
.table_key = undefined, .table_key = undefined,
.attribute_definitions = definitions[0..], .attribute_definitions = definitions[0..],
.hash_key_attribute_name = "Artist",
.range_key_attribute_name = null,
}; };
encryption.randomEncodedKey(&table_info.table_key); encryption.randomEncodedKey(&table_info.table_key);
try createDdbTable( try createDdbTable(