Skip to main content

Collection

Trait Collection 

Source
pub trait Collection: Send + Sync {
    // Required methods
    fn upsert(&self, doc_id: &str, data: Vec<u8>) -> Result<(), Error>;
    fn get(&self, doc_id: &str) -> Result<Option<Vec<u8>>, Error>;
    fn delete(&self, doc_id: &str) -> Result<(), Error>;
    fn scan(&self) -> Result<Vec<(String, Vec<u8>)>, Error>;
    fn find(
        &self,
        predicate: Box<dyn Fn(&[u8]) -> bool + Send>,
    ) -> Result<Vec<(String, Vec<u8>)>, Error>;
    fn query_geohash_prefix(
        &self,
        prefix: &str,
    ) -> Result<Vec<(String, Vec<u8>)>, Error>;
    fn count(&self) -> Result<usize, Error>;
}
Expand description

Collection trait for storing and querying documents

A collection is a logical grouping of documents (key-value pairs). Documents are stored as raw bytes (typically serialized protobuf).

§Document Storage Format

  • Key: String document ID (e.g., “cell-1”, “node-abc123”)
  • Value: Raw bytes (serialized protobuf message)

§Thread Safety

All operations are thread-safe. Multiple threads can read/write concurrently.

§Example

let cells = storage.collection("cells");

// Create and store a cell
let cell = CellState { id: "cell-1".to_string(), ..Default::default() };
let bytes = cell.encode_to_vec();
cells.upsert("cell-1", bytes)?;

// Retrieve the cell
if let Some(stored) = cells.get("cell-1")? {
    let cell = CellState::decode(&stored[..])?;
    println!("Retrieved cell: {}", cell.id);
}

// Query all cells
for (id, bytes) in cells.scan()? {
    let cell = CellState::decode(&bytes[..])?;
    println!("Cell {}: {:?}", id, cell);
}

Required Methods§

Source

fn upsert(&self, doc_id: &str, data: Vec<u8>) -> Result<(), Error>

Insert or update a document

If a document with the given ID exists, it is replaced. Otherwise, a new document is created.

§Arguments
  • doc_id - Unique document identifier
  • data - Serialized document bytes (typically protobuf)
§Returns

Ok(()) on success, Err if upsert fails

§Example
let cell = CellState { id: "cell-1".to_string(), ..Default::default() };
cells.upsert("cell-1", cell.encode_to_vec())?;
Source

fn get(&self, doc_id: &str) -> Result<Option<Vec<u8>>, Error>

Get a document by ID

§Arguments
  • doc_id - Document identifier to retrieve
§Returns
  • Ok(Some(bytes)) if document exists
  • Ok(None) if document not found
  • Err if query fails
§Example
match cells.get("cell-1")? {
    Some(bytes) => {
        let cell = CellState::decode(&bytes[..])?;
        println!("Found cell: {}", cell.id);
    }
    None => println!("Cell not found"),
}
Source

fn delete(&self, doc_id: &str) -> Result<(), Error>

Delete a document by ID

If the document doesn’t exist, this is a no-op (not an error).

§Arguments
  • doc_id - Document identifier to delete
§Returns

Ok(()) on success (whether or not document existed), Err if delete fails

§Example
cells.delete("cell-1")?;
Source

fn scan(&self) -> Result<Vec<(String, Vec<u8>)>, Error>

Scan all documents in the collection

Returns all documents as (id, bytes) tuples. Order is implementation-defined.

§Performance

This loads all documents into memory. For large collections, consider streaming or pagination (future enhancement).

§Returns

Vector of (document_id, document_bytes) tuples

§Example
for (id, bytes) in cells.scan()? {
    let cell = CellState::decode(&bytes[..])?;
    println!("Cell {}: {:?}", id, cell);
}
Source

fn find( &self, predicate: Box<dyn Fn(&[u8]) -> bool + Send>, ) -> Result<Vec<(String, Vec<u8>)>, Error>

Find documents matching a predicate

Filters documents by applying a predicate function to their serialized bytes. Less efficient than indexed queries, but flexible.

§Arguments
  • predicate - Function that returns true for documents to include
§Returns

Vector of matching (document_id, document_bytes) tuples

§Example
// Find all cells with status "active"
let active_cells = cells.find(Box::new(|bytes| {
    if let Ok(cell) = CellState::decode(bytes) {
        cell.status == CellStatus::Active as i32
    } else {
        false
    }
}))?;
Source

fn query_geohash_prefix( &self, prefix: &str, ) -> Result<Vec<(String, Vec<u8>)>, Error>

Query documents by geohash prefix (proximity queries)

Geohash is a hierarchical spatial index. Documents with the same prefix are geographically close. Longer prefixes = smaller areas.

§Arguments
  • prefix - Geohash prefix (e.g., “9q8y” for San Francisco area)
§Returns

Vector of matching (document_id, document_bytes) tuples

§Example
// Find all nodes within ~5km of a location
let nearby_nodes = nodes.query_geohash_prefix("9q8yy")?;
§Implementation Notes
  • For Automerge/redb: Uses prefix scan (requires geohash in key)
  • For in-memory: Scans all documents (inefficient for large datasets)
Source

fn count(&self) -> Result<usize, Error>

Count documents in the collection

§Returns

Number of documents in collection

§Example
let cell_count = cells.count()?;
println!("Total cells: {}", cell_count);

Implementors§