Skip to main content

Quick Start — Rust

This path generates a TeaQL Rust library and console application, tests both outputs, starts the SQLite-backed runtime, executes a generated query, performs an audited mutation, and regenerates after a model change.

Expected time: about 20–30 minutes after the Rust toolchain is installed.

Evidence boundary: the complete path was executed on 2026-07-13 with the versions below. It proves this combination, not a minimum Rust version or a support commitment for every provider.

ComponentVerified value
Generator Server20260813.034821
cargo-teaql2.0.11
TeaQL runtime and SQLite provider4.2.8
Rust toolchain used by the recorded runnightly 1.99.0
Generated crate edition2021

1. Prepare an Empty Working Directory

Run the commands in this guide from one project root. The examples assume this layout:

teaql-rust-quick-start/
├── model/main.xml
├── generated/
│ ├── rust-lib-core/
│ └── rust-app-console/
└── handwritten/rust-contract-harness/

Install a current Rust nightly toolchain, then pin the verified client:

rustup toolchain install nightly --profile minimal
rustup default nightly
cargo install cargo-teaql --version 2.0.11 --locked
cargo teaql --version

If your team uses another toolchain, qualify it separately rather than treating the recorded nightly as a published minimum-supported Rust version.

2. Create the Model

Create model/main.xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root alias_model_name="child_development_service"
chinese_name="User List Service"
english_name="User List Service"
data_service="sqlite"
name="demo-service"
org="yourcompany"
version="1.0.0"
_module_key="root">

<demo_sys
name="ChildDevelopment"
create_time="createTime()"
last_update_time="updateTime()"
_module_key="platform"
/>
<user_info
name="Philip"
platform="demo_sys()"
_module_key="platform"
/>
</root>

The model is the source of truth. Do not plan handwritten changes inside the generated directories.

3. Discover Targets and Evaluate

Generation targets are dynamic. Query the current service before selecting a target:

cargo teaql services
cargo teaql evaluate --input model/main.xml

The recorded catalog exposed rust-lib-core and rust-app-console. Use the names returned by your current catalog if they differ. If evaluation prints a Markdown report, read its first error and fix the model before generation.

4. Generate Sibling Outputs

cargo teaql rust-lib-core \
--input model/main.xml \
--output generated/rust-lib-core
cargo teaql rust-app-console \
--input model/main.xml \
--output generated/rust-app-console

Keep the two outputs as siblings. The verified console manifest refers to the library through ../rust-lib-core/lib.

Inspect the emitted manifests before building:

rg 'teaql-|rusqlite|path = ' generated/rust-lib-core/lib/Cargo.toml
rg 'teaql-|path = ' generated/rust-app-console/Cargo.toml

The recorded output used TeaQL runtime/provider 4.1.1. The generated manifest is the authority for the dependency set of your run.

5. Test and Start the Generated Application

cargo test --manifest-path generated/rust-lib-core/lib/Cargo.toml
cargo test --manifest-path generated/rust-app-console/Cargo.toml

For this model, the generated runtime declares DEMO_SERVICE_CORE_DATABASE_URL. Start it with a local SQLite file:

DEMO_SERVICE_CORE_DATABASE_URL=sqlite:///tmp/teaql-rust-quick-start.db \
cargo run --manifest-path generated/rust-app-console/Cargo.toml

Success means the process prints its startup message, opens SQLite, ensures the schema, and exits without an error. For a different model name, inspect generated/rust-lib-core/lib/src/runtime.rs and use its generated DATABASE_URL_ENV value rather than guessing the variable name.

6. Execute a Query and Audited Mutation

Keep application code outside generated output. Create handwritten/rust-contract-harness/Cargo.toml:

[package]
name = "teaql-rust-contract-harness"
version = "0.1.0"
edition = "2021"

[dependencies]
demo_service_core = { package = "demo-service-core", path = "../../generated/rust-lib-core/lib" }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

Create handwritten/rust-contract-harness/src/main.rs:

use demo_service_core::request_support::AuditedSave;
use demo_service_core::teaql_core::Entity as _;
use demo_service_core::{service_runtime, Q, ServiceRuntimeConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let runtime = service_runtime(ServiceRuntimeConfig {
database_url: "sqlite:///tmp/teaql-rust-contract-harness.db".to_string(),
})
.await?;

let platforms = Q::demo_syses()
.comment("Query the generated initial platform")
.purpose("Find the parent identifier for an audited child mutation")
.execute_for_list(&runtime)
.await?;
let platform_id = platforms
.iter()
.next()
.ok_or("generated initial platform was not returned")?
.id();

let mut user = Q::user_info()
.comment("Create Quick Start user")
.purpose("Verify an audited child mutation")
.new_entity(&runtime);
user.update_name("Quick Start User");
user.update_platform_id(platform_id);
user.audit_as("Create Quick Start user").save(&runtime).await?;

let users = Q::user_info()
.comment("Query Quick Start users")
.purpose("Verify the audited child mutation was persisted")
.execute_for_list(&runtime)
.await?;
if !users.iter().any(|item| item.name() == "Quick Start User") {
return Err("saved user was not returned by the query".into());
}

println!("Quick Start query and audited mutation passed");
Ok(())
}

These method names were inspected in the output generated from this exact model. For another model, read its generated q.rs, entity, and request files; never infer pluralization or update_xxx names.

Run the harness:

cargo run --manifest-path handwritten/rust-contract-harness/Cargo.toml

Expected final line:

Quick Start query and audited mutation passed

The query order is significant: commentpurposeexecute_for_xxx. Mutations must declare audit_as(...) before save(...) or update(...).

7. Change the Model and Regenerate

Advance the root version to 1.0.1, then add email and its audit-mask metadata to user_info:

<user_info
name="Philip"
email="philip@example.com"
_audit_mask_fields="email"
platform="demo_sys()"
_module_key="platform"
/>

Evaluate and regenerate the library:

cargo teaql evaluate --input model/main.xml
cargo teaql rust-lib-core \
--input model/main.xml \
--output generated/rust-lib-core
cargo test --manifest-path generated/rust-lib-core/lib/Cargo.toml

Inspect the exact generated change:

rg 'update_email|get_email|audit_mask_fields' generated/rust-lib-core/lib/src

The verified regeneration emitted update_email, email expression/request support, and audit_mask_fields = "email" without changing the TeaQL dependency versions. Run the handwritten harness again to confirm the existing query and mutation still work.

Known Generated-Template Boundary

The cargo-teaql 2.0.8 sample-data template observed in this run contains queries with purpose but no comment. Do not repair that by editing generated sample_data.rs. Preserve the evidence and report the template defect; handwritten queries must continue to use the complete intent chain.

Completion Checklist

  • The model evaluates without unresolved errors.
  • Both dynamic targets generate into sibling directories.
  • Both generated targets pass cargo test.
  • The generated console starts against SQLite.
  • The handwritten query and audited mutation pass.
  • Regeneration exposes the expected email API and audit metadata.
  • No generated file was used as a handwritten customization point.

Continue with Regenerate and Review, Rust Database Providers, or Troubleshoot First Run.