/** * ChildrenStorage - Low-level storage for structural children * * Handles the 'children:' prefix for storing container child names. * * Key format: children: * Value: Serialized array of child names * * @version 0.1 * @since 0.1 */ namespace Implexus.Storage.LowLevel { /** * Low-level storage for structural children. * * This class provides type-safe operations for storing and retrieving * structural child names using the 'children:' key prefix. */ public class ChildrenStorage : Object { /** * Key prefix for children entries. */ private const string PREFIX = "children:"; /** * The underlying Dbm storage. */ private Dbm _dbm; /** * Creates a new ChildrenStorage with the given Dbm backend. * * @param dbm The Dbm backend to use for storage */ public ChildrenStorage(Dbm dbm) { _dbm = dbm; } /** * Adds a child name to a parent's children set. * * @param parent The parent entity path * @param child_name The name of the child to add * @throws StorageError if the operation fails */ public void add_child(Core.EntityPath parent, string child_name) throws StorageError { var children = load_children_set(parent); if (!children.contains(child_name)) { children.add(child_name); save_children_set(parent, children); } } /** * Removes a child name from a parent's children set. * * @param parent The parent entity path * @param child_name The name of the child to remove * @throws StorageError if the operation fails */ public void remove_child(Core.EntityPath parent, string child_name) throws StorageError { var children = load_children_set(parent); if (children.contains(child_name)) { children.remove(child_name); save_children_set(parent, children); } } /** * Checks if a parent has a specific child. * * @param parent The parent entity path * @param child_name The name of the child to check * @return True if the child exists */ public bool has_child(Core.EntityPath parent, string child_name) { var children = load_children_set(parent); return children.contains(child_name); } /** * Gets all child names for a parent. * * @param parent The parent entity path * @return An enumerable of child names */ public Invercargill.Enumerable get_children(Core.EntityPath parent) { var children = load_children_set(parent); return children.as_enumerable(); } /** * Deletes all children for a parent. * * @param parent The parent entity path * @throws StorageError if the operation fails */ public void delete(Core.EntityPath parent) throws StorageError { string key = PREFIX + parent.to_string(); try { _dbm.delete(key); } catch (StorageError e) { // Key doesn't exist, that's fine } } /** * Loads the children set for a parent. * * @param parent The parent entity path * @return A vector of child names (empty if not found) */ private Invercargill.DataStructures.Vector load_children_set(Core.EntityPath parent) { string key = PREFIX + parent.to_string(); var result = new Invercargill.DataStructures.Vector(); var data = _dbm.get(key); if (data == null) { return result; } var reader = new ElementReader((!) data); try { var element = reader.read_element(); if (element.is_null()) { return result; } // The children set is stored as an array of strings var array = element.as>(); foreach (var child_element in array) { if (!child_element.is_null()) { string child_name = child_element.as(); if (!result.contains(child_name)) { result.add(child_name); } } } } catch (Invercargill.ElementError e) { warning("Failed to read children set: %s", e.message); } return result; } /** * Saves the children set for a parent. * * @param parent The parent entity path * @param children The set of child names to save * @throws StorageError if the operation fails */ private void save_children_set(Core.EntityPath parent, Invercargill.DataStructures.Vector children) throws StorageError { string key = PREFIX + parent.to_string(); uint count = children.count(); if (count == 0) { try { _dbm.delete(key); } catch (StorageError e) { // Key doesn't exist, that's fine } return; } // Store as array of strings var array = new Invercargill.DataStructures.Vector(); foreach (var child_name in children) { var element = new Invercargill.NativeElement(child_name); array.add(element); } var writer = new ElementWriter(); writer.write_element(new Invercargill.NativeElement>(array)); _dbm.set(key, writer.to_binary_data()); } } } // namespace Implexus.Storage.LowLevel