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 recorded run below is historical. The install command uses today's Cargo client, so repeating these steps is a new run, not the same verified combination. Consult Latest Versions and retain the emitted dependency versions and fresh test results.

ComponentVerified value
Generator Server20260825.171719
cargo-teaql2.0.13
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 Rust toolchain, then install the current observed client:

rustup toolchain install nightly --profile minimal
rustup default nightly
cargo install cargo-teaql --version 2.0.14 --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

Both comment and purpose are required before execute_for_xxx; they may appear in either order and need not be adjacent. 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.