// key_codec_gsi.odin — Additional key codec functions for GSI support // // These procedures complement key_codec.odin with prefix builders needed // for GSI scanning and querying. They follow the same encoding conventions: // [entity_type][varint_len][segment_bytes]... // // Add the contents of this file to key_codec.odin (or keep as a separate file // in the dynamodb/ package). package dynamodb import "core:bytes" // Build GSI index prefix for scanning all entries in a GSI: // [gsi][table_name][index_name] build_gsi_prefix :: proc(table_name: string, index_name: string) -> []byte { buf: bytes.Buffer bytes.buffer_init_allocator(&buf, 0, 256, context.allocator) bytes.buffer_write_byte(&buf, u8(Entity_Type.GSI)) encode_varint(&buf, len(table_name)) bytes.buffer_write_string(&buf, table_name) encode_varint(&buf, len(index_name)) bytes.buffer_write_string(&buf, index_name) return bytes.buffer_to_bytes(&buf) } // Build GSI partition prefix for querying within a single partition: // [gsi][table_name][index_name][pk_value] build_gsi_partition_prefix :: proc(table_name: string, index_name: string, pk_value: []byte) -> []byte { buf: bytes.Buffer bytes.buffer_init_allocator(&buf, 0, 512, context.allocator) bytes.buffer_write_byte(&buf, u8(Entity_Type.GSI)) encode_varint(&buf, len(table_name)) bytes.buffer_write_string(&buf, table_name) encode_varint(&buf, len(index_name)) bytes.buffer_write_string(&buf, index_name) encode_varint(&buf, len(pk_value)) bytes.buffer_write(&buf, pk_value) return bytes.buffer_to_bytes(&buf) } // Decode a GSI key back into components Decoded_GSI_Key :: struct { table_name: string, index_name: string, pk_value: []byte, sk_value: Maybe([]byte), } decode_gsi_key :: proc(key: []byte) -> (result: Decoded_GSI_Key, ok: bool) { decoder := Key_Decoder{data = key, pos = 0} entity_type := decoder_read_entity_type(&decoder) or_return if entity_type != .GSI { return {}, false } table_name_bytes := decoder_read_segment(&decoder) or_return result.table_name = string(table_name_bytes) index_name_bytes := decoder_read_segment(&decoder) or_return result.index_name = string(index_name_bytes) result.pk_value = decoder_read_segment(&decoder) or_return if decoder_has_more(&decoder) { sk := decoder_read_segment(&decoder) or_return result.sk_value = sk } return result, true } // Build GSI prefix for deleting all GSI entries for a table (used by delete_table) // [gsi][table_name] build_gsi_table_prefix :: proc(table_name: string) -> []byte { buf: bytes.Buffer bytes.buffer_init_allocator(&buf, 0, 256, context.allocator) bytes.buffer_write_byte(&buf, u8(Entity_Type.GSI)) encode_varint(&buf, len(table_name)) bytes.buffer_write_string(&buf, table_name) return bytes.buffer_to_bytes(&buf) }