QueryBuilder

Struct QueryBuilder 

Source
pub struct QueryBuilder<'a> { /* private fields */ }
Expand description

Builder for creating and executing document queries.

QueryBuilder uses a fluent interface pattern to construct and execute queries against Aurora collections.

§Examples

// Query for active premium users
let premium_users = db.query("users")
    .filter(|f| f.eq("status", "active") && f.eq("account_type", "premium"))
    .order_by("created_at", false)
    .limit(10)
    .collect()
    .await?;

Implementations§

Source§

impl<'a> QueryBuilder<'a>

Source

pub fn new(db: &'a Aurora, collection: &str) -> Self

Create a new query builder for the specified collection

§Examples
let query = db.query("users");
Source

pub fn filter<F>(self, filter_fn: F) -> Self
where F: Fn(&FilterBuilder<'_, '_>) -> bool + Send + Sync + 'a,

Add a filter function to the query

§Examples
let active_users = db.query("users")
    .filter(|f| f.eq("status", "active"))
    .collect()
    .await?;
Source

pub fn order_by(self, field: &str, ascending: bool) -> Self

Sort results by a field (ascending or descending)

§Parameters
  • field - The field to sort by
  • ascending - true for ascending order, false for descending
§Examples
// Sort by age ascending
.order_by("age", true)

// Sort by creation date descending (newest first)
.order_by("created_at", false)
Source

pub fn limit(self, limit: usize) -> Self

Limit the number of results returned

§Examples
// Get at most 10 results
.limit(10)
Source

pub fn offset(self, offset: usize) -> Self

Skip a number of results (for pagination)

§Examples
// For pagination: skip the first 20 results and get the next 10
.offset(20).limit(10)
Source

pub fn select(self, fields: &[&str]) -> Self

Select only specific fields to return

§Examples
// Only return name and email fields
.select(&["name", "email"])
Source

pub async fn collect(self) -> Result<Vec<Document>>

Execute the query and collect the results

§Returns

A vector of documents matching the query criteria

§Examples
let results = db.query("products")
    .filter(|f| f.lt("price", 100))
    .collect()
    .await?;
Source

pub async fn watch(self) -> Result<QueryWatcher>
where 'a: 'static,

Watch the query for real-time updates

Returns a QueryWatcher that streams live updates when documents are added, removed, or modified in ways that affect the query results. Perfect for building reactive UIs, live dashboards, and real-time applications.

§Performance
  • Zero overhead for queries without watchers
  • Updates delivered asynchronously via channels
  • Automatic filtering - only matching changes are emitted
  • Memory efficient - only tracks matching documents
§Requirements

This method requires the QueryBuilder to have a ’static lifetime, which means the database reference must also be ’static (e.g., Arc).

§Examples
use aurora_db::{Aurora, types::Value};
use std::sync::Arc;

let db = Arc::new(Aurora::open("mydb.db")?);

// Basic reactive query - watch active users
let mut watcher = db.query("users")
    .filter(|f| f.eq("active", Value::Bool(true)))
    .watch()
    .await?;

// Receive updates in real-time
while let Some(update) = watcher.next().await {
    match update {
        QueryUpdate::Added(doc) => {
            println!("New active user: {}", doc.id);
        },
        QueryUpdate::Removed(doc) => {
            println!("User deactivated: {}", doc.id);
        },
        QueryUpdate::Modified { old, new } => {
            println!("User updated: {} -> {}", old.id, new.id);
        },
    }
}
§Real-World Use Cases

Live Leaderboard:

// Watch top players by score
let mut leaderboard = db.query("players")
    .filter(|f| f.gte("score", Value::Int(1000)))
    .watch()
    .await?;

tokio::spawn(async move {
    while let Some(update) = leaderboard.next().await {
        // Update UI with new rankings
        broadcast_to_clients(&update).await;
    }
});

Activity Feed:

// Watch recent posts for a user's feed
let mut feed = db.query("posts")
    .filter(|f| f.eq("author_id", user_id))
    .watch()
    .await?;

// Stream updates to WebSocket
while let Some(update) = feed.next().await {
    match update {
        QueryUpdate::Added(post) => {
            websocket.send(json!({"type": "new_post", "post": post})).await?;
        },
        _ => {}
    }
}

Real-Time Dashboard:

// Watch critical metrics
let mut alerts = db.query("metrics")
    .filter(|f| f.gt("cpu_usage", Value::Float(80.0)))
    .watch()
    .await?;

tokio::spawn(async move {
    while let Some(update) = alerts.next().await {
        if let QueryUpdate::Added(metric) = update {
            // Alert on high CPU usage
            send_alert(format!("High CPU: {:?}", metric)).await;
        }
    }
});

Collaborative Editing:

// Watch document for changes from other users
let doc_id = "doc-123";
let mut changes = db.query("documents")
    .filter(|f| f.eq("id", doc_id))
    .watch()
    .await?;

tokio::spawn(async move {
    while let Some(update) = changes.next().await {
        if let QueryUpdate::Modified { old, new } = update {
            // Merge changes from other editors
            apply_remote_changes(&old, &new).await;
        }
    }
});

Stock Ticker:

// Watch price changes
let mut price_watcher = db.query("stocks")
    .filter(|f| f.eq("symbol", "AAPL"))
    .watch()
    .await?;

while let Some(update) = price_watcher.next().await {
    if let QueryUpdate::Modified { old, new } = update {
        if let (Some(old_price), Some(new_price)) =
            (old.data.get("price"), new.data.get("price")) {
            println!("AAPL: {} -> {}", old_price, new_price);
        }
    }
}
§Multiple Watchers Pattern
// Watch multiple queries concurrently
let mut high_priority = db.query("tasks")
    .filter(|f| f.eq("priority", Value::String("high".into())))
    .watch()
    .await?;

let mut urgent = db.query("tasks")
    .filter(|f| f.eq("status", Value::String("urgent".into())))
    .watch()
    .await?;

tokio::spawn(async move {
    loop {
        tokio::select! {
            Some(update) = high_priority.next() => {
                println!("High priority: {:?}", update);
            },
            Some(update) = urgent.next() => {
                println!("Urgent: {:?}", update);
            },
        }
    }
});
§Important Notes
  • Requires Arc for ’static lifetime
  • Updates are delivered asynchronously
  • Watcher keeps running until dropped
  • Only matching documents trigger updates
  • Use tokio::spawn to process updates in background
§See Also
  • Aurora::listen() for collection-level change notifications
  • QueryWatcher::next() to receive the next update
  • QueryWatcher::try_next() for non-blocking checks
Source

pub async fn first_one(self) -> Result<Option<Document>>

Get only the first matching document or None if no matches

§Examples
let user = db.query("users")
    .filter(|f| f.eq("email", "jane@example.com"))
    .first_one()
    .await?;
Source

pub async fn count(self) -> Result<usize>

Count the number of documents matching the query

§Examples
let active_count = db.query("users")
    .filter(|f| f.eq("status", "active"))
    .count()
    .await?;
Source

pub async fn update(self, updates: HashMap<&str, Value>) -> Result<usize>

Update documents matching the query with new field values

§Returns

The number of documents updated

§Examples
let updated = db.query("products")
    .filter(|f| f.lt("stock", 5))
    .update([
        ("status", Value::String("low_stock".to_string())),
        ("needs_reorder", Value::Bool(true))
    ].into_iter().collect())
    .await?;

Auto Trait Implementations§

§

impl<'a> Freeze for QueryBuilder<'a>

§

impl<'a> !RefUnwindSafe for QueryBuilder<'a>

§

impl<'a> Send for QueryBuilder<'a>

§

impl<'a> Sync for QueryBuilder<'a>

§

impl<'a> Unpin for QueryBuilder<'a>

§

impl<'a> !UnwindSafe for QueryBuilder<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.