diff --git a/main.odin b/main.odin index 4ddb8aa..fdab1d6 100644 --- a/main.odin +++ b/main.odin @@ -1237,15 +1237,26 @@ handle_query :: proc(engine: ^dynamodb.Storage_Engine, request: ^HTTP_Request, r // ---- GSI query path ---- if idx_name, has_idx := index_name.?; has_idx { - _, gsi_found := dynamodb.find_gsi(&metadata, idx_name) + gsi, gsi_found := dynamodb.find_gsi(&metadata, idx_name) if !gsi_found { make_error_response(response, .ValidationException, fmt.tprintf("The table does not have the specified index: %s", idx_name)) return } + esk_gsi, esk_gsi_ok := dynamodb.parse_exclusive_start_key_gsi( + request.body, table_name, &metadata, gsi, + ) + if !esk_gsi_ok { + make_error_response(response, .ValidationException, "Invalid ExclusiveStartKey") + return + } + defer { + if k, ok_gsi := esk_gsi.?; ok_gsi { delete(k) } + } + result, err := dynamodb.gsi_query(engine, table_name, idx_name, - pk_owned, exclusive_start_key, limit, sk_condition) + pk_owned, esk_gsi, limit, sk_condition) if err != .None { handle_storage_error(response, err) return @@ -1284,7 +1295,7 @@ handle_query :: proc(engine: ^dynamodb.Storage_Engine, request: ^HTTP_Request, r } write_items_response_with_pagination_ex( - response, final_items, result.last_evaluated_key, &metadata, scanned_count, + response, final_items, result.last_evaluated_key, &metadata, scanned_count, gsi, ) if has_proj && len(projection) > 0 { @@ -1420,14 +1431,25 @@ handle_scan :: proc(engine: ^dynamodb.Storage_Engine, request: ^HTTP_Request, re // ---- GSI scan path ---- if idx_name, has_idx := index_name.?; has_idx { - _, gsi_found := dynamodb.find_gsi(&metadata, idx_name) + gsi, gsi_found := dynamodb.find_gsi(&metadata, idx_name) if !gsi_found { make_error_response(response, .ValidationException, fmt.tprintf("The table does not have the specified index: %s", idx_name)) return } - result, err := dynamodb.gsi_scan(engine, table_name, idx_name, exclusive_start_key, limit) + esk_gsi, esk_gsi_ok := dynamodb.parse_exclusive_start_key_gsi( + request.body, table_name, &metadata, gsi, + ) + if !esk_gsi_ok { + make_error_response(response, .ValidationException, "Invalid ExclusiveStartKey") + return + } + defer { + if k, ok_gsi := esk_gsi.?; ok_gsi { delete(k) } + } + + result, err := dynamodb.gsi_scan(engine, table_name, idx_name, esk_gsi, limit) if err != .None { handle_storage_error(response, err) return @@ -1466,7 +1488,7 @@ handle_scan :: proc(engine: ^dynamodb.Storage_Engine, request: ^HTTP_Request, re } write_items_response_with_pagination_ex( - response, final_items, result.last_evaluated_key, &metadata, scanned_count, + response, final_items, result.last_evaluated_key, &metadata, scanned_count, gsi, ) if has_proj && len(projection) > 0 { @@ -1579,13 +1601,13 @@ write_items_response_with_pagination_ex :: proc( last_evaluated_key_binary: Maybe([]byte), metadata: ^dynamodb.Table_Metadata, scanned_count: int, + gsi: ^dynamodb.Global_Secondary_Index = nil, // ← NEW parameter ) { builder := strings.builder_make(context.allocator) defer strings.builder_destroy(&builder) strings.write_string(&builder, `{"Items":[`) - // Use serialize_item_to_builder directly an NOT serialize_item for item, i in items { if i > 0 do strings.write_string(&builder, ",") dynamodb.serialize_item_to_builder(&builder, item) @@ -1597,7 +1619,16 @@ write_items_response_with_pagination_ex :: proc( fmt.sbprintf(&builder, "%d", scanned_count) if binary_key, has_last := last_evaluated_key_binary.?; has_last { - lek_json, lek_ok := dynamodb.serialize_last_evaluated_key(binary_key, metadata) + lek_json: string + lek_ok: bool + + // Use GSI serializer if we have a GSI, otherwise use base table serializer + if gsi != nil { + lek_json, lek_ok = dynamodb.serialize_last_evaluated_key_gsi(binary_key, metadata, gsi) + } else { + lek_json, lek_ok = dynamodb.serialize_last_evaluated_key(binary_key, metadata) + } + if lek_ok { strings.write_string(&builder, `,"LastEvaluatedKey":`) strings.write_string(&builder, lek_json) @@ -1606,7 +1637,6 @@ write_items_response_with_pagination_ex :: proc( strings.write_string(&builder, "}") - // We have to Clone the string before passing to response_set_body resp_body := strings.clone(strings.to_string(builder)) response_set_body(response, transmute([]byte)resp_body) }