This document defines the fundamental interfaces that form Implexus's public API.
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:
*_async methodsIdle.add()Defines the four types of entities in the database.
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
The base interface for all database entities. All I/O operations are async.
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<string> 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
Unified API for both embedded and remote operation modes. All I/O operations are async.
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
Vala doesn't support async delegates, so there's no with_write_transaction() helper. Use manual begin/commit/rollback:
try {
yield engine.begin_transaction_async();
// perform operations
yield engine.commit_async();
} catch (Error e) {
yield engine.rollback_async();
throw e;
}
Entity persistence abstraction.
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<string> 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<Path> 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
Low-level key-value storage interface with concurrent read support indicator.
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<string> 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 support for atomic operations.
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
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
namespace Implexus.Core {
public errordomain EntityError {
NOT_FOUND,
ALREADY_EXISTS,
INVALID_OPERATION,
TYPE_MISMATCH,
STORAGE_ERROR,
IO_ERROR;
}
} // namespace Implexus.Core
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
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
// 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");
// 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
);
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);
}
// 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'");