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

Examples

This page contains practical code examples demonstrating key Ankurah features.

Defining a Model

#[derive(Model, Debug, Serialize, Deserialize)]
pub struct Album {
    #[active_type(YrsString)]
    pub name: String,
    pub artist: String,
    pub year: i32,
}

This automatically generates:

  • AlbumView (read-only)
  • AlbumMutable (for updates)

See Defining Models for full documentation.

Server Setup

let storage = SledStorageEngine::with_path(storage_dir)?;
let node = Node::new_durable(Arc::new(storage), PermissiveAgent::new());
node.system.create().await?;

let mut server = WebsocketServer::new(node);
println!("Running server...");
server.run("0.0.0.0:9797").await?;

Rust Client

let storage = SledStorageEngine::new_test()?;
let node = Node::new(Arc::new(storage), PermissiveAgent::new());
let _client = WebsocketClient::new(node.clone(), "ws://localhost:9797").await?;
node.system.wait_system_ready().await;

// Create album
let ctx = node.context(ankurah::policy::DEFAULT_CONTEXT)?;
let trx = ctx.begin();
trx.create(&Album { name: "Parade".into(), artist: "Prince".into(), year: 1986 }).await?;
trx.commit().await?;

React Component

/* creates and Binds a ReactObserver to the component */
const AlbumList = signalObserver(({ albums }: Props) => {
  return (
    <ul>
      /* React Observer automatically tracks albums */
      {albums.items.map((album) => (
        <li>{album.name}</li>
      ))}
    </ul>
  );
});

See React Usage for full documentation.

Live Query

// Using selection! macro with ctx.query()
let q: LiveQuery<AlbumView> = ctx.query(selection!("year > 1985"))?;

See Querying Data for full documentation.

Entity References

Create relationships between entities with Ref<T>:

// Create an artist
let trx = ctx.begin();
let artist = trx.create(&Artist { name: "Radiohead".into() }).await?;
let artist_id = artist.id();
trx.commit().await?;

// Create a song that references the artist
let trx = ctx.begin();
trx.create(&Song {
    title: "Paranoid Android".into(),
    artist: Ref::new(artist_id),
}).await?;
trx.commit().await?;

Traverse references to fetch related entities:

// Fetch the song and traverse to get the artist
let songs: Vec<SongView> = ctx.fetch("title = 'Paranoid Android'").await?;
let song = songs.first().unwrap();

// Get the referenced artist entity
let artist: ArtistView = song.artist()?.get(&ctx).await?;
println!("Artist: {}", artist.name()?);

JSON Queries

Create entities with dynamic JSON fields:

let trx = ctx.begin();

trx.create(&Track {
    name: "Test Track".into(),
    metadata: Json::new(serde_json::json!({
        "genre": "rock",
        "bpm": 120,
        "tags": ["guitar", "drums"]
    })),
}).await?;

trx.commit().await?;

Query by nested JSON paths:

// Query by nested JSON path
let tracks: Vec<TrackView> = ctx.fetch("metadata.genre = 'rock'").await?;

Numeric comparisons work too:

// Numeric comparison on JSON field
let fast_tracks: Vec<TrackView> = ctx.fetch("metadata.bpm > 100").await?;

Storage Backends

Sled (Embedded)

let storage = SledStorageEngine::new()?;

Postgres

let storage = Postgres::open(uri).await?;

IndexedDB (WASM)

#![allow(unused)]
fn main() {
let storage = IndexedDBStorageEngine::new("my-app").await?;
}

Next Steps