actually make filters work right
This commit is contained in:
125
dynamodb/update_item.odin
Normal file
125
dynamodb/update_item.odin
Normal file
@@ -0,0 +1,125 @@
|
||||
// update_item.odin — Storage layer UpdateItem operation
|
||||
// This file lives in the dynamodb/ package alongside storage.odin
|
||||
package dynamodb
|
||||
|
||||
import "core:strings"
|
||||
import "core:sync"
|
||||
import "../rocksdb"
|
||||
|
||||
// UpdateItem — fetch existing item, apply update plan, write back
|
||||
// Uses EXCLUSIVE lock (write operation)
|
||||
//
|
||||
// Returns:
|
||||
// - old_item: the item BEFORE mutations (if it existed), for ReturnValues
|
||||
// - new_item: the item AFTER mutations
|
||||
// - error
|
||||
update_item :: proc(
|
||||
engine: ^Storage_Engine,
|
||||
table_name: string,
|
||||
key_item: Item,
|
||||
plan: ^Update_Plan,
|
||||
) -> (old_item: Maybe(Item), new_item: Maybe(Item), err: Storage_Error) {
|
||||
table_lock := get_or_create_table_lock(engine, table_name)
|
||||
sync.rw_mutex_lock(table_lock)
|
||||
defer sync.rw_mutex_unlock(table_lock)
|
||||
|
||||
// Get table metadata
|
||||
metadata, meta_err := get_table_metadata(engine, table_name)
|
||||
if meta_err != .None {
|
||||
return nil, nil, meta_err
|
||||
}
|
||||
defer table_metadata_destroy(&metadata, engine.allocator)
|
||||
|
||||
// Extract key from the provided key item
|
||||
key_struct, key_ok := key_from_item(key_item, metadata.key_schema)
|
||||
if !key_ok {
|
||||
return nil, nil, .Missing_Key_Attribute
|
||||
}
|
||||
defer key_destroy(&key_struct)
|
||||
|
||||
// Get key values
|
||||
key_values, kv_ok := key_get_values(&key_struct)
|
||||
if !kv_ok {
|
||||
return nil, nil, .Invalid_Key
|
||||
}
|
||||
|
||||
// Build storage key
|
||||
storage_key := build_data_key(table_name, key_values.pk, key_values.sk)
|
||||
defer delete(storage_key)
|
||||
|
||||
// Fetch existing item (if any)
|
||||
existing_encoded, get_err := rocksdb.db_get(&engine.db, storage_key)
|
||||
existing_item: Item
|
||||
|
||||
if get_err == .None && existing_encoded != nil {
|
||||
defer delete(existing_encoded)
|
||||
|
||||
decoded, decode_ok := decode(existing_encoded)
|
||||
if !decode_ok {
|
||||
return nil, nil, .Serialization_Error
|
||||
}
|
||||
existing_item = decoded
|
||||
// Save old item for ReturnValues
|
||||
old_item = item_deep_copy(existing_item)
|
||||
} else if get_err == .NotFound || existing_encoded == nil {
|
||||
// Item doesn't exist yet — start with just the key attributes
|
||||
existing_item = make(Item)
|
||||
|
||||
for ks in metadata.key_schema {
|
||||
if val, found := key_item[ks.attribute_name]; found {
|
||||
existing_item[strings.clone(ks.attribute_name)] = attr_value_deep_copy(val)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return nil, nil, .RocksDB_Error
|
||||
}
|
||||
|
||||
// Apply update plan
|
||||
if !execute_update_plan(&existing_item, plan) {
|
||||
item_destroy(&existing_item)
|
||||
if old, has := old_item.?; has {
|
||||
old_copy := old
|
||||
item_destroy(&old_copy)
|
||||
}
|
||||
return nil, nil, .Invalid_Key
|
||||
}
|
||||
|
||||
// Validate key attributes are still present and correct type
|
||||
validation_err := validate_item_key_types(
|
||||
existing_item, metadata.key_schema, metadata.attribute_definitions,
|
||||
)
|
||||
if validation_err != .None {
|
||||
item_destroy(&existing_item)
|
||||
if old, has := old_item.?; has {
|
||||
old_copy := old
|
||||
item_destroy(&old_copy)
|
||||
}
|
||||
return nil, nil, validation_err
|
||||
}
|
||||
|
||||
// Encode updated item
|
||||
encoded_item, encode_ok := encode(existing_item)
|
||||
if !encode_ok {
|
||||
item_destroy(&existing_item)
|
||||
if old, has := old_item.?; has {
|
||||
old_copy := old
|
||||
item_destroy(&old_copy)
|
||||
}
|
||||
return nil, nil, .Serialization_Error
|
||||
}
|
||||
defer delete(encoded_item)
|
||||
|
||||
// Write back to RocksDB
|
||||
put_err := rocksdb.db_put(&engine.db, storage_key, encoded_item)
|
||||
if put_err != .None {
|
||||
item_destroy(&existing_item)
|
||||
if old, has := old_item.?; has {
|
||||
old_copy := old
|
||||
item_destroy(&old_copy)
|
||||
}
|
||||
return nil, nil, .RocksDB_Error
|
||||
}
|
||||
|
||||
new_item = existing_item
|
||||
return old_item, new_item, .None
|
||||
}
|
||||
Reference in New Issue
Block a user