# Core Interfaces This document defines the fundamental interfaces that form Implexus's public API. ## Async I/O Model All I/O operations in Implexus are asynchronous. Methods that require database access use Vala's `async` keyword and must be called with `yield`. This ensures the main loop remains responsive during database operations. **Key principles:** - Identity properties (path, name, entity_type, engine) are synchronous - no I/O required - Navigation, CRUD, and query operations are async - use `*_async` methods - Hooks run synchronously in the DBM worker thread context - Results are returned to the main loop via `Idle.add()` ## EntityType Enum Defines the four types of entities in the database. ```vala namespace Implexus.Core { public enum EntityType { CONTAINER, DOCUMENT, CATEGORY, INDEX; public string to_string() { switch (this) { case CONTAINER: return "container"; case DOCUMENT: return "document"; case CATEGORY: return "category"; case INDEX: return "index"; default: assert_not_reached(); } } public static EntityType? from_string(string name) { switch (name.down()) { case "container": return CONTAINER; case "document": return DOCUMENT; case "category": return CATEGORY; case "index": return INDEX; default: return null; } } } } // namespace Implexus.Core ``` ## Entity Interface The base interface for all database entities. All I/O operations are async. ```vala namespace Implexus.Core { public interface Entity : Object { // === Identity (Synchronous - No I/O) === public abstract unowned Engine engine { get; } public abstract Path path { owned get; } public abstract string name { owned get; } public abstract EntityType entity_type { get; } public abstract string type_label { owned get; } public abstract string configured_expression { owned get; } public abstract string configured_type_label { owned get; } // === Parent/Child Navigation (Async) === public abstract async Entity? get_parent_async() throws EntityError; public abstract async Invercargill.ReadOnlySet get_child_names_async() throws EntityError; public abstract async Entity? get_child_async(string name) throws EntityError; public abstract async Entity[] get_children_async() throws EntityError; // === Child Management (CONTAINER only - Async) === public abstract async Entity? create_container_async(string name) throws EntityError; public abstract async Entity? create_document_async(string name, string type_label) throws EntityError; public abstract async Entity? create_category_async( string name, string type_label, string expression ) throws EntityError; public abstract async Entity? create_index_async( string name, string type_label, string expression ) throws EntityError; public abstract async Entity? create_catalogue_async( string name, string type_label, string expression ) throws EntityError; // === Document Operations (DOCUMENT only - Async) === public abstract async Invercargill.Properties get_properties_async() throws EntityError; public abstract async Invercargill.Element? get_entity_property_async(string name) throws EntityError; public abstract async void set_entity_property_async(string name, Invercargill.Element value) throws EntityError; public abstract async void remove_property_async(string name) throws EntityError; // === Lifecycle (Async) === public abstract async void delete_async() throws EntityError; public abstract bool exists { get; } // === Set Operations (Async) === public abstract async EntitySet as_set_async(); // === Signals === public signal void property_changed(string key); } } // namespace Implexus.Core ``` ## Engine Interface Unified API for both embedded and remote operation modes. All I/O operations are async. ```vala namespace Implexus.Core { public interface Engine : Object { // === Root Access (Async) === public abstract async Entity get_root_async() throws EngineError; // === Path-Based Access (Async) === public abstract async Entity? get_entity_async(Path path) throws EngineError; public abstract async Entity? get_entity_or_null_async(Path path) throws EngineError; public abstract async bool entity_exists_async(Path path) throws EngineError; // === Query Operations (Async) === public abstract async Entity[] query_by_type_async(string type_label) throws EngineError; public abstract async Entity[] query_by_expression_async( string type_label, string expression ) throws EngineError; // === Transactions (Async) === public abstract async Transaction begin_transaction_async() throws EngineError; public abstract async void commit_async() throws EngineError; public abstract async void rollback_async(); public abstract bool in_transaction { get; } // === Configuration (Synchronous) === public abstract StorageConfiguration configuration { owned get; } // === Events === public signal void entity_created(Entity entity); public signal void entity_deleted(Path path); public signal void entity_modified(Entity entity); } } // namespace Implexus.Core ``` ### Transaction Management Vala doesn't support async delegates, so there's no `with_write_transaction()` helper. Use manual begin/commit/rollback: ```vala try { yield engine.begin_transaction_async(); // perform operations yield engine.commit_async(); } catch (Error e) { yield engine.rollback_async(); throw e; } ``` ## Storage Interface Entity persistence abstraction. ```vala namespace Implexus.Storage { public interface Storage : Object { // Entity Operations public abstract bool has_entity(Path path); public abstract uint8[]? load_entity(Path path); public abstract void save_entity(Path path, uint8[] data) throws StorageError; public abstract void delete_entity(Path path) throws StorageError; // Child Tracking public abstract Invercargill.ReadOnlySet get_child_names(Path parent_path); public abstract void register_child(Path parent, string child_name); public abstract void unregister_child(Path parent, string child_name); // Indexing Support public abstract Invercargill.Enumerable get_paths_by_type(string type_label); public abstract void register_type(Path path, string type_label); public abstract void unregister_type(Path path, string type_label); // Transactions public abstract void begin_transaction() throws StorageError; public abstract void commit_transaction() throws StorageError; public abstract void rollback_transaction(); public abstract bool in_transaction { get; } // Lifecycle public abstract void open() throws StorageError; public abstract void close(); public abstract void compact() throws StorageError; } } // namespace Implexus.Storage ``` ## DBM Interface Low-level key-value storage interface with concurrent read support indicator. ```vala namespace Implexus.Storage { public interface Dbm : Object { // === Concurrent Read Support === /** * Whether this DBM supports concurrent read operations. * - LMDB: true (MVCC allows concurrent readers) * - GDBM: false (single-threaded access required) * - Filesystem: false (single-threaded access required) */ public abstract bool supports_concurrent_reads { get; } // === Basic Operations === public abstract bool has_key(string key); public abstract Invercargill.BinaryData? @get(string key); public abstract void @set(string key, Invercargill.BinaryData value) throws StorageError; public abstract void delete(string key) throws StorageError; // === Iteration === public abstract Invercargill.Enumerable keys { owned get; } // === Transactions === public abstract void begin_transaction() throws StorageError; public abstract void commit_transaction() throws StorageError; public abstract void rollback_transaction(); public abstract bool in_transaction { get; } } } // namespace Implexus.Storage ``` ## Transaction Interface Transaction support for atomic operations. ```vala namespace Implexus.Core { public interface Transaction : Object { public abstract bool active { get; } public abstract async void commit_async() throws EngineError; public abstract async void rollback_async(); } } // namespace Implexus.Core ``` ## Error Domains ### EngineError ```vala namespace Implexus.Core { public errordomain EngineError { ENTITY_NOT_FOUND, ENTITY_ALREADY_EXISTS, INVALID_PATH, INVALID_OPERATION, TYPE_MISMATCH, EXPRESSION_ERROR, TRANSACTION_ERROR, STORAGE_ERROR, CONNECTION_ERROR, PROTOCOL_ERROR; } } // namespace Implexus.Core ``` ### EntityError ```vala namespace Implexus.Core { public errordomain EntityError { NOT_FOUND, ALREADY_EXISTS, INVALID_OPERATION, TYPE_MISMATCH, STORAGE_ERROR, IO_ERROR; } } // namespace Implexus.Core ``` ### StorageError ```vala namespace Implexus.Storage { public errordomain StorageError { OPEN_ERROR, READ_ERROR, WRITE_ERROR, DELETE_ERROR, TRANSACTION_ERROR, CORRUPTION_ERROR, DISK_FULL, IO_ERROR; } } // namespace Implexus.Storage ``` ## Interface Relationships ```mermaid graph TB subgraph Core Entity[Entity Interface] Engine[Engine Interface] Transaction[Transaction Interface] EntityType[EntityType Enum] end subgraph Storage Storage[Storage Interface] Dbm[Dbm Interface] AsyncDbmQueue[AsyncDbmQueue] DbmOperation[DbmOperation] end Engine --> Entity Engine --> Transaction Engine --> Storage Storage --> Dbm Storage --> AsyncDbmQueue AsyncDbmQueue --> DbmOperation Entity --> EntityType Entity --> Engine ``` ## Usage Patterns ### Accessing Entities ```vala // Via path (async) var entity = yield engine.get_entity_async(new Path("/users/john")); // Via navigation (async) var root = yield engine.get_root_async(); var users = yield root.get_child_async("users"); var john = yield users.get_child_async("john"); ``` ### Creating Entities ```vala // Create container (async) var container = yield (yield engine.get_root_async()).create_container_async("app"); // Create document (async) var doc = yield container.create_document_async("config", "AppConfig"); yield doc.set_entity_property_async("version", new ValueElement("1.0.0")); // Create category - auto-categorize documents by property value (async) var category = yield container.create_category_async( "by_status", "Task", "status" // Expression to evaluate on each Task document ); // Create index - text search on documents (async) var index = yield container.create_index_async( "search", "Task", "description" // Expression to search within ); ``` ### Using Transactions ```vala try { yield engine.begin_transaction_async(); var container = yield (yield engine.get_root_async()).create_container_async("batch"); var doc = yield container.create_document_async("item1", "Item"); yield doc.set_entity_property_async("value", new ValueElement(42)); var doc2 = yield (yield engine.get_root_async()).get_child_async("batch"); doc2 = yield ((!) doc2).create_document_async("item2", "Item"); yield doc2.set_entity_property_async("value", new ValueElement(84)); yield engine.commit_async(); } catch (Error e) { yield engine.rollback_async(); warning("Transaction failed: %s", e.message); } ``` ### Querying Entities ```vala // Query all entities of a type (async) var tasks = yield engine.query_by_type_async("Task"); foreach (var task in tasks) { var status = yield task.get_entity_property_async("status"); message("Task status: %s", status?.to_string() ?? "null"); } // Query with expression filter (async) var activeTasks = yield engine.query_by_expression_async("Task", "status == 'active'"); ```