### Test setup for Store with temp directory Source: https://docs.rs/grounddb/latest/src/grounddb/store/mod.rs.html Test module setup that creates a temporary directory and a Store with a schema defining a 'users' collection with a path template and required fields. Used as the starting point for tests. ```rust #[cfg(test)] mod tests { use super::*; use tempfile::TempDir; fn setup_test_store() -> (TempDir, Store) { let tmp = TempDir::new().unwrap(); let schema = r#" collections: users: path: "users/{name}.md" fields: name: { type: string, required: true } email: { type: string, required: true } "#; ``` -------------------------------- ### Setup for echo view rebuild test Source: https://docs.rs/grounddb/latest/src/grounddb/store/mod.rs.html Sets up a temporary store with a schema that uses a decorated path template and a view. This is the setup for testing that an API write fires on_view_change once and the watcher echo does not trigger a redundant view rebuild. ```rust let tmp = TempDir::new().unwrap(); let schema = r#" collections: tasks: path: "tasks/{status}/{id}.md" id: { auto: ulid } fields: title: { type: string, required: true } status: { type: string, enum: [open, done], default: open } additional_properties: false strict: true views: open_tasks: query: "SELECT id, title, status FROM tasks WHERE status != 'done'" "#; std::fs::write(tmp.path().join("schema.yaml"), schema).unwrap(); let store = Store::open(tmp.path().to_str().unwrap()).unwrap(); ``` -------------------------------- ### map example Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Shows how to apply a function to the Ok value of a Result, leaving Err untouched. The example parses lines and multiplies by two. ```rust let line = "1\n2\n3\n4\n"; for num in line.lines() { match num.parse::().map(|i| i * 2) { Ok(n) => println!("{n}"), Err(..) => {} } } ``` -------------------------------- ### is_err_and example Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Shows how to use is_err_and to check if a Result is Err and the error value matches a predicate. Includes examples with different error kinds and ownership. ```rust use std::io::{Error, ErrorKind}; let x: Result = Err(Error::new(ErrorKind::NotFound, "!")); assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), true); let x: Result = Err(Error::new(ErrorKind::PermissionDenied, "!")); assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false); let x: Result = Ok(123); assert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false); let x: Result = Err("ownership".to_string()); assert_eq!(x.as_ref().is_err_and(|x| x.len() > 1), true); println!("still alive {:?}", x); ``` -------------------------------- ### ok example Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Demonstrates converting a Result to an Option, returning Some(value) for Ok and None for Err. ```rust let x: Result = Ok(2); assert_eq!(x.ok(), Some(2)); let x: Result = Err("Nothing here"); assert_eq!(x.ok(), None); ``` -------------------------------- ### as_ref example Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Shows how to convert a Result to a Result of references, leaving the original in place. ```rust let x: Result = Ok(2); assert_eq!(x.as_ref(), Ok(&2)); let x: Result = Err("Error"); assert_eq!(x.as_ref(), Err(&"Error")); ``` -------------------------------- ### Test Module Setup and Simple Template Parsing Test Source: https://docs.rs/grounddb/latest/src/grounddb/path_template/mod.rs.html This snippet includes the test module setup and the first test case for parsing a simple template. It verifies that the template 'users/{name}.md' is parsed into the expected segments, including a literal, a field, and another literal. ```rust #[cfg(test)] mod tests { use super::*; use serde_yaml::Value; #[test] fn test_parse_simple_template() { let t = PathTemplate::parse("users/{name}.md").unwrap(); assert_eq!(t.segments.len(), 3); assert_eq!(t.segments[0], PathSegment::Literal("users/".to_string())); assert_eq!( t.segments[1], PathSegment::Field { name: "name".to_string(), format: None, } ); assert_eq!(t.segments[2], PathSegment::Literal(".md".to_string())); } ``` -------------------------------- ### FULL_SCHEMA: Example schema with types, collections, and views Source: https://docs.rs/grounddb/latest/src/grounddb/schema/parser.rs.html A full example schema YAML used in tests, defining types, collections (users, posts, comments, events), and views (post_feed, user_lookup, recent_activity, post_comments). Demonstrates field types, refs, enums, defaults, on_delete behavior, and view queries with materialization and buffer. ```yaml const FULL_SCHEMA: &str = r#" types: address: street: { type: string, required: true } city: { type: string, required: true } state: { type: string } zip: { type: string } collections: users: path: "users/{name}.md" fields: name: { type: string, required: true } email: { type: string, required: true } role: { type: string, enum: [admin, member, guest], default: member } address: { type: address } additional_properties: false strict: true on_delete: error posts: path: "posts/{status}/{date:YYYY-MM-DD}-{title}.md" id: { on_conflict: suffix } fields: title: { type: string, required: true } author_id: { type: ref, target: users, required: true, on_delete: cascade } date: { type: date, required: true } tags: { type: list, items: string } status: { type: string, enum: [draft, published, archived], default: draft } content: true additional_properties: false strict: true comments: path: "comments/{parent:type}/{parent:id}/{user:id}-{created_at:YYYY-MM-DDTHHMM}.md" fields: user: { type: ref, target: users, required: true, on_delete: cascade } parent: { type: ref, target: [posts, comments], required: true, on_delete: cascade } content: true events: path: "events/{id}.md" id: { auto: ulid } fields: type: { type: string, required: true } severity: { type: string, enum: [info, warn, error], default: info } payload: { type: object } additional_properties: true strict: false views: post_feed: query: | SELECT p.title, p.date, p.tags, u.name AS author_name, u.id AS author_id FROM posts p JOIN users u ON p.author_id = u.id WHERE p.status = 'published' ORDER BY p.date DESC LIMIT 100 materialize: true buffer: 2x user_lookup: query: | SELECT id, name, email, role FROM users ORDER BY name ASC materialize: true recent_activity: query: | SELECT id, title, modified_at, status FROM posts ORDER BY modified_at DESC LIMIT 50 materialize: true buffer: 2x post_comments: type: query query: | SELECT c.id, c.created_at, c.content, u.name AS commenter_name FROM comments c JOIN users u ON c.user = u.id WHERE c.parent = :post_id ORDER BY c.created_at ASC params: post_id: { type: string } "#; ``` -------------------------------- ### Product implementation example for Result Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Demonstrates how to use the product method on an iterator of Results, which returns an Err if any element fails to parse. ```rust let nums = vec!["5", "10", "1", "2"]; let total: Result = nums.iter().map(|w| w.parse::()).product(); assert_eq!(total, Ok(100)); let nums = vec!["5", "10", "one", "2"]; let total: Result = nums.iter().map(|w| w.parse::()).product(); assert!(total.is_err()); ``` -------------------------------- ### Setup store with views and schema Source: https://docs.rs/grounddb/latest/src/grounddb/store/mod.rs.html Sets up a temporary store with a schema defining users, posts, and three views (post_feed, user_lookup, all_posts). The schema includes required fields, enums, defaults, and a materialized view with a buffer. ```rust fn setup_store_with_views() -> (TempDir, Store) { let tmp = TempDir::new().unwrap(); let schema = r#" collections: users: path: "users/{name}.md" fields: name: { type: string, required: true } email: { type: string, required: true } role: { type: string, enum: [admin, member, guest], default: member } additional_properties: false strict: true on_delete: error posts: path: "posts/{status}/{date:YYYY-MM-DD}-{title}.md" id: { on_conflict: suffix } fields: title: { type: string, required: true } author_id: { type: ref, target: users, required: true, on_delete: cascade } date: { type: date, required: true } tags: { type: list, items: string } status: { type: string, enum: [draft, published, archived], default: draft } content: true additional_properties: false strict: true views: post_feed: query: | SELECT p.title, p.date, u.name AS author_name FROM posts p JOIN users u ON p.author_id = u.id WHERE p.status = 'published' ORDER BY p.date DESC LIMIT 100 materialize: true buffer: 2x user_lookup: query: | SELECT id, name, email, role FROM users ORDER BY name ASC materialize: false all_posts: query: | SELECT id, title, status, date FROM posts ORDER BY date DESC materialize: false "#; std::fs::write(tmp.path().join("schema.yaml"), schema).unwrap(); std::fs::create_dir_all(tmp.path().join("users")).unwrap(); std::fs::create_dir_all(tmp.path().join("posts")).unwrap(); let store = Store::open(tmp.path().to_str().unwrap()).unwrap(); (tmp, store) } ``` -------------------------------- ### SystemDb Implementation Source: https://docs.rs/grounddb/latest/src/grounddb/system_db/mod.rs.html The core structure and initialization logic for the system database, including connection configuration and WAL mode setup. ```rust 1use crate::error::{GroundDbError, Result}; 2use crate::util::json_to_yaml; 3use rusqlite::{params, Connection, OptionalExtension}; 4use std::collections::HashMap; 5use std::path::Path; 6use std::sync::Mutex; 7 8/// How long a connection retries a lock held by another connection before 9/// giving up with `SQLITE_BUSY`. 10/// 11/// This happens to match the default rusqlite installs on every connection, but 12/// we set it explicitly: that default is an implementation detail of the 13/// dependency, and the correctness of multi-process access should not silently 14/// change when rusqlite is upgraded. 15pub const BUSY_TIMEOUT_MS: u64 = 5000; 16 17/// The system database that manages document index, schema state, and view cache. 18/// Uses a Mutex around the connection so Store can be Send + Sync. 19pub struct SystemDb { 20 conn: Mutex, 21} 22 23impl SystemDb { 24 /// Open or create the system database at the given path. 25 pub fn open(path: &Path) -> Result { 26 let conn = Connection::open(path)?; 27 Self::configure(&conn, true)?; 28 let db = SystemDb { conn: Mutex::new(conn) }; 29 db.initialize_tables()?; 30 Ok(db) 31 } 32 33 /// Open an in-memory system database (for testing). 34 pub fn open_in_memory() -> Result { 35 let conn = Connection::open_in_memory()?; 36 Self::configure(&conn, false)?; 37 let db = SystemDb { conn: Mutex::new(conn) }; 38 db.initialize_tables()?; 39 Ok(db) 40 } 41 42 /// Apply connection-level pragmas. Must run before any statement that opens 43 /// a transaction, because `journal_mode` cannot be changed inside one. 44 /// 45 /// ## What WAL buys us, and what it does not 46 /// 47 /// The store is reachable from more than one OS process. The `Mutex` around 48 /// the connection is an *in-process* lock — it exists so `Store` can be 49 /// `Send + Sync` — so between processes the only arbiter is SQLite itself. 50 /// 51 /// In the default rollback-journal mode a writer's `RESERVED` lock escalates 52 /// to `EXCLUSIVE` at commit, which locks readers out, and a reader that is 53 /// already mid-statement can force the writer to fail. WAL removes that 54 /// contention in one direction only: **readers never block writers and 55 /// writers never block readers**, because readers work from a snapshot. 56 /// 57 /// WAL does *not* make multi-process writing free: 58 /// 59 /// - **Writers are still serialized.** Exactly one write transaction may be 60 /// in flight per database. The improvement is that a second writer now 61 /// *waits* out the [`BUSY_TIMEOUT_MS`] window instead of erroring 62 /// immediately — and it still errors if the holder outlives that window. 63 /// - **WAL needs shared memory.** It coordinates through a `-shm` file 64 /// mapped by every connection, so it does not work over network 65 /// filesystems (NFS, SMB, most container/VM shares). SQLite will refuse to 66 /// enter WAL there, which is why the mode is read back rather than 67 /// assumed. 68 /// - **Two extra files appear** next to the database (`-wal` and `-shm`). 69 /// Anything that copies or deletes the store must treat them as part of it. 70 /// 71 /// WAL is meaningless for an in-memory database — there is no second process 72 /// to share it with and no file to map — so it is only requested on disk. 73 fn configure(conn: &Connection, on_disk: bool) -> Result<()> { 74 conn.busy_timeout(std::time::Duration::from_millis(BUSY_TIMEOUT_MS))?; 75 76 if on_disk { 77 // `PRAGMA journal_mode` returns the mode actually in effect, which 78 // may not be the one asked for (a network filesystem cannot do WAL). 79 // Reading it back keeps a silent downgrade from looking like success 80 // — the store still works, just with the old contention behaviour. 81 let mode: String = conn.query_row("PRAGMA journal_mode = WAL", [], |row| row.get(0))?; 82 if !mode.eq_ignore_ascii_case("wal") { 83 log::warn!( 84 "system db could not enter WAL mode (still '{mode}'); \ 85 concurrent access will contend as before. \ 86 This is expected on network filesystems." 87 ); 88 } 89 } 90 91 Ok(()) 92 } 93 94 fn conn(&self) -> std::sync::MutexGuard<'_, Connection> { 95 self.conn.lock().unwrap() 96 } 97 98 /// The journal mode this connection is running in (`"wal"`, `"memory"`, 99 /// `"delete"`, …). Exposed for diagnostics and tests. 100 pub fn journal_mode(&self) -> Result { 101 let mode = self 102 .conn() ``` -------------------------------- ### err example Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Demonstrates converting a Result to an Option, returning Some(error) for Err and None for Ok. ```rust let x: Result = Ok(2); assert_eq!(x.err(), None); let x: Result = Err("Nothing here"); assert_eq!(x.err(), Some("Nothing here")); ``` -------------------------------- ### as_mut example Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Demonstrates converting a mutable Result to a Result of mutable references, allowing mutation of the contained value. ```rust fn mutate(r: &mut Result) { match r.as_mut() { Ok(v) => *v = 42, Err(e) => *e = 0, } } let mut x: Result = Ok(2); mutate(&mut x); assert_eq!(x.unwrap(), 42); let mut x: Result = Err(13); mutate(&mut x); assert_eq!(x.unwrap_err(), 0); ``` -------------------------------- ### Test subscription unsubscribe Source: https://docs.rs/grounddb/latest/src/grounddb/store/mod.rs.html Demonstrates the setup for unsubscribing from collection changes. ```rust #[test] fn test_subscription_unsubscribe() { let (_tmp, store) = setup_test_store(); let received = Arc::new(Mutex::new(Vec::::new())); let received_clone = received.clone(); let sub_id = store.on_collection_change( "users", Box::new(move |event| { received_clone.lock().unwrap().push(event); }), ); // Insert then unsubscribe let users = store.collection("users").unwrap(); ``` -------------------------------- ### Test file move reconciles yaml status setup Source: https://docs.rs/grounddb/latest/src/grounddb/store/mod.rs.html Initializes a test store for the file move reconciliation test. ```rust let (tmp, store) = setup_test_store(); ``` -------------------------------- ### Setup decorated store with path template Source: https://docs.rs/grounddb/latest/src/grounddb/store/mod.rs.html Creates a temporary store with a decorated path template `tasks/{status}/{id}-{title}.md`, auto ULID ids, and strict schema. Returns the temp dir and store for tests. ```rust let tmp = TempDir::new().unwrap(); let schema = r#" collections: tasks: path: "tasks/{status}/{id}-{title}.md" id: { auto: ulid } fields: title: { type: string, required: true } status: { type: string, enum: [open, done], default: open } additional_properties: false strict: true "#; std::fs::write(tmp.path().join("schema.yaml"), schema).unwrap(); let store = Store::open(tmp.path().to_str().unwrap()).unwrap(); (tmp, store) ``` -------------------------------- ### map_or_default example Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Demonstrates map_or_default, which applies a function to the Ok value or returns the default value for the type U when Err. ```rust let x: Result<_, &str> = Ok("foo"); let y: Result<&str, _> = Err("bar"); assert_eq!(x.map_or_default(|x| x.len()), 3); assert_eq!(y.map_or_default(|y| y.len()), 0); ``` -------------------------------- ### expect: Recommended message style Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Shows the recommended style for `expect` messages: describe the reason you expect the `Result` to be `Ok`. The example expects an environment variable to be set by a wrapper script. ```rust let path = std::env::var("IMPORTANT_PATH") .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); ``` -------------------------------- ### Sum implementation example for Result Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Demonstrates how to use the sum method on an iterator of Results, which returns an Err if a negative element is encountered. ```rust let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) }; let v = vec![1, 2]; let res: Result = v.iter().map(f).sum(); assert_eq!(res, Ok(3)); let v = vec![1, -2]; let res: Result = v.iter().map(f).sum(); assert_eq!(res, Err("Negative element found")); ``` -------------------------------- ### map_or_else example Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Shows how to use map_or_else to apply a fallback function to the Err value or a function to the Ok value. ```rust let k = 21; let x : Result<_, &str> = Ok("foo"); assert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 3); let x : Result<&str, _> = Err("bar"); assert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 42); ``` -------------------------------- ### is_ok() on Result Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Example for the `is_ok` method, which returns `true` if the result is `Ok`. ```rust let x: Result = Ok(-3); assert_eq!(x.is_ok(), true); let x: Result = Err("Some error message"); assert_eq!(x.is_ok(), false); ``` -------------------------------- ### test_user_lookup_view_parsing: Retrieve user_lookup view Source: https://docs.rs/grounddb/latest/src/grounddb/view/mod.rs.html Starts testing the user_lookup view parsing by retrieving it from the engine. The test is incomplete in the source. ```rust #[test] fn test_user_lookup_view_parsing() { let schema = test_schema(); let engine = ViewEngine::new(&schema).unwrap(); let lookup = engine.get_view("user_lookup").unwrap(); ``` -------------------------------- ### FromIterator implementation for Result Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Examples showing how FromIterator collects Results, stopping at the first Err encountered. ```rust let v = vec![1, 2]; let res: Result, &'static str> = v.iter().map(|x: &u32| x.checked_add(1).ok_or("Overflow!") ).collect(); assert_eq!(res, Ok(vec![2, 3])); ``` ```rust let v = vec![1, 2, 0]; let res: Result, &'static str> = v.iter().map(|x: &u32| x.checked_sub(1).ok_or("Underflow!") ).collect(); assert_eq!(res, Err("Underflow!")); ``` ```rust let v = vec![3, 2, 1, 10]; let mut shared = 0; let res: Result, &'static str> = v.iter().map(|x: &u32| { shared += x; x.checked_sub(2).ok_or("Underflow!") }).collect(); assert_eq!(res, Err("Underflow!")); assert_eq!(shared, 6); ``` -------------------------------- ### inspect: Run closure on Ok value Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Demonstrates `inspect` to run a closure on the `Ok` value without changing it. The example parses a string, prints the original value, then cubes it and expects success. ```rust let x: u8 = "4" .parse::() .inspect(|x| println!("original: {x}")) .map(|x| x.pow(3)) .expect("literal `4` should parse as a `u8`"); ``` -------------------------------- ### transpose() on Result, E> Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Example for the `transpose` method on `Result, E>`, which converts a `Result` of an `Option` into an `Option` of a `Result`. `Ok(None)` maps to `None`; `Ok(Some(_))` and `Err(_)` map to `Some(Ok(_))` and `Some(Err(_))`. ```rust #[derive(Debug, Eq, PartialEq)] struct SomeErr; let x: Result, SomeErr> = Ok(Some(5)); let y: Option> = Some(Ok(5)); assert_eq!(x.transpose(), y); ``` -------------------------------- ### open Source: https://docs.rs/grounddb/latest/grounddb/store/struct.Store.html Opens a GroundDB store at the given data directory path. Parses schema.yaml, opens/creates _system.db, and runs the boot lifecycle. ```APIDOC ## open(path: &str) -> Result ### Description Opens a GroundDB store at the given data directory path. Parses schema.yaml, opens/creates _system.db, and runs the boot lifecycle. ### Method open ### Parameters - **path** (string) - Required - The data directory path. ### Returns - **Result** - The opened store instance or an error. ``` -------------------------------- ### iter_mut: Mutate contained value via iterator Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Shows `iter_mut` to get a mutable iterator over the possibly contained value. The example mutates the `Ok` value and verifies that `Err` yields no items. ```rust let mut x: Result = Ok(7); match x.iter_mut().next() { Some(v) => *v = 40, None => {}, } assert_eq!(x, Ok(40)); let mut x: Result = Err("nothing!"); assert_eq!(x.iter_mut().next(), None); ``` -------------------------------- ### Open a GroundDB Store and Access a Collection Source: https://docs.rs/grounddb Demonstrates how to initialize a store from a data directory and retrieve a collection to list its documents. ```rust use grounddb::Store; let store = Store::open("data").unwrap(); // Access a collection let users = store.collection("users").unwrap(); let docs = users.list().unwrap(); ``` -------------------------------- ### Collection struct with get, list, and insert methods Source: https://docs.rs/grounddb/latest/src/grounddb/store/mod.rs.html Defines the `Collection` struct and its core methods: `definition`, `template`, `get`, `list`, and the beginning of `insert`. The `get` method reads the document file and overrides the ID with the index record's ID, noting that the file stem is not authoritative for decorated paths. `list` reads all documents, skipping missing files and logging warnings. ```rust /// A handle to a collection within a store. /// Provides CRUD operations using serde_yaml::Value for dynamic data. pub struct Collection<'a> { store: &'a Store, name: String, } impl<'a> Collection<'a> { fn definition(&self) -> &CollectionDefinition { &self.store.schema.collections[&self.name] } fn template(&self) -> &PathTemplate { &self.store.path_templates[&self.name] } /// Get a document by ID pub fn get(&self, id: &str) -> Result> { let record = self .store .db .get_document(&self.name, id)? .ok_or_else(|| GroundDbError::NotFound { collection: self.name.clone(), id: id.to_string(), })?; let file_path = self.store.root.join(&record.path); let mut doc = document::read_document(&file_path)?; // The index id is authoritative; the file stem is not the id for a // decorated path (`{id}-{title}.md`). doc.id = record.id; Ok(doc) } /// List all documents in this collection pub fn list(&self) -> Result>> { let records = self.store.db.list_documents(&self.name)?; let mut docs = Vec::new(); for record in &records { let file_path = self.store.root.join(&record.path); if file_path.exists() { match document::read_document(&file_path) { Ok(mut doc) => { // Index id is authoritative (see Collection::get). doc.id = record.id.clone(); docs.push(doc); } Err(e) => { log::warn!("Failed to read document {}: {}", record.path, e); } } } } Ok(docs) } /// Insert a new document. Returns the document ID. pub fn insert( &self, mut data: serde_yaml::Value, ``` -------------------------------- ### schema Source: https://docs.rs/grounddb/latest/grounddb/store/struct.Store.html Gets the schema definition. ```APIDOC ## schema() -> &SchemaDefinition ### Description Gets the schema definition. ### Method schema ### Returns - **&SchemaDefinition** - The schema definition. ``` -------------------------------- ### get_document Source: https://docs.rs/grounddb/latest/grounddb/store/struct.Store.html Gets a typed document from a collection. ```APIDOC ## get_document(&self, collection_name: &str, id: &str) -> Result> ### Description Gets a typed document from a collection. ### Method get_document ### Parameters - **collection_name** (string) - Required - The collection name. - **id** (string) - Required - The document ID. ### Returns - **Result>** - The typed document or an error. ``` -------------------------------- ### get Source: https://docs.rs/grounddb/latest/grounddb/store/struct.Collection.html Retrieves a document by its ID from the collection. ```APIDOC ## get ### Description Retrieves a document by its ID from the collection. ### Method pub fn get(&self, id: &str) -> Result> ### Parameters - **id** (str) - Required - The ID of the document to retrieve. ### Returns - **Result>** - The document with the given ID, or an error if not found. ``` -------------------------------- ### SystemDb::open Source: https://docs.rs/grounddb/latest/grounddb/system_db/struct.SystemDb.html Opens or creates the system database at the given path. ```APIDOC ## SystemDb::open ### Description Opens or creates the system database at the given path. ### Method open ### Parameters - **path** (`&Path`) - Required - The filesystem path to the database file. ### Returns - `Result` - The opened SystemDb instance or an error. ``` -------------------------------- ### root Source: https://docs.rs/grounddb/latest/grounddb/store/struct.Store.html Gets the root data directory path. ```APIDOC ## root() -> &Path ### Description Gets the root data directory path. ### Method root ### Returns - **&Path** - The root data directory path. ``` -------------------------------- ### SystemDb::get_view_data Source: https://docs.rs/grounddb/latest/grounddb/system_db/struct.SystemDb.html Gets cached view data. ```APIDOC ## SystemDb::get_view_data ### Description Gets cached view data. ### Method get_view_data ### Parameters - **view_name** (`&str`) - Required - The view name. ### Returns - `Result>` - The cached view data, or None if not found. ``` -------------------------------- ### SystemDb::get_last_schema_hash Source: https://docs.rs/grounddb/latest/grounddb/system_db/struct.SystemDb.html Gets the most recent schema hash. ```APIDOC ## SystemDb::get_last_schema_hash ### Description Gets the most recent schema hash. ### Method get_last_schema_hash ### Parameters None. ### Returns - `Result>` - The most recent schema hash, or None if none exists. ``` -------------------------------- ### SystemDb::get_directory_hash Source: https://docs.rs/grounddb/latest/grounddb/system_db/struct.SystemDb.html Gets the stored directory hash for a collection. ```APIDOC ## SystemDb::get_directory_hash ### Description Gets the stored directory hash for a collection. ### Method get_directory_hash ### Parameters - **collection** (`&str`) - Required - The collection name. ### Returns - `Result>` - The directory hash, or None if not set. ``` -------------------------------- ### SystemDb::get_document Source: https://docs.rs/grounddb/latest/grounddb/system_db/struct.SystemDb.html Gets a document from the index by collection and id. ```APIDOC ## SystemDb::get_document ### Description Gets a document from the index by collection and id. ### Method get_document ### Parameters - **collection** (`&str`) - Required - The collection name. - **id** (`&str`) - Required - The document ID. ### Returns - `Result>` - The document record, or None if not found. ``` -------------------------------- ### Test view execution with LIMIT Source: https://docs.rs/grounddb/latest/src/grounddb/store/mod.rs.html Demonstrates configuring a view with a SQL LIMIT clause and verifying that the result set is restricted accordingly. ```rust #[test] fn test_view_execution_limit() { let tmp = TempDir::new().unwrap(); let schema = r#" collections: users: path: "users/{name}.md" fields: name: { type: string, required: true } email: { type: string, required: true } additional_properties: false strict: true views: recent_users: query: | SELECT id, name FROM users ORDER BY name ASC LIMIT 2 materialize: false "#; std::fs::write(tmp.path().join("schema.yaml"), schema).unwrap(); std::fs::create_dir_all(tmp.path().join("users")).unwrap(); let store = Store::open(tmp.path().to_str().unwrap()).unwrap(); // Insert 3 users let users = store.collection("users").unwrap(); users.insert( serde_yaml::from_str("name: Alice\nemail: a@test.com").unwrap(), None, ).unwrap(); users.insert( serde_yaml::from_str("name: Bob\nemail: b@test.com").unwrap(), None, ).unwrap(); users.insert( serde_yaml::from_str("name: Charlie\nemail: c@test.com").unwrap(), None, ).unwrap(); let result = store.view_dynamic("recent_users").unwrap(); let rows = result.as_array().unwrap(); // LIMIT 2 should restrict to 2 rows assert_eq!(rows.len(), 2); } ``` -------------------------------- ### SystemDb::get_last_schema_yaml Source: https://docs.rs/grounddb/latest/grounddb/system_db/struct.SystemDb.html Gets the most recent schema YAML content. ```APIDOC ## SystemDb::get_last_schema_yaml ### Description Gets the most recent schema YAML content. ### Method get_last_schema_yaml ### Parameters None. ### Returns - `Result>` - The most recent schema YAML content, or None if none exists. ``` -------------------------------- ### validate_and_prepare: Apply defaults and validate document Source: https://docs.rs/grounddb/latest/src/grounddb/validation/mod.rs.html Applies defaults and validates a document. Returns an error if strict validation fails, otherwise returns warnings. ```rust pub fn validate_and_prepare( schema: &SchemaDefinition, collection: &CollectionDefinition, data: &mut serde_yaml::Value, ) -> Result> { apply_defaults(collection, data); let result = validate_document(schema, collection, data); if !result.is_ok() { return Err(GroundDbError::Validation(format!( "Document validation failed:\n - {}", result.errors.join("\n - ") ))); } Ok(result.warnings) } ``` -------------------------------- ### Batch::collection Source: https://docs.rs/grounddb/latest/grounddb/store/struct.Batch.html Get a handle for queuing operations on a collection. ```APIDOC ## Batch::collection ### Description Get a handle for queuing operations on a collection. ### Method collection ### Signature pub fn collection(&mut self, name: &str) -> BatchCollection<'a, '_> ### Parameters - **name** (&str) - The name of the collection. ### Returns - **BatchCollection<'a, '_>** - A handle for queuing operations on the collection. ``` -------------------------------- ### collection Source: https://docs.rs/grounddb/latest/grounddb/store/struct.Store.html Gets a dynamic collection handle (uses serde_yaml::Value as the data type). ```APIDOC ## collection(name: &str) -> Result> ### Description Gets a dynamic collection handle (uses serde_yaml::Value as the data type). ### Method collection ### Parameters - **name** (string) - Required - The collection name. ### Returns - **Result>** - A collection handle or an error. ``` -------------------------------- ### test_schema: Build test schema with collections and views Source: https://docs.rs/grounddb/latest/src/grounddb/view/mod.rs.html Creates a test schema with collections and views for unit tests. Defines users, posts, and three views (post_feed, user_lookup, post_comments) with queries, materialization, and parameters. ```rust fn test_schema() -> SchemaDefinition { parse_schema_str( r#" collections: users: path: "users/{name}.md" fields: name: { type: string, required: true } email: { type: string, required: true } role: { type: string, enum: [admin, member, guest], default: member } posts: path: "posts/{status}/{date:YYYY-MM-DD}-{title}.md" fields: title: { type: string, required: true } author_id: { type: ref, target: users, required: true } date: { type: date, required: true } status: { type: string, enum: [draft, published, archived], default: draft } content: true views: post_feed: query: | SELECT p.title, p.date, u.name AS author_name FROM posts p JOIN users u ON p.author_id = u.id WHERE p.status = 'published' ORDER BY p.date DESC LIMIT 100 materialize: true buffer: 2x user_lookup: query: | SELECT id, name, email, role FROM users ORDER BY name ASC materialize: true post_comments: type: query query: | SELECT c.id, c.created_at FROM posts c WHERE c.id = :post_id ORDER BY c.created_at ASC params: post_id: { type: string } "#, ) .unwrap() } ``` -------------------------------- ### List Documents Source: https://docs.rs/grounddb/latest/src/grounddb/system_db/mod.rs.html Shows how to list all documents within a specific collection. ```rust let db = SystemDb::open_in_memory().unwrap(); let data1: serde_yaml::Value = serde_yaml::from_str("name: Alice").unwrap(); let data2: serde_yaml::Value = serde_yaml::from_str("name: Bob").unwrap(); db.upsert_document("alice", "users", "users/alice.md", &data1, None, None, None).unwrap(); db.upsert_document("bob", "users", "users/bob.md", &data2, None, None, None).unwrap(); let docs = db.list_documents("users").unwrap(); assert_eq!(docs.len(), 2); ``` -------------------------------- ### Result::unwrap usage Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Demonstrates basic usage of unwrap and how it panics on an Err variant. ```rust let x: Result = Ok(2); assert_eq!(x.unwrap(), 2); ``` ```rust let x: Result = Err("emergency failure"); x.unwrap(); // panics with `emergency failure` ``` -------------------------------- ### new(schema: &SchemaDefinition) -> Result Source: https://docs.rs/grounddb/latest/grounddb/view/struct.ViewEngine.html Creates a new view engine from schema view definitions. ```APIDOC ## new(schema: &SchemaDefinition) -> Result ### Description Creates a new view engine from schema view definitions. ### Method new ### Parameters - **schema** (&SchemaDefinition) - Required - The schema definition containing view definitions. ### Returns - **Result** - A new ViewEngine instance or an error. ``` -------------------------------- ### get_view_data(&self, name: &str) -> Option> Source: https://docs.rs/grounddb/latest/grounddb/view/struct.ViewEngine.html Gets a clone of the current data for a static view. ```APIDOC ## get_view_data(&self, name: &str) -> Option> ### Description Gets a clone of the current data for a static view. ### Method get_view_data ### Parameters - **name** (&str) - Required - The name of the view. ### Returns - **Option>** - A clone of the view data if found, otherwise None. ``` -------------------------------- ### Test insert and list users (Rust) Source: https://docs.rs/grounddb/latest/src/grounddb/store/mod.rs.html Test that inserts two users and verifies the list returns both. Uses the setup_test_store helper and the users collection. ```rust let (_tmp, store) = setup_test_store(); let users = store.collection("users").unwrap(); let data1: serde_yaml::Value = serde_yaml::from_str("name: Alice\nemail: alice@test.com").unwrap(); let data2: serde_yaml::Value = serde_yaml::from_str("name: Bob\nemail: bob@test.com").unwrap(); users.insert(data1, None).unwrap(); users.insert(data2, None).unwrap(); let docs = users.list().unwrap(); assert_eq!(docs.len(), 2); ``` -------------------------------- ### Test explain_view output Source: https://docs.rs/grounddb/latest/src/grounddb/store/mod.rs.html Tests explain_view output for a view. Asserts the returned JSON contains the view name, original SQL with SELECT, rewritten SQL with WITH, and expected limit/buffer_limit/is_query_template values. ```rust let (_tmp, store) = setup_store_with_views(); let result = store.explain_view("post_feed").unwrap(); assert_eq!(result["view"], "post_feed"); assert!(result["original_sql"].as_str().unwrap().contains("SELECT")); assert!(result["rewritten_sql"].as_str().unwrap().contains("WITH")); assert_eq!(result["limit"], 100); assert_eq!(result["buffer_limit"], 200); assert_eq!(result["is_query_template"], false); ``` -------------------------------- ### get_view(&self, name: &str) -> Option<&ParsedView> Source: https://docs.rs/grounddb/latest/grounddb/view/struct.ViewEngine.html Gets the parsed view metadata for a given view name. ```APIDOC ## get_view(&self, name: &str) -> Option<&ParsedView> ### Description Gets the parsed view metadata for a given view name. ### Method get_view ### Parameters - **name** (&str) - Required - The name of the view. ### Returns - **Option<&ParsedView>** - The parsed view metadata if found, otherwise None. ``` -------------------------------- ### flatten() removes one level at a time Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Additional example for `flatten` showing that it only removes one level of nesting at a time. ```rust let x: Result, u32>, u32> = Ok(Ok(Ok("hello"))); assert_eq!(Ok(Ok("hello")), x.flatten()); assert_eq!(Ok("hello"), x.flatten().flatten()); ``` -------------------------------- ### SchemaMigration Implementation Methods Source: https://docs.rs/grounddb/latest/src/grounddb/migration/mod.rs.html Provides methods to check if a migration is safe to auto-apply and to generate a human-readable description of the change. ```rust 44impl SchemaMigration { 45 /// Whether this migration is safe to auto-apply without user intervention. 46 pub fn is_safe(&self) -> bool { 47 match self { 48 SchemaMigration::CollectionAdded { .. } => true, 49 SchemaMigration::EnumValueAdded { .. } => true, 50 SchemaMigration::FieldAdded { has_default, required, .. } => { 51 // Safe if has a default or is not required 52 *has_default || !*required 53 } 54 SchemaMigration::DefaultChanged { .. } => true, 55 _ => false, 56 } 57 } 58 59 /// Human-readable description of this migration. 60 pub fn describe(&self) -> String { 61 match self { 62 SchemaMigration::CollectionAdded { name } => { 63 format!("Collection '{}' added", name) 64 } 65 SchemaMigration::CollectionRemoved { name } => { 66 format!("Collection '{}' removed (data preserved)", name) 67 } 68 SchemaMigration::FieldAdded { collection, field, has_default, required } => { 69 let qualifier = if *required && !*has_default { 70 " (required, no default — ERROR)" 71 } else if *has_default { 72 " (has default — will backfill)" 73 } else { 74 " (optional)" 75 }; 76 format!("Field '{}.{}' added{}", collection, field, qualifier) 77 } 78 SchemaMigration::FieldRemoved { collection, field } => { 79 format!("Field '{}.{}' removed", collection, field) 80 } 81 SchemaMigration::FieldTypeChanged { collection, field } => { 82 format!("Field '{}.{}' type changed (ERROR)", collection, field) 83 } 84 SchemaMigration::EnumValueAdded { collection, field, value } => { 85 format!("Enum value '{}' added to '{}.{}'", value, collection, field) 86 } 87 SchemaMigration::EnumValueRemoved { collection, field, value } => { 88 format!("Enum value '{}' removed from '{}.{}' (WARNING)", value, collection, field) 89 } 90 SchemaMigration::PathTemplateChanged { collection, old_template, new_template } => { 91 format!( 92 "Path template for '{}' changed: '{}' -> '{}' (WARNING)", 93 collection, old_template, new_template 94 ) 95 } 96 SchemaMigration::DefaultChanged { collection, field } => { 97 format!("Default value for '{}.{}' changed", collection, field) 98 } 99 } 100 } 101} ``` -------------------------------- ### cloned() on Result<&T, E> Source: https://docs.rs/grounddb/latest/grounddb/error/type.Result.html Example for the `cloned` method on `Result<&T, E>`, which clones the contents of the `Ok` part. Requires `T: Clone`. ```rust let val = 12; let x: Result<&i32, i32> = Ok(&val); assert_eq!(x, Ok(&12)); let cloned = x.cloned(); assert_eq!(cloned, Ok(12)); ``` -------------------------------- ### test_view_engine_creation: Assert engine creates three views Source: https://docs.rs/grounddb/latest/src/grounddb/view/mod.rs.html Verifies that ViewEngine::new successfully parses the test schema and creates three views with the expected keys. ```rust #[test] fn test_view_engine_creation() { let schema = test_schema(); let engine = ViewEngine::new(&schema).unwrap(); assert_eq!(engine.views.len(), 3); assert!(engine.views.contains_key("post_feed")); assert!(engine.views.contains_key("user_lookup")); assert!(engine.views.contains_key("post_comments")); } ``` -------------------------------- ### Test validate_and_prepare Source: https://docs.rs/grounddb/latest/src/grounddb/validation/mod.rs.html Validates and prepares a document, expecting no warnings and the default 'role' value applied. ```rust let schema = test_schema(); let collection = &schema.collections["users"]; let mut data: serde_yaml::Value = serde_yaml::from_str( "name: Alice\nemail: alice@test.com", ) .unwrap(); let warnings = validate_and_prepare(&schema, collection, &mut data).unwrap(); assert!(warnings.is_empty()); // Default should be applied assert_eq!( data["role"], serde_yaml::Value::String("member".into()) ); ```