Crate ankurah

Crate ankurah 

Source
Expand description

§Ankurah

Ankurah Logo
The root of all cosmic projections of state

Ankurah is a state-management framework that enables real-time data synchronization across multiple nodes with built-in observability.

It supports multiple storage and data type backends to enable no-compromise representation of your data.

This project is in the early stages of development, and is not yet ready for production use.

§Key Features

  • Schema-First Design: Define data models using Rust structs with an ActiveRecord-style interface - View/Mutable
  • Content-filtered pub/sub: Subscribe to changes on a collection using a SQL-like query - subscribe
  • Real-Time Observability: Signal-based pattern for tracking entity changes
  • Distributed Architecture: Multi-node synchronization with event sourcing
  • Flexible Storage: Support for multiple storage backends (Sled, Postgres, TiKV)
  • Isomorphic code: Server applications and Web applications use the same code, including first-class support for React and Leptos out of the box

§Core Concepts

  • Model: A struct describing fields and types for entities in a collection (data binding)
  • Collection: A group of entities of the same type (similar to a database table, and backed by a table in the postgres backend)
  • Entity: A discrete identity in a collection - Dynamic schema (similar to a schema-less database row)
  • View: A read-only representation of an entity - Typed by the model
  • Mutable: A mutable state representation of an entity - Typed by the model
  • Event: An atomic change that can be applied to an entity - used for syncrhonization and audit trail

§Quick Start

  1. Start the server:
cargo run -p ankurah-example-server

# or dev mode
cargo watch -x 'run -p ankurah-example-server'
  1. Build WASM bindings:
cd examples/wasm-bindings
wasm-pack build --target web --debug

# or dev mode
cargo watch -s 'wasm-pack build --target web --debug'
  1. Run the React example app:
cd examples/react-app
bun install
bun dev

Then load http://localhost:5173/ in one regular browser tab, and one incognito browser tab and play with the example app. You can also use two regular browser tabs, but they share one IndexedDB local storage backend, so it’s not as good of a test. In this example, the “server” process is a native Rust process whose node is flagged as “durable”, meaning that it attests it will not lose data. The “client” process is a WASM process that is also durable in some sense, but not to be relied upon to have all data. The demo server currently uses the sled backend, but postgres is also supported, and TiKV support is planned.

§Example: Inter-Node Subscription

#[derive(Model, Debug, Serialize, Deserialize)]
pub struct Album {
    name: String,
    year: String,
}
    // Create server and client nodes
    let server = Node::new_durable(Arc::new(SledStorageEngine::new_test()?), ankurah::policy::PermissiveAgent::new());
    server.system.create().await?;
    let client = Node::new(Arc::new(SledStorageEngine::new_test()?), ankurah::policy::PermissiveAgent::new());

    // Connect nodes using local process connection
    let _conn = LocalProcessConnection::new(&server, &client).await?;
    client.system.wait_system_ready().await; // Wait for the client to join the server "system"

    // Get contexts for the server and client
    let server = server.context(ankurah::policy::DEFAULT_CONTEXT)?;
    let client = client.context(ankurah::policy::DEFAULT_CONTEXT)?;

    // Create a LiveQuery and subscribe to changes on the client
    let livequery = client.query::<AlbumView>("name = 'Origin of Symmetry'")?;
    use ankurah::signals::Subscribe;
    let _guard = livequery.subscribe(|changes| {
        println!("Received changes: {}", changes);
    });

    // Create a new album on the server
    let trx = server.begin();
    trx.create(&Album {
        name: "Origin of Symmetry".into(),
        year: "2001".into(),
    }).await;
    trx.commit().await?;

    Ok(())
}

§Design Philosophy

Ankurah follows an event-sourced architecture where:

  • All operations have unique IDs and precursor operations
  • Entity state is maintained per node with operation tree tracking
  • Operations use ULID for distributed ID generation
  • Entity IDs are derived from their creation operation

For more details, see the repository documentation. And join the Discord server to be part of the discussion!

Re-exports§

pub use ankql;
pub use ankurah_core as core;
pub use ankurah_proto as proto;
pub use ankurah_signals as signals;

Modules§

changes
entity
error
model
policy
property
storage
transaction
value

Macros§

create
Macro for creating entities with automatic .into() on fields.
into
Macro for ergonomic entity creation with automatic .into() on fields.

Structs§

Context
Context is used to provide a local interface to fetch and subscribe to entities with a specific ContextData. Generally this means your auth token for a specific user, but ContextData is abstracted so you can use what you want.
EntityId
LiveQuery
MatchArgs
Node
A participant in the Ankurah network, and primary place where queries are initiated
PermissiveAgent
A policy agent that allows all operations
Ref
A typed reference to another entity.
ResultSet
View-typed ResultSet

Enums§

QueryValue
Value type for query parameter substitution in FFI contexts.
Value
ValueType

Traits§

Model
A model is a struct that represents the present values for a given entity Schema is defined primarily by the Model object, and the View is derived from that via macro.
Mutable
A mutable Model instance for an Entity with typed accessors. It is associated with a transaction, and may not outlive said transaction.
Property
View
A read only view of an Entity which offers typed accessors