Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

AnkQL Syntax

AnkQL is Ankurah’s query language for filtering entities. It uses familiar SQL-like syntax that works consistently across all storage backends.

Basic Comparisons

field = value       # Equality
field != value      # Not equal
field > value       # Greater than
field >= value      # Greater than or equal
field < value       # Less than
field <= value      # Less than or equal

Examples

let albums: Vec<AlbumView> = ctx.fetch("name = 'Dark Side of the Moon'").await?;
let albums: Vec<AlbumView> = ctx.fetch("year > 1985").await?;
let albums: Vec<AlbumView> = ctx.fetch("artist != 'Unknown'").await?;

Logical Operators

Combine conditions with AND and OR:

condition1 AND condition2
condition1 OR condition2

Use parentheses for complex logic:

(condition1 OR condition2) AND condition3

Examples

let albums: Vec<AlbumView> = ctx.fetch("year > 1980 AND year < 1990").await?;
let albums: Vec<AlbumView> = ctx.fetch("artist = 'Prince' OR artist = 'Madonna'").await?;
let albums: Vec<AlbumView> = ctx.fetch("(artist = 'Prince' OR artist = 'Madonna') AND year > 1985").await?;

The IN Operator

Check if a value is in a list:

field IN (value1, value2, value3)

Example

let albums: Vec<AlbumView> = ctx.fetch("year IN (1984, 1985, 1986)").await?;

Ordering Results

Use ORDER BY to sort results:

... ORDER BY field ASC
... ORDER BY field DESC

Examples

let albums: Vec<AlbumView> = ctx.fetch("year > 1980 ORDER BY year DESC").await?;
let albums: Vec<AlbumView> = ctx.fetch("true ORDER BY name ASC").await?;

Selecting All Entities

Use true to match all entities:

let albums: Vec<AlbumView> = ctx.fetch("true ORDER BY name ASC").await?;

String Values

String literals use single quotes:

let albums: Vec<AlbumView> = ctx.fetch("name = 'Purple Rain'").await?;

To include a single quote in a string, escape it with another single quote:

let albums: Vec<AlbumView> = ctx.fetch("name = 'Rock ''n'' Roll'").await?;

Variable Interpolation

Use the fetch! and selection! macros for dynamic queries. They support multiple syntaxes:

Unquoted Form

The unquoted form is the most concise. Variables expand to equality by default:

#![allow(unused)]
fn main() {
let artist = "Prince";
fetch!(ctx, {artist}).await?;  // Equivalent to: artist = 'Prince'
}

Add comparison operators as prefixes:

// Unquoted form: {>year} expands to year > {year}
let year = 1985;

let albums: Vec<AlbumView> = fetch!(ctx, {>year}).await?;

All comparison operators work: {>var}, {<var}, {>=var}, {<=var}, {!=var}:

// All comparison operators work: >, <, >=, <=, !=
let year = 1985;

let _newer: Vec<AlbumView> = fetch!(ctx, {>year}).await?;
let _older: Vec<AlbumView> = fetch!(ctx, {<year}).await?;
let _gte: Vec<AlbumView> = fetch!(ctx, {>=year}).await?;
let _lte: Vec<AlbumView> = fetch!(ctx, {<=year}).await?;
let _not_eq: Vec<AlbumView> = fetch!(ctx, {!=year}).await?;

Combine 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

Use quoted form for string literals and positional arguments:

// Quoted form with positional argument for string values
let artist = "Prince";

let albums: Vec<AlbumView> = fetch!(ctx, "artist = '{}'", artist).await?;

Multiple variables:

// Multiple variables with quoted form
let min_year = 1980;
let max_year = 1990;

let albums: Vec<AlbumView> = fetch!(ctx, "year >= {} AND year <= {}", min_year, max_year).await?;

Pure string literals (no variables):

// Quoted form for pure string literals
let albums: Vec<AlbumView> = fetch!(ctx, "artist = 'Prince' AND year > 1985").await?;

Common Patterns

Check if entity exists

// Check if any entities match the query
let album_name = "Purple Rain";
let matching_albums: Vec<AlbumView> = fetch!(ctx, "name = '{}'", album_name).await?;
let exists = matching_albums.len() > 0;

Get first match

let album = ctx.fetch::<AlbumView>("name = 'Purple Rain'").await?.into_iter().next();

Count matches

let count = ctx.fetch::<AlbumView>("year > 1985").await?.len();

Next Steps