Skip to content
DocumentationBuild a data-backed service
On this page

Page resources

Open Markdownllms.txtView source

Last updated

This recipe adds transactional order state without putting a database product, table layout, or connection string into the service contract.

The .one and Rust APIs below are illustrative end-product syntax.

1. Declare state obligations

one 1

semantic parcelhub.order_state
    domain one.data@1
    state Orders@1
        key (CustomerId, OrderId)
        value Order

        consistency read_your_writes
        transaction atomic_per_key
        durability acknowledged
        retention 7y
        encryption at_rest
        tenancy customer_id
        erasure by_customer

This declaration owns what callers may rely on. It does not mention PostgreSQL, SQLite, DynamoDB, a table name, an index, or a region.

2. Declare the write effect

semantic parcelhub.orders
    domain one.contracts@1
    struct PlaceOrder@1
        customer_id: CustomerId
        order_id: OrderId
        items: List<OrderItem>(1..=100)
        idempotency_key: IdempotencyKey

    operation Place@1
        input PlaceOrder
        output Order
        faults [DuplicateOrder, InvalidOrder]
        effect create(order)
        idempotency caller_key(input.idempotency_key)
        outcome query Orders.Get
        authority customer_order:place

The idempotency and outcome-query contracts make retry and reconciliation behavior explicit. They do not grant a caller permission to place an order.

3. Use a capability, not a database handle

pub async fn place(ctx: Place, input: PlaceOrder)
    -> Result<Order, PlaceOrderFault>
{
    let order = Order::construct(input)?;

    ctx.orders()
        .insert_if_absent(
            (order.customer_id, order.id),
            &order,
            input.idempotency_key,
        )
        .await?;

    Ok(order)
}

The generated orders() capability exposes only the selected state contract. The implementation cannot issue arbitrary SQL, enumerate other tenants, or open a second connection unless another exact capability is declared.

4. Let Planning select the realization

one plan --root OrdersApi

An eligible local plan may select an embedded transactional store. A production plan may select a managed relational provider. Each candidate must prove the declared consistency, transaction, durability, encryption, tenancy, retention, erasure, observation, and recovery requirements.

Installing either provider does nothing by itself. The accepted P-IR names one exact realization and configuration revision for this root.

5. Test the owned behavior

#[one::test(root = claims::OrdersApi)]
async fn duplicate_delivery_is_idempotent(app: TestApp) {
    let request = fixtures::place_order("order-7391", "attempt-7");

    let first = app.orders().place(request.clone()).await.unwrap();
    let second = app.orders().place(request).await.unwrap();

    assert_eq!(first.id, second.id);
    app.state().assert_single_order(first.id).await;
}

Run the same contract suite against every claimed state provider. Add provider-specific tests only for behavior unique to that realization.

Executable evidence

ParcelHub's current Contracts source uses struct declarations and attaches bounded one.data#KeyValue@1 lanes directly to Get, Place, and Cancel. Its reactive Orders test proves SQLite-backed exact-key reads, cache reuse, unrelated-key suppression, updates, bounded replay, and explicit resnapshot:

cargo test -p parcelhub --all-targets

See data and state and data-intensive systems.