Skip to main content

Rust Database Providers

TeaQL Rust separates generated business APIs from storage execution. The same generated domain API can target PostgreSQL, MySQL, SQLite, embedded SQLite, or an in-memory repository depending on the provider.

Read Rust Overview first if you need the runtime and generated-crate context. Read Java Parity & Generator if you need to understand how Rust maps the Java TeaQL programming model.

Overview

Provider support is centered on these runtime targets:

ProviderWhen to use
SQLx PostgreSQLProduction-grade server backends, complex queries, transactions, aggregation analysis
SQLx MySQLEnterprise MySQL backends and migration scenarios
SQLx SQLiteLocal-first apps, tests, small services
rusqlite SQLiteEmbedded, router, edge devices, synchronous execution, small dependency footprint
MemoryRepositoryUnit tests, no-database demos, fast model validation

Provider Architecture

Generated Q API
-> generated service crate
-> RuntimeModule / module()
-> UserContext
-> Repository API
-> Provider
-> Database or memory store

The generated API should not care whether the underlying execution target is PostgreSQL, MySQL, SQLite, rusqlite, or memory. Provider selection is an infrastructure decision made during runtime assembly.

SQLx PostgreSQL

Use SQLx PostgreSQL for production server-side backends where you need mature PostgreSQL operations, transactions, aggregation, and predictable async execution.

Best fit:

  • Multi-user backend services
  • Complex business systems
  • Reporting and aggregation paths
  • Production databases with migration discipline

SQLx MySQL

Use SQLx MySQL when the business system already standardizes on MySQL or when the migration path is from a MySQL-centric enterprise stack.

Best fit:

  • Enterprise MySQL applications
  • Business systems moving from handwritten MyBatis-style persistence
  • Standard async backend services

SQLx SQLite

Use SQLx SQLite for local-first applications, tests, and lightweight services where async SQLx integration is still useful.

Best fit:

  • Local-first business tools
  • Developer tests
  • Small services
  • Portable demos

[!WARNING] In-Memory Connection Isolation When using in-memory SQLite (sqlite::memory:), SQLite creates a separate, completely isolated database for each physical connection. Under a standard database connection pool (which creates multiple connections by default), different queries will execute against different in-memory database instances, leading to "table not found" or missing record issues.

To solve this, always configure your in-memory SQLite connection string to use a shared cache so all connections in the pool access the same in-memory instance:

let pool = SqlitePool::connect("sqlite::memory:?cache=shared").await?;

rusqlite SQLite

Use rusqlite when synchronous SQLite execution, embedded deployment, small dependency shape, or multi-architecture device support matters more than async server integration.

Best fit:

  • Embedded devices
  • Router and edge environments
  • Offline business apps
  • Agent memory on local devices
  • Multi-architecture targets

MemoryRepository

Use MemoryRepository when you want to exercise generated APIs without a database.

Best fit:

  • Unit tests
  • No-database demos
  • Model validation
  • Fast runtime simulation

Choosing a Provider

NeedProvider
Production PostgreSQL backendSQLx PostgreSQL
Enterprise MySQL backendSQLx MySQL
Local-first async SQLiteSQLx SQLite
Embedded or edge SQLiterusqlite SQLite
Fast tests without storageMemoryRepository

Example Configuration

Provider configuration follows the runtime assembly model:

Domain model
-> generated Rust package
-> RuntimeModule
-> selected repository provider
-> PostgreSQL / MySQL / SQLite / Memory

Use the model's data-service concept to keep provider choice explicit. For the current shared data-service vocabulary, see KSML data service config.

Generated crates can expose runtime helpers for provider-backed services, including database URL environment variable names, pool setup, provider registration, and ensure_schema() after the selected provider is registered.

Common Patterns

  • Use SQLx PostgreSQL or SQLx MySQL for backend services.
  • Use SQLx SQLite for local-first and test-heavy server code.
  • Use rusqlite for embedded devices and sync execution.
  • Use MemoryRepository when testing generated API behavior without persistence.
  • Keep business query code provider-agnostic.

Limitations and Roadmap

The Rust runtime is active runtime work, not a placeholder. Current direction:

  • Java TeaQL remains mature and proven for enterprise Java systems.
  • Rust core runtime is being rebuilt around provider-backed execution.
  • MySQL, PostgreSQL, and SQLite are the primary Rust database targets.
  • rusqlite exists for embedded SQLite scenarios.
  • MemoryRepository supports no-database tests and simplified execution.