2026-02-15 08:55:22 -05:00
|
|
|
package dynamodb
|
|
|
|
|
|
|
|
|
|
import "core:fmt"
|
|
|
|
|
import "core:strings"
|
|
|
|
|
|
|
|
|
|
// DynamoDB AttributeValue - the core data type
|
|
|
|
|
Attribute_Value :: union {
|
2026-02-16 10:52:35 -05:00
|
|
|
String, // S
|
|
|
|
|
DDB_Number, // N — decimal-preserving numeric type
|
|
|
|
|
Binary, // B (base64)
|
|
|
|
|
Bool, // BOOL
|
|
|
|
|
Null, // NULL
|
|
|
|
|
String_Set, // SS
|
|
|
|
|
DDB_Number_Set, // NS
|
|
|
|
|
Binary_Set, // BS
|
|
|
|
|
List, // L
|
|
|
|
|
Map, // M
|
2026-02-15 08:55:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String :: distinct string
|
|
|
|
|
Binary :: distinct string
|
|
|
|
|
Bool :: distinct bool
|
|
|
|
|
Null :: distinct bool
|
|
|
|
|
|
|
|
|
|
String_Set :: distinct []string
|
2026-02-16 08:45:30 -05:00
|
|
|
DDB_Number_Set :: distinct []DDB_Number
|
2026-02-15 08:55:22 -05:00
|
|
|
Binary_Set :: distinct []string
|
|
|
|
|
List :: distinct []Attribute_Value
|
|
|
|
|
Map :: distinct map[string]Attribute_Value
|
|
|
|
|
|
|
|
|
|
// Item is a map of attribute names to values
|
|
|
|
|
Item :: map[string]Attribute_Value
|
|
|
|
|
|
|
|
|
|
// Key represents a DynamoDB key (partition key + optional sort key)
|
|
|
|
|
Key :: struct {
|
|
|
|
|
pk: Attribute_Value,
|
|
|
|
|
sk: Maybe(Attribute_Value),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Free a key
|
|
|
|
|
key_destroy :: proc(key: ^Key) {
|
|
|
|
|
attr_value_destroy(&key.pk)
|
|
|
|
|
if sk, ok := key.sk.?; ok {
|
|
|
|
|
sk_copy := sk
|
|
|
|
|
attr_value_destroy(&sk_copy)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Extract key from item based on key schema
|
|
|
|
|
key_from_item :: proc(item: Item, key_schema: []Key_Schema_Element) -> (Key, bool) {
|
|
|
|
|
pk_value: Attribute_Value
|
|
|
|
|
sk_value: Maybe(Attribute_Value)
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
for schema_elem in key_schema {
|
|
|
|
|
attr, ok := item[schema_elem.attribute_name]
|
|
|
|
|
if !ok {
|
|
|
|
|
return {}, false
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
// Validate that key is a scalar type (S, N, or B)
|
|
|
|
|
#partial switch _ in attr {
|
2026-02-16 10:52:35 -05:00
|
|
|
case String, DDB_Number, Binary:
|
2026-02-15 08:55:22 -05:00
|
|
|
// Valid key type
|
|
|
|
|
case:
|
|
|
|
|
return {}, false
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
// Deep copy the attribute value
|
|
|
|
|
copied := attr_value_deep_copy(attr)
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
switch schema_elem.key_type {
|
|
|
|
|
case .HASH:
|
|
|
|
|
pk_value = copied
|
|
|
|
|
case .RANGE:
|
|
|
|
|
sk_value = copied
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
return Key{pk = pk_value, sk = sk_value}, true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert key to item
|
|
|
|
|
key_to_item :: proc(key: Key, key_schema: []Key_Schema_Element) -> Item {
|
|
|
|
|
item := make(Item)
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
for schema_elem in key_schema {
|
|
|
|
|
attr_value: Attribute_Value
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
switch schema_elem.key_type {
|
|
|
|
|
case .HASH:
|
|
|
|
|
attr_value = key.pk
|
|
|
|
|
case .RANGE:
|
|
|
|
|
if sk, ok := key.sk.?; ok {
|
|
|
|
|
attr_value = sk
|
|
|
|
|
} else {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
item[schema_elem.attribute_name] = attr_value_deep_copy(attr_value)
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
return item
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Extract raw byte values from key
|
|
|
|
|
Key_Values :: struct {
|
|
|
|
|
pk: []byte,
|
|
|
|
|
sk: Maybe([]byte),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key_get_values :: proc(key: ^Key) -> (Key_Values, bool) {
|
|
|
|
|
pk_bytes: []byte
|
2026-02-15 13:56:08 -05:00
|
|
|
|
|
|
|
|
#partial switch v in key.pk {
|
2026-02-15 08:55:22 -05:00
|
|
|
case String:
|
|
|
|
|
pk_bytes = transmute([]byte)string(v)
|
2026-02-16 10:52:35 -05:00
|
|
|
case DDB_Number:
|
|
|
|
|
pk_bytes = encode_ddb_number_for_sort(v)
|
2026-02-15 08:55:22 -05:00
|
|
|
case Binary:
|
|
|
|
|
pk_bytes = transmute([]byte)string(v)
|
|
|
|
|
case:
|
|
|
|
|
return {}, false
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
sk_bytes: Maybe([]byte)
|
|
|
|
|
if sk, ok := key.sk.?; ok {
|
2026-02-15 13:56:08 -05:00
|
|
|
#partial switch v in sk {
|
2026-02-15 08:55:22 -05:00
|
|
|
case String:
|
|
|
|
|
sk_bytes = transmute([]byte)string(v)
|
2026-02-16 10:52:35 -05:00
|
|
|
case DDB_Number:
|
|
|
|
|
sk_bytes = encode_ddb_number_for_sort(v)
|
2026-02-15 08:55:22 -05:00
|
|
|
case Binary:
|
|
|
|
|
sk_bytes = transmute([]byte)string(v)
|
|
|
|
|
case:
|
|
|
|
|
return {}, false
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
return Key_Values{pk = pk_bytes, sk = sk_bytes}, true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Key type
|
|
|
|
|
Key_Type :: enum {
|
|
|
|
|
HASH,
|
|
|
|
|
RANGE,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key_type_to_string :: proc(kt: Key_Type) -> string {
|
|
|
|
|
switch kt {
|
|
|
|
|
case .HASH: return "HASH"
|
|
|
|
|
case .RANGE: return "RANGE"
|
|
|
|
|
}
|
|
|
|
|
return "HASH"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key_type_from_string :: proc(s: string) -> (Key_Type, bool) {
|
|
|
|
|
switch s {
|
|
|
|
|
case "HASH": return .HASH, true
|
|
|
|
|
case "RANGE": return .RANGE, true
|
|
|
|
|
}
|
|
|
|
|
return .HASH, false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Scalar attribute type
|
|
|
|
|
Scalar_Attribute_Type :: enum {
|
|
|
|
|
S, // String
|
|
|
|
|
N, // Number
|
|
|
|
|
B, // Binary
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scalar_type_to_string :: proc(t: Scalar_Attribute_Type) -> string {
|
|
|
|
|
switch t {
|
|
|
|
|
case .S: return "S"
|
|
|
|
|
case .N: return "N"
|
|
|
|
|
case .B: return "B"
|
|
|
|
|
}
|
|
|
|
|
return "S"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scalar_type_from_string :: proc(s: string) -> (Scalar_Attribute_Type, bool) {
|
|
|
|
|
switch s {
|
|
|
|
|
case "S": return .S, true
|
|
|
|
|
case "N": return .N, true
|
|
|
|
|
case "B": return .B, true
|
|
|
|
|
}
|
|
|
|
|
return .S, false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Key schema element
|
|
|
|
|
Key_Schema_Element :: struct {
|
|
|
|
|
attribute_name: string,
|
|
|
|
|
key_type: Key_Type,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Attribute definition
|
|
|
|
|
Attribute_Definition :: struct {
|
|
|
|
|
attribute_name: string,
|
|
|
|
|
attribute_type: Scalar_Attribute_Type,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Projection type for indexes
|
|
|
|
|
Projection_Type :: enum {
|
|
|
|
|
ALL,
|
|
|
|
|
KEYS_ONLY,
|
|
|
|
|
INCLUDE,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Projection
|
|
|
|
|
Projection :: struct {
|
|
|
|
|
projection_type: Projection_Type,
|
|
|
|
|
non_key_attributes: Maybe([]string),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Global secondary index
|
|
|
|
|
Global_Secondary_Index :: struct {
|
|
|
|
|
index_name: string,
|
|
|
|
|
key_schema: []Key_Schema_Element,
|
|
|
|
|
projection: Projection,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Local secondary index
|
|
|
|
|
Local_Secondary_Index :: struct {
|
|
|
|
|
index_name: string,
|
|
|
|
|
key_schema: []Key_Schema_Element,
|
|
|
|
|
projection: Projection,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Table status
|
|
|
|
|
Table_Status :: enum {
|
|
|
|
|
CREATING,
|
|
|
|
|
UPDATING,
|
|
|
|
|
DELETING,
|
|
|
|
|
ACTIVE,
|
|
|
|
|
INACCESSIBLE_ENCRYPTION_CREDENTIALS,
|
|
|
|
|
ARCHIVING,
|
|
|
|
|
ARCHIVED,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
table_status_to_string :: proc(status: Table_Status) -> string {
|
|
|
|
|
switch status {
|
|
|
|
|
case .CREATING: return "CREATING"
|
|
|
|
|
case .UPDATING: return "UPDATING"
|
|
|
|
|
case .DELETING: return "DELETING"
|
|
|
|
|
case .ACTIVE: return "ACTIVE"
|
|
|
|
|
case .INACCESSIBLE_ENCRYPTION_CREDENTIALS: return "INACCESSIBLE_ENCRYPTION_CREDENTIALS"
|
|
|
|
|
case .ARCHIVING: return "ARCHIVING"
|
|
|
|
|
case .ARCHIVED: return "ARCHIVED"
|
|
|
|
|
}
|
|
|
|
|
return "ACTIVE"
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-15 15:04:43 -05:00
|
|
|
table_status_from_string :: proc(s: string) -> Table_Status {
|
|
|
|
|
switch s {
|
|
|
|
|
case "CREATING": return .CREATING
|
|
|
|
|
case "UPDATING": return .UPDATING
|
|
|
|
|
case "DELETING": return .DELETING
|
|
|
|
|
case "ACTIVE": return .ACTIVE
|
|
|
|
|
case "ARCHIVING": return .ARCHIVING
|
|
|
|
|
case "ARCHIVED": return .ARCHIVED
|
|
|
|
|
}
|
|
|
|
|
return .ACTIVE
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
// Table description
|
|
|
|
|
Table_Description :: struct {
|
|
|
|
|
table_name: string,
|
|
|
|
|
key_schema: []Key_Schema_Element,
|
|
|
|
|
attribute_definitions: []Attribute_Definition,
|
|
|
|
|
table_status: Table_Status,
|
|
|
|
|
creation_date_time: i64,
|
|
|
|
|
item_count: u64,
|
|
|
|
|
table_size_bytes: u64,
|
|
|
|
|
global_secondary_indexes: Maybe([]Global_Secondary_Index),
|
|
|
|
|
local_secondary_indexes: Maybe([]Local_Secondary_Index),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DynamoDB operation types
|
|
|
|
|
Operation :: enum {
|
|
|
|
|
CreateTable,
|
|
|
|
|
DeleteTable,
|
|
|
|
|
DescribeTable,
|
|
|
|
|
ListTables,
|
|
|
|
|
UpdateTable,
|
|
|
|
|
PutItem,
|
|
|
|
|
GetItem,
|
|
|
|
|
DeleteItem,
|
|
|
|
|
UpdateItem,
|
|
|
|
|
Query,
|
|
|
|
|
Scan,
|
|
|
|
|
BatchGetItem,
|
|
|
|
|
BatchWriteItem,
|
|
|
|
|
TransactGetItems,
|
|
|
|
|
TransactWriteItems,
|
|
|
|
|
Unknown,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
operation_from_target :: proc(target: string) -> Operation {
|
|
|
|
|
prefix :: "DynamoDB_20120810."
|
|
|
|
|
if !strings.has_prefix(target, prefix) {
|
|
|
|
|
return .Unknown
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
op_name := target[len(prefix):]
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
switch op_name {
|
|
|
|
|
case "CreateTable": return .CreateTable
|
|
|
|
|
case "DeleteTable": return .DeleteTable
|
|
|
|
|
case "DescribeTable": return .DescribeTable
|
|
|
|
|
case "ListTables": return .ListTables
|
|
|
|
|
case "UpdateTable": return .UpdateTable
|
|
|
|
|
case "PutItem": return .PutItem
|
|
|
|
|
case "GetItem": return .GetItem
|
|
|
|
|
case "DeleteItem": return .DeleteItem
|
|
|
|
|
case "UpdateItem": return .UpdateItem
|
|
|
|
|
case "Query": return .Query
|
|
|
|
|
case "Scan": return .Scan
|
|
|
|
|
case "BatchGetItem": return .BatchGetItem
|
|
|
|
|
case "BatchWriteItem": return .BatchWriteItem
|
|
|
|
|
case "TransactGetItems": return .TransactGetItems
|
|
|
|
|
case "TransactWriteItems": return .TransactWriteItems
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
return .Unknown
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DynamoDB error types
|
|
|
|
|
DynamoDB_Error_Type :: enum {
|
|
|
|
|
ValidationException,
|
|
|
|
|
ResourceNotFoundException,
|
|
|
|
|
ResourceInUseException,
|
|
|
|
|
ConditionalCheckFailedException,
|
|
|
|
|
ProvisionedThroughputExceededException,
|
|
|
|
|
ItemCollectionSizeLimitExceededException,
|
|
|
|
|
InternalServerError,
|
|
|
|
|
SerializationException,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error_to_response :: proc(err_type: DynamoDB_Error_Type, message: string) -> string {
|
|
|
|
|
type_str: string
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
switch err_type {
|
|
|
|
|
case .ValidationException:
|
|
|
|
|
type_str = "com.amazonaws.dynamodb.v20120810#ValidationException"
|
|
|
|
|
case .ResourceNotFoundException:
|
|
|
|
|
type_str = "com.amazonaws.dynamodb.v20120810#ResourceNotFoundException"
|
|
|
|
|
case .ResourceInUseException:
|
|
|
|
|
type_str = "com.amazonaws.dynamodb.v20120810#ResourceInUseException"
|
|
|
|
|
case .ConditionalCheckFailedException:
|
|
|
|
|
type_str = "com.amazonaws.dynamodb.v20120810#ConditionalCheckFailedException"
|
|
|
|
|
case .ProvisionedThroughputExceededException:
|
|
|
|
|
type_str = "com.amazonaws.dynamodb.v20120810#ProvisionedThroughputExceededException"
|
|
|
|
|
case .ItemCollectionSizeLimitExceededException:
|
|
|
|
|
type_str = "com.amazonaws.dynamodb.v20120810#ItemCollectionSizeLimitExceededException"
|
|
|
|
|
case .InternalServerError:
|
|
|
|
|
type_str = "com.amazonaws.dynamodb.v20120810#InternalServerError"
|
|
|
|
|
case .SerializationException:
|
|
|
|
|
type_str = "com.amazonaws.dynamodb.v20120810#SerializationException"
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
return fmt.aprintf(`{{"__type":"%s","message":"%s"}}`, type_str, message)
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-15 15:04:43 -05:00
|
|
|
// Build an Attribute_Value with the correct scalar type from raw bytes
|
|
|
|
|
build_attribute_value_with_type :: proc(raw_bytes: []byte, attr_type: Scalar_Attribute_Type) -> Attribute_Value {
|
|
|
|
|
switch attr_type {
|
2026-02-16 10:52:35 -05:00
|
|
|
case .S:
|
|
|
|
|
return String(strings.clone(string(raw_bytes)))
|
|
|
|
|
case .N:
|
|
|
|
|
// Key bytes are canonical-encoded via encode_ddb_number_for_sort.
|
|
|
|
|
// Decode them back to a DDB_Number.
|
|
|
|
|
ddb_num, ok := decode_ddb_number_from_sort(raw_bytes)
|
|
|
|
|
if ok {
|
|
|
|
|
return clone_ddb_number(ddb_num)
|
|
|
|
|
}
|
|
|
|
|
// Fallback: try interpreting as a plain numeric string
|
|
|
|
|
fallback_num, fb_ok := parse_ddb_number(string(raw_bytes))
|
|
|
|
|
if fb_ok {
|
|
|
|
|
return fallback_num
|
|
|
|
|
}
|
|
|
|
|
// Last resort — return as string (shouldn't happen)
|
|
|
|
|
return String(strings.clone(string(raw_bytes)))
|
|
|
|
|
case .B:
|
|
|
|
|
return Binary(strings.clone(string(raw_bytes)))
|
2026-02-15 15:04:43 -05:00
|
|
|
}
|
2026-02-16 10:52:35 -05:00
|
|
|
return String(strings.clone(string(raw_bytes)))
|
2026-02-15 15:04:43 -05:00
|
|
|
}
|
|
|
|
|
|
2026-02-15 08:55:22 -05:00
|
|
|
// Deep copy an attribute value
|
|
|
|
|
attr_value_deep_copy :: proc(attr: Attribute_Value) -> Attribute_Value {
|
|
|
|
|
switch v in attr {
|
|
|
|
|
case String:
|
|
|
|
|
return String(strings.clone(string(v)))
|
2026-02-16 08:45:30 -05:00
|
|
|
case DDB_Number:
|
|
|
|
|
return clone_ddb_number(v)
|
2026-02-15 08:55:22 -05:00
|
|
|
case Binary:
|
|
|
|
|
return Binary(strings.clone(string(v)))
|
|
|
|
|
case Bool:
|
|
|
|
|
return v
|
|
|
|
|
case Null:
|
|
|
|
|
return v
|
|
|
|
|
case String_Set:
|
|
|
|
|
ss := make([]string, len(v))
|
|
|
|
|
for s, i in v {
|
|
|
|
|
ss[i] = strings.clone(s)
|
|
|
|
|
}
|
|
|
|
|
return String_Set(ss)
|
2026-02-16 08:45:30 -05:00
|
|
|
case DDB_Number_Set:
|
|
|
|
|
ddb_ns := make([]DDB_Number, len(v))
|
|
|
|
|
for num, i in v {
|
|
|
|
|
ddb_ns[i] = clone_ddb_number(num)
|
|
|
|
|
}
|
|
|
|
|
return DDB_Number_Set(ddb_ns)
|
2026-02-15 08:55:22 -05:00
|
|
|
case Binary_Set:
|
|
|
|
|
bs := make([]string, len(v))
|
|
|
|
|
for b, i in v {
|
|
|
|
|
bs[i] = strings.clone(b)
|
|
|
|
|
}
|
|
|
|
|
return Binary_Set(bs)
|
|
|
|
|
case List:
|
|
|
|
|
list := make([]Attribute_Value, len(v))
|
|
|
|
|
for item, i in v {
|
|
|
|
|
list[i] = attr_value_deep_copy(item)
|
|
|
|
|
}
|
|
|
|
|
return List(list)
|
|
|
|
|
case Map:
|
|
|
|
|
m := make(map[string]Attribute_Value)
|
|
|
|
|
for key, val in v {
|
|
|
|
|
m[strings.clone(key)] = attr_value_deep_copy(val)
|
|
|
|
|
}
|
|
|
|
|
return Map(m)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Free an attribute value
|
|
|
|
|
attr_value_destroy :: proc(attr: ^Attribute_Value) {
|
|
|
|
|
switch v in attr {
|
|
|
|
|
case String:
|
|
|
|
|
delete(string(v))
|
2026-02-16 08:45:30 -05:00
|
|
|
case DDB_Number:
|
|
|
|
|
delete(v.integer_part)
|
|
|
|
|
delete(v.fractional_part)
|
2026-02-15 08:55:22 -05:00
|
|
|
case Binary:
|
|
|
|
|
delete(string(v))
|
|
|
|
|
case String_Set:
|
|
|
|
|
for s in v {
|
|
|
|
|
delete(s)
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
slice := v
|
|
|
|
|
delete(slice)
|
2026-02-16 08:45:30 -05:00
|
|
|
case DDB_Number_Set:
|
|
|
|
|
for num in v {
|
|
|
|
|
delete(num.integer_part)
|
|
|
|
|
delete(num.fractional_part)
|
|
|
|
|
}
|
|
|
|
|
delete(v)
|
2026-02-15 08:55:22 -05:00
|
|
|
case Binary_Set:
|
|
|
|
|
for b in v {
|
|
|
|
|
delete(b)
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
slice := v
|
|
|
|
|
delete(slice)
|
2026-02-15 08:55:22 -05:00
|
|
|
case List:
|
|
|
|
|
for item in v {
|
|
|
|
|
item_copy := item
|
|
|
|
|
attr_value_destroy(&item_copy)
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
list := v
|
|
|
|
|
delete(list)
|
2026-02-15 08:55:22 -05:00
|
|
|
case Map:
|
|
|
|
|
for key, val in v {
|
|
|
|
|
delete(key)
|
|
|
|
|
val_copy := val
|
|
|
|
|
attr_value_destroy(&val_copy)
|
|
|
|
|
}
|
2026-02-15 13:56:08 -05:00
|
|
|
m := v
|
|
|
|
|
delete(m)
|
2026-02-15 08:55:22 -05:00
|
|
|
case Bool, Null:
|
|
|
|
|
// Nothing to free
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Free an item
|
|
|
|
|
item_destroy :: proc(item: ^Item) {
|
|
|
|
|
for key, val in item {
|
|
|
|
|
delete(key)
|
|
|
|
|
val_copy := val
|
|
|
|
|
attr_value_destroy(&val_copy)
|
|
|
|
|
}
|
|
|
|
|
delete(item^)
|
2026-02-16 10:52:35 -05:00
|
|
|
}
|