### Sentinel Workflow Examples Source: https://sentinel.cyberpath-hq.com/docs/cli-commands Provides examples of complete workflows, including setting up a new store, managing documents (insert, get, update, delete), and audit trail operations. ```APIDOC ## Workflow Examples ### Setting Up a New Store This workflow demonstrates the initialization of a new Sentinel data store, including key generation and collection creation. ```bash # Generate keys SIGNING_KEY=$(sentinel gen key signing) ENCRYPTION_KEY=$(sentinel gen key encryption) # Initialize the store sentinel init \ --path /data/my-store \ --signing-key $SIGNING_KEY \ --passphrase "my-secure-passphrase" \ --encryption-algorithm xchacha20poly1305 # Create collections sentinel create-collection --store /data/my-store --name users sentinel create-collection --store /data/my-store --name audit_logs sentinel create-collection --store /data/my-store --name certificates ``` ### Managing Documents This workflow covers the basic CRUD operations for documents within a collection. ```bash # Insert documents sentinel insert \ --store /data/my-store \ --collection users \ --id user-001 \ --data '{"name": "Alice", "role": "admin"}' sentinel insert \ --store /data/my-store \ --collection users \ --id user-002 \ --data '{"name": "Bob", "role": "user"}' # Retrieve and modify USER=$(sentinel get --store /data/my-store --collection users --id user-001) MODIFIED=$(echo "$USER" | jq '.role = "superadmin"') sentinel update \ --store /data/my-store \ --collection users \ --id user-001 \ --data "$MODIFIED" # Delete sentinel delete --store /data/my-store --collection users --id user-002 ``` ### Audit Trail Operations This workflow shows how to create and inspect audit log entries. ```bash # Create audit log entries sentinel insert \ --store /data/my-store \ --collection audit_logs \ --id "$(date +%Y%m%d-%H%M%S)-login" \ --data "{\"action\": \"login\", \"user\": \"alice\", \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" # View all audit logs (using filesystem tools) ls -la /data/my-store/audit_logs/ # Search audit logs with grep grep -r "alice" /data/my-store/audit_logs/ ``` ``` -------------------------------- ### QueryBuilder::build Example (Rust) Source: https://sentinel.cyberpath-hq.com/docs/api-reference Shows the final step in building a query using `QueryBuilder::build()`. This example first applies a filter and then calls `build()` to get the executable `Query` object. ```rust let query = QueryBuilder::new() .filter("age", Operator::GreaterThan, json!(25)) .build(); ``` -------------------------------- ### Create Sentinel Store Source: https://sentinel.cyberpath-hq.com/docs/quick-start Initializes a new Sentinel store at a specified directory path. The directory is created if it does not exist. This function does not use a passphrase for signing. ```rust use sentinel_dbms::Store; #[tokio::main] async fn main() -> Result<(), Box> { // Create a store at ./my-database // The directory will be created if it doesn't exist let store = Store::new("./my-database", None).await?; println!("Store created at ./my-database"); Ok(()) } ``` -------------------------------- ### Query Documents in Sentinel DB Source: https://sentinel.cyberpath-hq.com/docs/quick-start Demonstrates how to query documents based on specific criteria using the `QueryBuilder` API. This includes filtering by field values, operators, and sorting the results. ```rust use sentinel_dbms::{Store, QueryBuilder, Operator, SortOrder}; use serde_json::json; use futures::TryStreamExt; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; let users = store.collection("users").await?; // Insert some test data users.insert("user1", json!({"name": "Alice", "age": 30})).await?; users.insert("user2", json!({"name": "Bob", "age": 25})).await?; users.insert("user3", json!({"name": "Charlie", "age": 35})).await?; // Find users older than 25 let query = QueryBuilder::new() .filter("age", Operator::GreaterThan, json!(25)) .sort("age", SortOrder::Ascending) .build(); let result = users.query(query).await?; let documents: Vec<_> = result.documents.try_collect().await?; println!("Found {} users older than 25:", documents.len()); for doc in documents { println!(" - {}, age: {}", doc.data()["name"], doc.data()["age"]); } Ok(()) } ``` -------------------------------- ### Handle Optional Documents Safely in Rust with Sentinel Source: https://sentinel.cyberpath-hq.com/docs/errors Demonstrates a robust pattern for handling the `Option` returned by Sentinel's `get` method. This example safely retrieves a document or creates a default one if it doesn't exist, ensuring that subsequent operations can proceed without errors. ```rust use sentinel_dbms::Store; use serde_json::json; async fn safe_get_or_create( store: &Store, collection_name: &str, id: &str, ) -> sentinel_dbms::Result { let collection = store.collection(collection_name).await?; match collection.get(id).await? { Some(doc) => Ok(doc), None => { // Create default document collection.insert(id, json!({ "created_automatically": true })).await?; // Fetch and return it collection.get(id).await?.ok_or_else(|| { sentinel_dbms::SentinelError::Internal { message: "Document not found after creation".to_string(), } }) } } } ``` -------------------------------- ### Example WAL Configuration Persistence (JSON) Source: https://sentinel.cyberpath-hq.com/docs/wal-configuration Illustrates how WAL configuration settings are persisted in a collection's `.metadata.json` file. This JSON object shows various WAL parameters like write mode, compression, and format. ```json { "id": "users", "wal_config": { "write_mode": "strict", "verification_mode": "warn", "auto_verify": false, "enable_recovery": true, "max_wal_size_bytes": 10485760, "compression_algorithm": "zstd", "max_records_per_file": 1000, "format": "binary" } } ``` -------------------------------- ### Query Examples Source: https://sentinel.cyberpath-hq.com/docs/querying Provides practical examples of how to use the QueryBuilder to perform common data retrieval operations. ```APIDOC ## Examples ### Example 1: Finding Active Admins Retrieves documents from the 'users' collection where the 'role' is 'admin' and the 'status' is 'active'. #### Request Example ```rust use sentinel_dbms::{Store, QueryBuilder, Operator}; use serde_json::json; use futures::TryStreamExt; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-data", None).await?; let users = store.collection("users").await?; let query = QueryBuilder::new() .filter("role", Operator::Equals, json!("admin")) .filter("status", Operator::Equals, json!("active")) .build(); let result = users.query(query).await?; let admins: Vec<_> = result.documents.try_collect().await?; println!("Found {} active admins", admins.len()); Ok(()) } ``` ### Example 2: Recent Documents Retrieves the 100 most recent documents from the 'audit_logs' collection, sorted by 'created_at' in descending order. #### Request Example ```rust use sentinel_dbms::{Store, QueryBuilder, SortOrder}; use futures::TryStreamExt; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-data", None).await?; let logs = store.collection("audit_logs").await?; let query = QueryBuilder::new() .sort("created_at", SortOrder::Descending) .limit(100) .build(); let result = logs.query(query).await?; let recent: Vec<_> = result.documents.try_collect().await?; println!("Retrieved {} most recent logs", recent.len()); Ok(()) } ``` ``` -------------------------------- ### Sentinel Unit Tests: Insert, Get, Update, Delete Operations (Rust) Source: https://sentinel.cyberpath-hq.com/docs/examples Demonstrates unit tests for basic CRUD operations (insert, get, update, delete) on a Sentinel store collection. It utilizes temporary directories for isolated test environments and the `tokio` runtime for asynchronous operations. Dependencies include `sentinel_dbms`, `serde_json`, and `tempfile`. ```rust #[cfg(test)] mod tests { use sentinel_dbms::{Store, Result}; use serde_json::json; use tempfile::TempDir; async fn setup_test_store() -> Result<(Store, TempDir)> { let temp_dir = TempDir::new().unwrap(); let store = Store::new(temp_dir.path(), None).await?; Ok((store, temp_dir)) } #[tokio::test] async fn test_insert_and_get() -> Result<()> { let (store, _temp) = setup_test_store().await?; let users = store.collection("users").await?; // Insert users.insert("test_user", json!({ "name": "Test User", "email": "test@example.com" })).await?; // Get let doc = users.get("test_user").await?.expect("Document not found"); assert_eq!(doc.id(), "test_user"); assert_eq!(doc.data()["name"], "Test User"); Ok(()) } #[tokio::test] async fn test_update() -> Result<()> { let (store, _temp) = setup_test_store().await?; let users = store.collection("users").await?; // Insert users.insert("test_user", json!({ "name": "Original Name" })).await?; // Update users.update("test_user", json!({ "name": "Updated Name" })).await?; // Verify let doc = users.get("test_user").await?.expect("Document not found"); assert_eq!(doc.data()["name"], "Updated Name"); Ok(()) } #[tokio::test] async fn test_delete() -> Result<()> { let (store, _temp) = setup_test_store().await?; let users = store.collection("users").await?; // Insert users.insert("test_user", json!({"name": "Test"})).await?; // Delete users.delete("test_user").await?; // Verify deleted let doc = users.get("test_user").await?; assert!(doc.is_none()); Ok(()) } } ``` -------------------------------- ### QueryBuilder::project Example (Rust) Source: https://sentinel.cyberpath-hq.com/docs/api-reference Demonstrates how to use the `project` method to select specific fields for the query results. This example requests only the 'name' and 'email' fields. ```rust let query = QueryBuilder::new() .project(vec!["name".to_string(), "email".to_string()]); ``` -------------------------------- ### Store and Retrieve Application Configuration with Sentinel DBMS (Rust) Source: https://sentinel.cyberpath-hq.com/docs/examples This example shows how to use Sentinel DBMS to store and retrieve application configuration settings. It demonstrates inserting various configuration parameters like database, Redis, API, and feature flags, and then reading back specific settings like the database host and port. This requires `sentinel_dbms`, `serde_json`, and `tokio` crates. ```rust use sentinel_dbms::{Store, Result}; use serde_json::json; #[tokio::main] async fn main() -> Result<()> { let store = Store::new("./app_config", None).await?; let config = store.collection("config").await?; // Store various configuration settings config.insert("database", json!({ "host": "localhost", "port": 5432, "name": "myapp", "pool_size": 10 })).await?; config.insert("redis", json!({ "host": "localhost", "port": 6379, "ttl": 3600 })).await?; config.insert("api", json!({ "base_url": "https://api.example.com", "timeout": 30, "retries": 3, "rate_limit": 100 })).await?; config.insert("features", json!({ "enable_cache": true, "enable_metrics": true, "enable_debug": false })).await?; println!("Configuration saved"); // Read configuration let db_config = config.get("database").await?; if let Some(cfg) = db_config { println!("Database host: {}", cfg.data()["host"]); println!("Database port: {}", cfg.data()["port"]); } Ok(()) } ``` -------------------------------- ### Manage Multiple Collections in a Store (Rust) Source: https://sentinel.cyberpath-hq.com/docs/quick-start This code illustrates how to create and manage multiple distinct collections within a single Sentinel database store. It demonstrates inserting data into different collections and then listing all available collections. Dependencies include `sentinel_dbms` and `serde_json`. The function returns a `Result` indicating success or failure. ```rust use sentinel_dbms::Store; use serde_json::json; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; // Create multiple collections let users = store.collection("users").await?; let products = store.collection("products").await?; let orders = store.collection("orders").await?; // Work with each collection users.insert("alice", json!({"name": "Alice"})).await?; products.insert("widget", json!({"name": "Widget", "price": 9.99})).await?; orders.insert("order-123", json!({"user_id": "alice", "total": 29.97})).await?; // List all collections in the store let collections = store.list_collections().await?; println!("Collections: {:?}", collections); Ok(()) } ``` -------------------------------- ### Create Sentinel Collection Source: https://sentinel.cyberpath-hq.com/docs/quick-start Retrieves or creates a collection within an existing Sentinel store. Collections act as namespaces for related documents and are represented as subdirectories. ```rust use sentinel_dbms::Store; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; // Get or create a "users" collection let users = store.collection("users").await?; println!("Collection 'users' ready!"); Ok(()) } ``` -------------------------------- ### Create Sentinel Database and Collections Source: https://sentinel.cyberpath-hq.com/docs/examples Initializes a new Sentinel database and creates collections for different data types (users, posts, comments). This is the first step in setting up a new Sentinel database. ```rust use sentinel_dbms::{Store, Result}; use serde_json::json; #[tokio::main] async fn main() -> Result<()> { // Create a store let store = Store::new("./my_database", None).await?; // Create collections for different data types let users = store.collection("users").await?; let posts = store.collection("posts").await?; let comments = store.collection("comments").await?; println!("Database initialized!"); println!("Collections: users, posts, comments"); Ok(()) } ``` -------------------------------- ### Add Signatures to Documents in Sentinel DB Source: https://sentinel.cyberpath-hq.com/docs/quick-start Explains how to create a Sentinel store with a passphrase to enable automatic signing of documents. This ensures tamper-evident storage by generating and attaching signatures to each document. ```rust use sentinel_dbms::Store; use serde_json::json; #[tokio::main] async fn main() -> Result<(), Box> { // Create store with passphrase for signing let store = Store::new("./secure-database", Some("my-secret-passphrase")).await?; let users = store.collection("users").await?; // Insert a document (will be signed automatically) users.insert("alice", json!({ "name": "Alice", "email": "alice@example.com" })).await?; // Retrieve and check signature if let Some(doc) = users.get("alice").await? { println!("Document ID: {}", doc.id()); println!("Signature: {}", doc.signature()); // Will show: "ed25519:..." (not empty) } Ok(()) } ``` -------------------------------- ### Example Usage of Document Accessor Methods (Rust) Source: https://sentinel.cyberpath-hq.com/docs/api-reference Demonstrates how to use the accessor methods to retrieve and display information about a document. This example shows fetching a document by its ID and then printing its ID, creation timestamp, hash, and a specific field from its data. ```rust let doc = users.get("alice").await?.unwrap(); println!("ID: {}", doc.id()); println!("Created: {}", doc.created_at()); println!("Hash: {}", doc.hash()); println!("Name: {}", doc.data()["name"]); ``` -------------------------------- ### Bulk Insert Documents in Sentinel DB Source: https://sentinel.cyberpath-hq.com/docs/quick-start Shows how to efficiently insert multiple documents into a collection using the `bulk_insert` method. This is suitable for scenarios requiring the insertion of many records at once. ```rust use sentinel_dbms::Store; use serde_json::json; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; let users = store.collection("users").await?; // Prepare multiple documents let documents = vec![ ("bob", json!({"name": "Bob", "role": "user"})), ("charlie", json!({"name": "Charlie", "role": "user"})), ("david", json!({"name": "David", "role": "admin"})), ]; // Insert all at once users.bulk_insert(documents).await?; println!("{} documents inserted", documents.len()); Ok(()) } ``` -------------------------------- ### Build Sentinel from Source Source: https://sentinel.cyberpath-hq.com/docs/installation Commands to clone the Sentinel repository, navigate into the directory, and build the project in release mode using Cargo. Also includes commands to run tests and benchmarks. ```shell # Clone the repository git clone https://github.com/cyberpath-HQ/sentinel.git cd sentinel # Build all crates cargo build --release # Run tests cargo test # Run benchmarks cargo bench ``` -------------------------------- ### Initialize Sentinel Store with Tokio Runtime Source: https://sentinel.cyberpath-hq.com/docs/installation Demonstrates how to initialize a Sentinel `Store` within an asynchronous Rust function using the `#[tokio::main]` macro. This is essential for Sentinel's asynchronous operations. ```rust use sentinel_dbms::Store; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./data", None).await?; // Your code here Ok(()) } ``` -------------------------------- ### List and Count Documents in Sentinel DB Source: https://sentinel.cyberpath-hq.com/docs/quick-start Illustrates how to retrieve the total count of documents and a list of all document IDs within a collection using the `count` and `list` methods respectively. Requires the `futures` crate for stream processing. ```rust use sentinel_dbms::Store; use futures::TryStreamExt; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; let users = store.collection("users").await?; // Count documents let count = users.count().await?; println!("Total documents: {}", count); // List all document IDs let ids: Vec<_> = users.list().try_collect().await?; println!("Document IDs:"); for id in ids { println!(" - {}", id); } Ok(()) } ``` -------------------------------- ### QueryBuilder::new Example (Rust) Source: https://sentinel.cyberpath-hq.com/docs/api-reference Illustrates the basic usage of `QueryBuilder::new()` to create an empty query builder instance. This is typically the first step before applying filters, sorting, or other query configurations. ```rust let query = QueryBuilder::new(); ``` -------------------------------- ### Search for emails containing 'example' Source: https://sentinel.cyberpath-hq.com/docs/cli-commands Searches the 'users' collection within the specified store for documents where the 'email' field contains the substring 'example'. ```bash sentinel query \ --store /data/my-store \ --collection users \ --filter "email~example" ``` -------------------------------- ### Hashing Data Example (Rust) Source: https://sentinel.cyberpath-hq.com/docs/api-reference Demonstrates how to use the `hash_data` function to calculate the BLAKE3 hash of a JSON object. The example shows creating a JSON value and then hashing it asynchronously. ```rust use sentinel_dbms::hash_data; let hash = hash_data(&json!({"key": "value"})).await?; ``` -------------------------------- ### Implement Audit Logging with Sentinel DB Source: https://sentinel.cyberpath-hq.com/docs/examples Provides a function `log_action` to create timestamped audit log entries in a dedicated collection using sentinel_dbms. It includes user ID, action, details, timestamp, and an example IP address. The main function demonstrates logging various user actions. ```rust use sentinel_dbms::{Store, Result}; use serde_json::json; use chrono::Utc; async fn log_action( store: &Store, user_id: &str, action: &str, details: serde_json::Value, ) -> Result<()> { let audit_logs = store.collection("audit_logs").await?; // Create timestamped log entry let timestamp = Utc::now(); let log_id = format!("{}-{}", timestamp.format("%Y%m%d-%H%M%S"), user_id); audit_logs.insert(&log_id, json!({ "user_id": user_id, "action": action, "details": details, "timestamp": timestamp.to_rfc3339(), "ip_address": "192.168.1.100" // Example })).await?; Ok(()) } #[tokio::main] async fn main() -> Result<()> { let store = Store::new("./audit_database", Some("audit-key")).await?; // Log various actions log_action(&store, "alice", "login", json!({ "success": true, "method": "password" })).await?; log_action(&store, "alice", "document_update", json!({ "document_id": "report-123", "changes": ["title", "status"] })).await?; log_action(&store, "bob", "login_failed", json!({ "reason": "invalid_password", "attempts": 3 })).await?; println!("Audit logs created successfully"); Ok(()) } ``` -------------------------------- ### Handle Many-to-Many Relationships in Sentinel Source: https://sentinel.cyberpath-hq.com/docs/migration-guide This example demonstrates how to implement many-to-many relationships in Sentinel by storing arrays of references. It shows how a user can belong to multiple groups and a group can have multiple users by storing lists of IDs in both the 'users' and 'groups' collections. ```rust // Store array of references users.insert("user-1", json!({ "name": "Alice", "group_ids": ["group-1", "group-2"] })).await?; groups.insert("group-1", json!({ "name": "Admins", "user_ids": ["user-1", "user-2"] })).await?; ``` -------------------------------- ### QueryBuilder::sort Example (Rust) Source: https://sentinel.cyberpath-hq.com/docs/api-reference Demonstrates how to apply sorting to a query using the `sort` method. This example sorts the results by the 'name' field in ascending order. ```rust let query = QueryBuilder::new() .sort("name", SortOrder::Ascending); ``` -------------------------------- ### Handle One-to-Many Relationships in Sentinel Source: https://sentinel.cyberpath-hq.com/docs/migration-guide This example illustrates how to manage one-to-many relationships in Sentinel. It shows how to insert related data, using a foreign key (`user_id`) in the 'posts' collection to reference a document in the 'users' collection. It also demonstrates querying posts associated with a specific user. ```sql -- Users table CREATE TABLE users (id, name, email); -- Posts table with foreign key CREATE TABLE posts (id, user_id, title, content); ``` ```rust // Store user reference in each post users.insert("user-1", json!({ "name": "Alice", "email": "alice@example.com" })).await?; posts.insert("post-1", json!({ "user_id": "user-1", // Reference "title": "My First Post", "content": "Hello world" })).await?; // Query posts by user let user_posts = posts.filter(|doc| { doc.data()["user_id"].as_str() == Some("user-1") }); ``` -------------------------------- ### Stream All Documents Without Loading into Memory (Rust) Source: https://sentinel.cyberpath-hq.com/docs/quick-start This snippet demonstrates how to efficiently process all documents in a collection without loading them entirely into memory. It utilizes Rust's `StreamExt` to iterate over documents as they are read from the database, making it suitable for large datasets. Dependencies include `sentinel_dbms` and `futures`. ```rust use sentinel_dbms::Store; use futures::StreamExt; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; let users = store.collection("users").await?; // Stream all documents let mut all_docs = users.all(); let mut count = 0; while let Some(doc_result) = all_docs.next().await { match doc_result { Ok(doc) => { println!("Document: {}", doc.id()); count += 1; } Err(e) => { eprintln!("Error reading document: {}", e); } } } println!("Total documents processed: {}", count); Ok(()) } ``` -------------------------------- ### QueryBuilder::offset Example (Rust) Source: https://sentinel.cyberpath-hq.com/docs/api-reference Shows how to use the `offset` method to skip a specified number of results. This example sets the offset to 20, meaning the first 20 results will be skipped. ```rust let query = QueryBuilder::new() .offset(20); ``` -------------------------------- ### Sentinel: Implementing Pagination with Limit and Offset Source: https://sentinel.cyberpath-hq.com/docs/querying Provides examples of how to control the number of results and skip records for pagination using the `limit` and `offset` methods in the QueryBuilder. Requires the `sentinel_dbms` crate. ```rust use sentinel_dbms::QueryBuilder; // Get first 10 results let page1 = QueryBuilder::new() .limit(10) .offset(0) .build(); // Get next 10 results (page 2) let page2 = QueryBuilder::new() .limit(10) .offset(10) .build(); // Get results 20-30 (page 3) let page3 = QueryBuilder::new() .limit(10) .offset(20) .build(); ``` -------------------------------- ### Implement User CRUD Operations with Sentinel DBMS (Rust) Source: https://sentinel.cyberpath-hq.com/docs/examples This code implements a `UserManager` struct to handle Create, Read, Update, and Delete (CRUD) operations for users using Sentinel DBMS. It includes functions for creating, retrieving, updating email, deactivating, and deleting users. The example requires `sentinel_dbms`, `serde_json`, `tokio`, and `chrono` crates. ```rust use sentinel_dbms::{Store, Result}; use serde_json::json; struct UserManager { store: Store, } impl UserManager { async fn new(path: &str) -> Result { Ok(Self { store: Store::new(path, None).await?, }) } async fn create_user( &self, username: &str, name: &str, email: &str, role: &str, ) -> Result<()> { let users = self.store.collection("users").await?; users.insert(username, json!({ "name": name, "email": email, "role": role, "status": "active", "created_at": chrono::Utc::now().to_rfc3339() })).await?; println!("User {} created", username); Ok(()) } async fn get_user(&self, username: &str) -> Result> { let users = self.store.collection("users").await?; users.get(username).await } async fn update_email(&self, username: &str, new_email: &str) -> Result<()> { let users = self.store.collection("users").await?; if let Some(mut doc) = users.get(username).await? { let mut data = doc.data().clone(); data["email"] = json!(new_email); users.update(username, data).await?; println!("Email updated for {}", username); } Ok(()) } async fn deactivate_user(&self, username: &str) -> Result<()> { let users = self.store.collection("users").await?; if let Some(doc) = users.get(username).await? { let mut data = doc.data().clone(); data["status"] = json!("inactive"); users.update(username, data).await?; println!("User {} deactivated", username); } Ok(()) } async fn delete_user(&self, username: &str) -> Result<()> { let users = self.store.collection("users").await?; users.delete(username).await?; println!("User {} deleted (moved to .deleted/)", username); Ok(()) } } #[tokio::main] async fn main() -> Result<()> { let manager = UserManager::new("./user_system").await?; // Create users manager.create_user("alice", "Alice Johnson", "alice@example.com", "admin").await?; manager.create_user("bob", "Bob Smith", "bob@example.com", "user").await?; // Get user if let Some(user) = manager.get_user("alice").await? { println!("Found user: {}", user.data()["name"]); } // Update email manager.update_email("alice", "alice.j@example.com").await?; // Deactivate user manager.deactivate_user("bob").await?; // Delete user manager.delete_user("bob").await?; Ok(()) } ``` -------------------------------- ### Use Timestamps for Tracking Source: https://sentinel.cyberpath-hq.com/docs/best-practices Ensures data freshness and auditability by consistently including `created_at` and `updated_at` timestamps in documents. This example uses `chrono::Utc` to generate ISO 8601 formatted timestamps. ```rust use chrono::Utc; collection.insert("doc-1", json!({ "data": "value", "created_at": Utc::now().to_rfc3339(), "updated_at": Utc::now().to_rfc3339() })).await?; ``` -------------------------------- ### Filter Documents Using Closures (Rust) Source: https://sentinel.cyberpath-hq.com/docs/quick-start This example shows how to filter documents within a collection using closures. The `filter` method is applied to a document stream, allowing for inline logic to select specific documents based on their data. It requires `sentinel_dbms`, `futures`, and `serde_json`. The input is a stream of documents, and the output is a filtered stream of documents. ```rust use sentinel_dbms::Store; use futures::StreamExt; use serde_json::json; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; let users = store.collection("users").await?; // Insert test data users.insert("user1", json!({"name": "Alice", "role": "admin"})).await?; users.insert("user2", json!({"name": "Bob", "role": "user"})).await?; users.insert("user3", json!({"name": "Charlie", "role": "admin"})).await?; // Find all admins let mut admins = users.filter(|doc| { doc.data().get("role") .and_then(|v| v.as_str()) .map_or(false, |role| role == "admin") }); while let Some(doc) = admins.next().await { let doc = doc?; println!("Admin: {}", doc.data()["name"]); } Ok(()) } ``` -------------------------------- ### Create and Verify Signed Data with Sentinel DB Source: https://sentinel.cyberpath-hq.com/docs/examples Illustrates how to create a secure store with passphrase protection using sentinel_dbms, automatically signing all inserted documents. It also shows how to retrieve a document and access its hash and signature for integrity verification. ```rust use sentinel_dbms::{Store, Result}; use serde_json::json; #[tokio::main] async fn main() -> Result<()> { // Create store with passphrase protection let store = Store::new("./secure_database", Some("my-secure-passphrase")).await?; let users = store.collection("users").await?; // All documents will be automatically signed users.insert("alice", json!({ "name": "Alice Johnson", "email": "alice@example.com", "role": "admin" })).await?; // Retrieve and verify signature let doc = users.get("alice").await?.expect("Document not found"); println!("Document ID: {}", doc.id()); println!("Hash: {}", doc.hash()); println!("Signature: {}", doc.signature()); println!("Created: {}", doc.created_at()); Ok(()) } ``` ```rust use sentinel_dbms::{Store, Result, hash_data}; #[tokio::main] async fn main() -> Result<()> { let store = Store::new("./my_database", None).await?; let users = store.collection("users").await?; // Get a document let doc = users.get("alice").await?.expect("Document not found"); // Compute current hash let current_hash = hash_data(doc.data()).await?; // Compare with stored hash if current_hash == doc.hash() { println!("✓ Document integrity verified"); } else { println!("✗ Document has been tampered with!"); } Ok(()) } ``` -------------------------------- ### Retrieve Document from Sentinel Collection Source: https://sentinel.cyberpath-hq.com/docs/quick-start Retrieves a document from a Sentinel collection by its ID. Returns an Option, yielding None if the document is not found, preventing errors. ```rust use sentinel_dbms::Store; use serde_json::json; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; let users = store.collection("users").await?; // Retrieve the document if let Some(doc) = users.get("alice").await? { println!("Found user: {}", doc.data()["name"]); println!("Email: {}", doc.data()["email"]); println!("Role: {}", doc.data()["role"]); println!("Created at: {}", doc.created_at()); println!("Hash: {}", doc.hash()); } else { println!("User not found"); } Ok(()) } ``` -------------------------------- ### Sentinel Store Initialization (Signing) Source: https://sentinel.cyberpath-hq.com/docs/troubleshooting Shows how to initialize a Sentinel store, illustrating the difference between initializing with and without a passphrase for signing. The `passphrase` parameter enables signature verification for data integrity. ```rust use sentinel_dbms::Store; // Without signing (signatures are optional) let store_unsigned = Store::new("./data_unsigned", None).await?; // With signing (requires a passphrase) let store_signed = Store::new("./data_signed", Some("my_secure_passphrase")).await?; ``` -------------------------------- ### Get Collection WAL Size Source: https://sentinel.cyberpath-hq.com/docs/api-reference Retrieves the current Write-Ahead Log (WAL) file size in bytes for a collection. It includes an example of checkpointing the WAL if the size exceeds a specified threshold. ```rust use sentinel_dbms::wal::ops::CollectionWalOps; let size = collection.wal_size().await?; println!("WAL size: {} bytes", size); // Checkpoint if exceeds threshold if size > 50 * 1024 * 1024 { collection.checkpoint_wal().await?; } ``` -------------------------------- ### Configure WAL Max Size and Records Source: https://sentinel.cyberpath-hq.com/docs/troubleshooting Demonstrates how to configure the maximum WAL size in bytes and the maximum number of records per file. It also shows how to manually checkpoint the WAL to reclaim space. ```rust config.max_wal_size_bytes = Some(50 * 1024 * 1024); // 50MB max config.max_records_per_file = Some(5000); collection.checkpoint_wal().await?; ``` -------------------------------- ### Delete Document in Sentinel DB Source: https://sentinel.cyberpath-hq.com/docs/quick-start Demonstrates how to delete a single document from a collection using the `delete` method. The operation is idempotent and deleted documents are moved to a `.deleted/` subdirectory for recovery. ```rust use sentinel_dbms::Store; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; let users = store.collection("users").await?; // Delete the document users.delete("alice").await?; println!("Document deleted!"); Ok(()) } ``` -------------------------------- ### Update Document in Sentinel Collection Source: https://sentinel.cyberpath-hq.com/docs/quick-start Updates the content of an existing document in a Sentinel collection identified by its ID. The document's file location is preserved, but its timestamp and hash are updated. ```rust use sentinel_dbms::Store; use serde_json::json; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; let users = store.collection("users").await?; // Update Alice's information users.update("alice", json!({ "name": "Alice Johnson", "email": "alice.johnson@example.com", // New email "role": "senior_admin", // Promoted! "department": "Engineering" })).await?; println!("Document updated!"); Ok(()) } ``` -------------------------------- ### Translate MongoDB Query to Sentinel Source: https://sentinel.cyberpath-hq.com/docs/migration-guide Converts a MongoDB find query with filtering and sorting to its Sentinel equivalent using QueryBuilder. This example shows how to perform similar data retrieval operations in Sentinel. ```rust use sentinel_dbms::{QueryBuilder, Operator, SortOrder}; use serde_json::json; let query = QueryBuilder::new() .filter("age", Operator::GreaterThan, json!(25)) .filter("role", Operator::Equals, json!("admin")) .sort("name", SortOrder::Ascending) .limit(10) .build(); ``` -------------------------------- ### Insert Document into Sentinel Collection Source: https://sentinel.cyberpath-hq.com/docs/quick-start Inserts a new JSON document into a specified Sentinel collection using a unique ID. Sentinel automatically adds metadata such as version, timestamps, and a hash. ```rust use sentinel_dbms::Store; use serde_json::json; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; let users = store.collection("users").await?; // Insert a document with ID "alice" users.insert("alice", json!({ "name": "Alice Johnson", "email": "alice@example.com", "role": "admin", "department": "Engineering" })).await?; println!("Document 'alice' created!"); Ok(()) } ``` -------------------------------- ### Implement Pagination for Sentinel Queries Source: https://sentinel.cyberpath-hq.com/docs/examples Implements a function to retrieve paginated results from a Sentinel collection, sorting by name and applying limit and offset. The main function demonstrates fetching the first two pages. ```rust use sentinel_dbms::{Store, QueryBuilder, SortOrder, Result}; use futures::TryStreamExt; async fn get_page( store: &Store, page: usize, per_page: usize, ) -> Result> { let users = store.collection("users").await?; let query = QueryBuilder::new() .sort("name", SortOrder::Ascending) .limit(per_page) .offset(page * per_page) .build(); let result = users.query(query).await?; result.documents.try_collect().await } #[tokio::main] async fn main() -> Result<()> { let store = Store::new("./my_database", None).await?; // Get first page (10 users) let page1 = get_page(&store, 0, 10).await?; println!("Page 1: {} users", page1.len()); // Get second page let page2 = get_page(&store, 1, 10).await?; println!("Page 2: {} users", page2.len()); Ok(()) } ``` -------------------------------- ### Delete an Entire Collection (Rust) Source: https://sentinel.cyberpath-hq.com/docs/quick-start This snippet shows how to remove a collection and all its associated documents from the Sentinel database. It first creates a temporary collection, adds a document to it, and then proceeds to delete the entire collection. This operation is irreversible. It requires `sentinel_dbms` and `serde_json`. ```rust use sentinel_dbms::Store; use serde_json::json; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./my-database", None).await?; // Create a temporary collection let temp = store.collection("temp").await?; temp.insert("doc1", json!({})).await?; // Delete the entire collection store.delete_collection("temp").await?; println!("Collection deleted!"); Ok(()) } ``` -------------------------------- ### Batch Insert Operations with Checkpointing Source: https://sentinel.cyberpath-hq.com/docs/wal Shows how to perform multiple insert operations in a batch and then checkpoint the Write-Ahead Log (WAL) once afterward. This improves performance for bulk data loading. ```rust use sentinel_dbms::wal::ops::CollectionWalOps; // Insert many documents for i in 0..10000 { collection.insert( &format!("doc-{}", i), serde_json::json!({{"index": i}}) ).await?; } // Checkpoint once after all inserts collection.checkpoint_wal().await?; ``` -------------------------------- ### Initialize Store with Passphrase for Encryption Source: https://sentinel.cyberpath-hq.com/docs/troubleshooting Shows how to initialize the Sentinel store with a passphrase, enabling data-at-rest encryption for tamper detection. ```rust let store = Store::new("./data", Some("passphrase")).await?; ``` -------------------------------- ### Install Rust with Rustup Source: https://sentinel.cyberpath-hq.com/docs/installation Installs Rust and Cargo using the official rustup script. This is a prerequisite for installing Sentinel. ```shell curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` -------------------------------- ### Create Sentinel Store (Rust) Source: https://sentinel.cyberpath-hq.com/docs/store Demonstrates how to create a new Sentinel store, either with or without a passphrase for signing. The `Store::new` function initializes a store at the specified path, creating the root directory if it doesn't exist. This operation is idempotent. ```rust use sentinel_dbms::Store; #[tokio::main] async fn main() -> Result<(), Box> { // Create a store without signing let store = Store::new("./my-data", None).await?; // Or create a store with signing enabled let signed_store = Store::new("./secure-data", Some("my-passphrase")).await?; Ok(()) } ``` -------------------------------- ### Configure Store-Level WAL with Collection Overrides in Rust Source: https://sentinel.cyberpath-hq.com/docs/wal-configuration Demonstrates how to initialize a Sentinel store and apply custom Write-Ahead Logging (WAL) configurations to a specific collection. This includes setting write and verification modes, enabling recovery, and defining maximum WAL file size. ```rust use sentinel_dbms::Store; use sentinel_wal::{StoreWalConfig, WalFailureMode, CollectionWalConfig}; #[tokio::main] async fn main() -> Result<(), Box> { let store = Store::new("./data", None).await?; // Create a custom config let mut wal_config = CollectionWalConfig::default(); wal_config.write_mode = WalFailureMode::Strict; wal_config.verification_mode = WalFailureMode::Warn; wal_config.enable_recovery = true; wal_config.max_wal_size_bytes = Some(50 * 1024 * 1024); // 50MB // Apply to a collection let users = store.collection_with_config("users", Some(wal_config)).await?; Ok(()) } ``` -------------------------------- ### Configure WAL Compression Algorithm in Rust Source: https://sentinel.cyberpath-hq.com/docs/wal-best-practices This Rust code snippet illustrates how to configure the compression algorithm for Write-Ahead Logging (WAL) files. It shows examples for Zstandard (Zstd) for most production workloads, Gzip for archival with lower CPU overhead, and disabling compression entirely for real-time systems where space is less critical. ```rust use sentinel_wal::CompressionAlgorithm; // For most production workloads (recommended) config.compression_algorithm = Some(CompressionAlgorithm::Zstd); // For archival with lower CPU overhead config.compression_algorithm = Some(CompressionAlgorithm::Gzip); // For real-time systems where space is less critical config.compression_algorithm = None; ``` -------------------------------- ### Verify Sentinel Installation with a Test Source: https://sentinel.cyberpath-hq.com/docs/installation A comprehensive test to verify Sentinel installation by creating a store, inserting a document, reading it back, and cleaning up. It confirms that Sentinel is operational. ```rust use sentinel_dbms::Store; use serde_json::json; #[tokio::main] async fn main() -> Result<(), Box> { // Create a temporary store let store = Store::new("./test-data", None).await?; // Create a collection let test = store.collection("test").await?; // Insert a document test.insert("hello", json!({ "message": "Sentinel is working!" })).await?; // Read it back let doc = test.get("hello").await?; println!("{:?}", doc); // Clean up std::fs::remove_dir_all("./test-data")?; println!("✓ Sentinel is installed correctly!"); Ok(()) } ```