Querying Data
Ankurah provides a SQL-like query language called AnkQL for filtering and retrieving entities. Queries work consistently across all storage backends—whether you’re querying Postgres on your server or IndexedDB in a browser.
Two Ways to Query
There are two fundamental patterns for getting data:
| Method | Returns | Use When |
|---|---|---|
fetch() | One-time snapshot | You need data once (e.g., checking if something exists) |
query() | Live subscription | You want automatic updates when data changes |
fetch() - One-Time Snapshot
Use fetch() when you need data once and don’t need ongoing updates:
// Fetch with a string query - one-time snapshot
let albums: Vec<AlbumView> = ctx.fetch("year > 1985").await?;
The results are a Vec<AlbumView> containing all matching entities at that moment. If the data changes later, you won’t be notified.
query() - Live Subscription
Use query() when your UI should update automatically as data changes:
// Using selection! macro with ctx.query()
let q: LiveQuery<AlbumView> = ctx.query(selection!("year > 1985"))?;
A LiveQuery is reactive—when entities matching your query are created, updated, or deleted (anywhere in the system), the query’s results update automatically.
Query Methods
Using Macros (Recommended)
The recommended way to query is using the fetch! and selection! macros, which provide compile-time safety and variable interpolation:
Variable Interpolation with Macros
Use the fetch! and selection! macros for dynamic queries. They support multiple syntaxes:
Unquoted Form (Terse)
The unquoted form is the most concise. Variables expand to equality comparisons by default:
// Unquoted form: {variable} expands to variable = {variable}
let artist = "Prince";
let albums: Vec<AlbumView> = fetch!(ctx, {artist}).await?;
Add comparison operators as prefixes: {>year}, {<year}, {>=year}, {<=year}, {!=year}:
// Unquoted form with comparison operator: {>year} expands to year > {year}
let year = 1985;
let albums: Vec<AlbumView> = fetch!(ctx, {>year}).await?;
Combine multiple conditions with AND/OR:
// Combine multiple conditions with AND/OR
let artist = "Prince";
let year = 1985;
let albums: Vec<AlbumView> = fetch!(ctx, {artist} AND {>year}).await?;
Mix unquoted variables with explicit comparisons:
// Mix unquoted variables with explicit comparisons
let artist = "Prince";
let year = 1985;
let albums: Vec<AlbumView> = fetch!(ctx, {artist} AND year > {year}).await?;
Quoted Form (Flexible)
Use quoted form for string literals and positional arguments:
// Quoted form for pure string literals
let albums: Vec<AlbumView> = fetch!(ctx, "artist = 'Prince' AND year > 1985").await?;
Positional arguments with {}:
// Quoted form with positional arguments
let min_year = 1980;
let max_year = 1990;
let albums: Vec<AlbumView> = fetch!(ctx, "year >= {} AND year <= {}", min_year, max_year).await?;
Multiple positional arguments:
// Quoted form with named variable interpolation
let artist = "Prince";
let year = 1985;
let albums: Vec<AlbumView> = fetch!(ctx, "artist = '{}' AND year > {}", artist, year).await?;
With query() and selection!
The same syntaxes work with ctx.query(selection!(...)):
// Unquoted form with selection! macro
let artist = "Prince";
let live: LiveQuery<AlbumView> = ctx.query(selection!({artist}))?;
// Unquoted form with comparison operator
let year = 1985;
let live: LiveQuery<AlbumView> = ctx.query(selection!({>year}))?;
// Combine conditions with AND/OR
let artist = "Prince";
let year = 1985;
let live: LiveQuery<AlbumView> = ctx.query(selection!({artist} AND {>year}))?;
// Quoted form for string literals
let live: LiveQuery<AlbumView> = ctx.query(selection!("artist = 'Prince' AND year > 1985"))?;
Next Steps
- Query Syntax - Learn the full AnkQL query language
- React Usage - Using queries in React components