// gsi_metadata.odin — GSI metadata parsing for serialize/deserialize_table_metadata // // Parses GSI definitions from the embedded JSON string stored in table metadata. // This file lives in the dynamodb/ package. package dynamodb import "core:encoding/json" import "core:mem" import "core:strings" // Parse GlobalSecondaryIndexes from a JSON string like: // [{"IndexName":"email-index","KeySchema":[{"AttributeName":"email","KeyType":"HASH"}], // "Projection":{"ProjectionType":"ALL"}}] // // Allocates all strings with the given allocator (engine.allocator for long-lived data). parse_gsis_json :: proc(json_str: string, allocator: mem.Allocator) -> ([]Global_Secondary_Index, bool) { data, parse_err := json.parse(transmute([]byte)json_str, allocator = context.temp_allocator) if parse_err != nil { return nil, false } defer json.destroy_value(data) arr, ok := data.(json.Array) if !ok { return nil, false } if len(arr) == 0 { return nil, true // Empty is valid } result := make([]Global_Secondary_Index, len(arr), allocator) for elem, i in arr { obj, obj_ok := elem.(json.Object) if !obj_ok { cleanup_gsis(result[:i], allocator) delete(result, allocator) return nil, false } gsi, gsi_ok := parse_single_gsi_json(obj, allocator) if !gsi_ok { cleanup_gsis(result[:i], allocator) delete(result, allocator) return nil, false } result[i] = gsi } return result, true } // Parse a single GSI object from JSON @(private = "file") parse_single_gsi_json :: proc(obj: json.Object, allocator: mem.Allocator) -> (Global_Secondary_Index, bool) { gsi: Global_Secondary_Index // IndexName idx_val, idx_found := obj["IndexName"] if !idx_found { return {}, false } idx_str, idx_ok := idx_val.(json.String) if !idx_ok { return {}, false } gsi.index_name = strings.clone(string(idx_str), allocator) // KeySchema ks_val, ks_found := obj["KeySchema"] if !ks_found { delete(gsi.index_name, allocator) return {}, false } ks_arr, ks_ok := ks_val.(json.Array) if !ks_ok || len(ks_arr) == 0 || len(ks_arr) > 2 { delete(gsi.index_name, allocator) return {}, false } key_schema := make([]Key_Schema_Element, len(ks_arr), allocator) for ks_elem, j in ks_arr { ks_obj, kobj_ok := ks_elem.(json.Object) if !kobj_ok { for k in 0.. 0 { nka := make([]string, len(nka_arr), allocator) for attr_val, k in nka_arr { if attr_str, attr_ok := attr_val.(json.String); attr_ok { nka[k] = strings.clone(string(attr_str), allocator) } } gsi.projection.non_key_attributes = nka } } } } return gsi, true } // Clean up partially-constructed GSI array cleanup_gsis :: proc(gsis: []Global_Secondary_Index, allocator: mem.Allocator) { for gsi in gsis { delete(gsi.index_name, allocator) for ks in gsi.key_schema { delete(ks.attribute_name, allocator) } delete(gsi.key_schema, allocator) if nka, has_nka := gsi.projection.non_key_attributes.?; has_nka { for attr in nka { delete(attr, allocator) } delete(nka, allocator) } } }