fix storage issues

This commit is contained in:
2026-02-15 20:57:16 -05:00
parent 280ce15b07
commit b510c000ec
5 changed files with 577 additions and 188 deletions

View File

@@ -485,41 +485,131 @@ parse_limit :: proc(request_body: []byte) -> int {
return 0
}
// Parse ExclusiveStartKey from request body as binary key bytes
// Returns nil if not present
parse_exclusive_start_key :: proc(request_body: []byte) -> Maybe([]byte) {
// ============================================================================
// ExclusiveStartKey Parsing (Pagination Input)
//
// Parse ExclusiveStartKey from request body. Requires key_schema so we can
// validate and extract the key, then convert it to a binary storage key.
// Returns the binary key bytes that can be passed straight to scan/query.
// Returns nil (not an error) when the field is absent.
// ============================================================================
parse_exclusive_start_key :: proc(
request_body: []byte,
table_name: string,
key_schema: []Key_Schema_Element,
) -> (result: Maybe([]byte), ok: bool) {
data, parse_err := json.parse(request_body, allocator = context.temp_allocator)
if parse_err != nil {
return nil
return nil, true // no ESK is fine
}
defer json.destroy_value(data)
root, ok := data.(json.Object)
if !ok {
return nil
root, root_ok := data.(json.Object)
if !root_ok {
return nil, true
}
key_val, found := root["ExclusiveStartKey"]
esk_val, found := root["ExclusiveStartKey"]
if !found {
return nil
return nil, true // absent → no pagination, that's ok
}
// Parse as Item first
key_item, item_ok := parse_item_from_value(key_val)
// Parse ExclusiveStartKey as a DynamoDB Item
key_item, item_ok := parse_item_from_value(esk_val)
if !item_ok {
return nil
return nil, false // present but malformed → real error
}
defer item_destroy(&key_item)
// Convert to binary key bytes (this will be done by the storage layer)
// For now, just return nil - the storage layer will handle the conversion
return nil
// Validate and extract key struct using schema
key_struct, key_ok := key_from_item(key_item, key_schema)
if !key_ok {
return nil, false // missing required key attributes
}
defer key_destroy(&key_struct)
// Get raw byte values
key_values, kv_ok := key_get_values(&key_struct)
if !kv_ok {
return nil, false
}
// Build binary storage key
binary_key := build_data_key(table_name, key_values.pk, key_values.sk)
result = binary_key
ok = true
return
}
// Serialize a Key as ExclusiveStartKey for response
serialize_last_evaluated_key :: proc(key: Key) -> string {
item := key_to_item(key, {}) // Empty key_schema since we don't need validation here
// ============================================================================
// LastEvaluatedKey Generation (Pagination Output)
//
// Decode a binary storage key back into a DynamoDB JSON fragment suitable
// for the "LastEvaluatedKey" field in scan/query responses.
//
// Steps:
// 1. Decode the binary key → table_name, pk_bytes, sk_bytes
// 2. Look up attribute types from metadata (S/N/B)
// 3. Build a Key struct with correctly-typed AttributeValues
// 4. Convert Key → Item → DynamoDB JSON string
// ============================================================================
// Build a Key struct from a binary storage key using metadata for type info.
// This mirrors the Zig buildKeyFromBinaryWithTypes helper.
build_key_from_binary_with_types :: proc(
binary_key: []byte,
metadata: ^Table_Metadata,
) -> (key: Key, ok: bool) {
decoder := Key_Decoder{data = binary_key, pos = 0}
// Skip entity type byte
_ = decoder_read_entity_type(&decoder) or_return
// Skip table name segment
_ = decoder_read_segment_borrowed(&decoder) or_return
// Read partition key bytes
pk_bytes := decoder_read_segment_borrowed(&decoder) or_return
// Read sort key bytes if present
sk_bytes: Maybe([]byte) = nil
if decoder_has_more(&decoder) {
sk := decoder_read_segment_borrowed(&decoder) or_return
sk_bytes = sk
}
// Get PK attribute type from metadata
pk_name := table_metadata_get_partition_key_name(metadata).? or_return
pk_type := table_metadata_get_attribute_type(metadata, pk_name).? or_return
pk_attr := build_attribute_value_with_type(pk_bytes, pk_type)
// Build SK attribute if present
sk_attr: Maybe(Attribute_Value) = nil
if sk, has_sk := sk_bytes.?; has_sk {
sk_name := table_metadata_get_sort_key_name(metadata).? or_return
sk_type := table_metadata_get_attribute_type(metadata, sk_name).? or_return
sk_attr = build_attribute_value_with_type(sk, sk_type)
}
return Key{pk = pk_attr, sk = sk_attr}, true
}
// Serialize a binary storage key as a LastEvaluatedKey JSON fragment.
// Returns a string like: {"pk":{"S":"val"},"sk":{"N":"42"}}
serialize_last_evaluated_key :: proc(
binary_key: []byte,
metadata: ^Table_Metadata,
) -> (result: string, ok: bool) {
key, key_ok := build_key_from_binary_with_types(binary_key, metadata)
if !key_ok {
return "", false
}
defer key_destroy(&key)
item := key_to_item(key, metadata.key_schema)
defer item_destroy(&item)
return serialize_item(item)
return serialize_item(item), true
}