| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- /**
- * Basic usage example for Implexus
- *
- * This example demonstrates the unified API facade that allows
- * applications to seamlessly switch between embedded and remote modes.
- *
- * Features demonstrated:
- * - Mode selection (embedded vs remote)
- * - Entity creation (Container, Document, Category, Index)
- * - Property management
- * - Path-based access
- * - Transactions
- * - Querying by type and expression
- * - Entity deletion
- *
- * Note: All I/O operations are async. This example uses MainLoop
- * to run async operations from the synchronous main() function.
- */
- using Implexus;
- using Implexus.Core;
- using Implexus.Engine;
- // Global engine reference for async operations
- Core.Engine engine;
- public static int main(string[] args) {
- print("Implexus Basic Usage Example\n");
- print("=============================\n\n");
-
- // Parse command line arguments to select mode
- bool use_remote = false;
- string host = "localhost";
- uint16 port = 9876;
- string storage_path = "./example_data";
-
- for (int i = 1; i < args.length; i++) {
- if (args[i] == "--remote") {
- use_remote = true;
- } else if (args[i] == "--host" && i + 1 < args.length) {
- host = args[++i];
- } else if (args[i] == "--port" && i + 1 < args.length) {
- port = (uint16) int.parse(args[++i]);
- } else if (args[i] == "--path" && i + 1 < args.length) {
- storage_path = args[++i];
- } else if (args[i] == "--help") {
- print("Usage: basicusage [OPTIONS]\n");
- print("Options:\n");
- print(" --remote Use remote mode (default: embedded)\n");
- print(" --host HOST Remote server host (default: localhost)\n");
- print(" --port PORT Remote server port (default: 9876)\n");
- print(" --path PATH Storage path for embedded mode (default: ./example_data)\n");
- print(" --help Show this help message\n");
- return 0;
- }
- }
-
- // Run the async example
- var loop = new MainLoop();
- int result = 0;
- Error? error = null;
-
- run_example.begin(use_remote, host, port, storage_path, (obj, res) => {
- try {
- result = run_example.end(res);
- } catch (Error e) {
- error = e;
- result = 1;
- }
- loop.quit();
- });
- loop.run();
-
- if (error != null) {
- stderr.printf("Error: %s\n", ((!)error).message);
- }
-
- return result;
- }
- async int run_example(bool use_remote, string host, uint16 port, string storage_path) throws Error {
- // ============================================================
- // MODE SELECTION
- // The only difference between modes is how you create the configuration!
- // ============================================================
-
- EngineConfiguration config;
- if (use_remote) {
- print("Mode: REMOTE (%s:%u)\n\n", host, port);
- config = EngineConfiguration.remote(host, port);
- } else {
- print("Mode: EMBEDDED (path: %s)\n\n", storage_path);
- config = EngineConfiguration.embedded(storage_path);
- }
-
- // Create the engine - same API regardless of mode
- engine = EngineFactory.create(config);
-
- print("Engine created successfully!\n\n");
-
- // ============================================================
- // WORKING WITH CONTAINERS AND DOCUMENTS
- // ============================================================
-
- print("--- Creating Containers and Documents ---\n");
-
- // Get the root container (always exists)
- var root = yield engine.get_root_async();
- print("Got root entity: %s\n", root.path.to_string());
-
- // Create a container hierarchy for organizing users
- var users = yield root.create_container_async("users");
- print("Created container: %s\n", users.path.to_string());
-
- // Create documents with type labels for querying
- var john = yield users.create_document_async("john", "User");
- print("Created document: %s (type: %s)\n", john.path.to_string(), john.type_label);
-
- // Set various property types on the document
- yield john.set_entity_property_async("email", new Invercargill.NativeElement<string>("john@example.com"));
- yield john.set_entity_property_async("age", new Invercargill.NativeElement<int>(30));
- yield john.set_entity_property_async("active", new Invercargill.NativeElement<bool?>(true));
- print("Set properties: email, age, active\n\n");
-
- // ============================================================
- // QUERYING ENTITIES
- // ============================================================
-
- print("--- Querying Entities ---\n");
-
- // Query by type label
- print("Users (by type 'User'):\n");
- foreach (var entity in yield engine.query_by_type_async("User")) {
- print(" - %s\n", entity.name);
-
- // Access properties
- var email = yield entity.get_entity_property_async("email");
- if (email != null) {
- print(" email: %s\n", ((!) email).to_string());
- }
- }
- print("\n");
-
- // Query by expression (using Invercargill.Expressions)
- print("Active users (expression 'active==true'):\n");
- foreach (var entity in yield engine.query_by_expression_async("User", "active==true")) {
- print(" - %s\n", entity.name);
- }
- print("\n");
-
- // ============================================================
- // PATH-BASED ACCESS
- // ============================================================
-
- print("--- Path-Based Access ---\n");
-
- // Access entity by path
- var path = new EntityPath("/users/john");
- var entity = yield engine.get_entity_async(path);
- print("Retrieved entity by path: %s\n", entity.path.to_string());
-
- // Check if entity exists
- var exists = yield engine.entity_exists_async(new EntityPath("/users/john"));
- print("Entity /users/john exists: %s\n".printf(exists ? "true" : "false"));
-
- var not_exists = yield engine.entity_exists_async(new EntityPath("/users/jane"));
- print("Entity /users/jane exists: %s\n".printf(not_exists ? "true" : "false"));
- print("\n");
-
- // ============================================================
- // TRANSACTIONS
- // ============================================================
-
- print("--- Transactions ---\n");
-
- // Create multiple entities atomically in a transaction
- var tx = yield engine.begin_transaction_async();
- print("Transaction started\n");
-
- try {
- var jane = yield users.create_document_async("jane", "User");
- yield jane.set_entity_property_async("email", new Invercargill.NativeElement<string>("jane@example.com"));
- yield jane.set_entity_property_async("age", new Invercargill.NativeElement<int>(25));
- yield jane.set_entity_property_async("active", new Invercargill.NativeElement<bool?>(true));
- print("Created jane in transaction\n");
-
- var bob = yield users.create_document_async("bob", "User");
- yield bob.set_entity_property_async("email", new Invercargill.NativeElement<string>("bob@example.com"));
- yield bob.set_entity_property_async("age", new Invercargill.NativeElement<int>(35));
- yield bob.set_entity_property_async("active", new Invercargill.NativeElement<bool?>(false));
- print("Created bob in transaction\n");
-
- yield tx.commit_async();
- print("Transaction committed!\n\n");
-
- } catch (Error e) {
- yield tx.rollback_async();
- print("Transaction rolled back: %s\n", e.message);
- }
-
- // ============================================================
- // CATEGORIES (Dynamic Grouping)
- // ============================================================
-
- print("--- Categories (Dynamic Grouping) ---\n");
-
- // Create a category that auto-populates with matching entities
- var active_users = yield root.create_category_async("active_users", "User", "active==true");
- print("Created category: %s\n", active_users.path.to_string());
- print(" Type filter: User\n");
- print(" Expression: active==true\n");
-
- // The category's children are automatically populated
- // with documents matching the expression
- print(" Active users in category:\n");
- foreach (var child in yield active_users.get_children_async()) {
- print(" - %s\n", child.name);
- }
- print("\n");
-
- // ============================================================
- // INDEXES (Text Search)
- // ============================================================
-
- print("--- Indexes (Text Search) ---\n");
-
- // Create an index for text search results
- // Parameters: name, type_label, expression
- var search_index = yield root.create_index_async("email_search", "User", "email");
- print("Created index: %s\n", search_index.path.to_string());
- print(" Type filter: User\n");
- print(" Expression: email\n");
-
- // Index contains documents matching the search terms
- print(" Documents in index:\n");
- foreach (var result in yield search_index.get_children_async()) {
- print(" - %s\n", result.name);
- }
- print("\n");
-
- // ============================================================
- // FINAL STATE
- // ============================================================
-
- print("--- Final State ---\n");
- print("All users:\n");
- foreach (var user in yield engine.query_by_type_async("User")) {
- var user_email = yield user.get_entity_property_async("email");
- var age = yield user.get_entity_property_async("age");
- var active = yield user.get_entity_property_async("active");
- print(" - %s (email: %s, age: %s, active: %s)\n",
- user.name,
- user_email != null ? ((!) user_email).to_string() : "N/A",
- age != null ? ((!) age).to_string() : "N/A",
- active != null ? ((!) active).to_string() : "N/A"
- );
- }
- print("\n");
-
- // ============================================================
- // CLEANUP (Optional)
- // ============================================================
-
- print("--- Cleanup ---\n");
- print("Deleting test entities...\n");
-
- // Delete category and index first
- yield active_users.delete_async();
- print("Deleted active_users category\n");
-
- yield search_index.delete_async();
- print("Deleted email_search index\n");
-
- // Delete all users
- foreach (var user in yield engine.query_by_type_async("User")) {
- string name = user.name;
- yield user.delete_async();
- print("Deleted %s\n", name);
- }
-
- // Delete the users container
- yield users.delete_async();
- print("Deleted users container\n");
-
- print("\nExample completed successfully!\n");
- print("\nTip: To test remote mode, start implexusd first:\n");
- print(" ./build/tools/implexusd/implexusd --port 9876 --storage ./server_data\n");
- print(" Then run: ./build/examples/basicusage --remote\n");
-
- return 0;
- }
|