Skip to main content

5 posts tagged with "sqlite"

View All Tags

TeaQL Runtime Providers: PostgreSQL, MySQL, SQLite

· 2 min read
TeaQL Code Gen
Core Contributor

TeaQL Rust uses runtime providers to keep generated business APIs separate from storage execution.

The application code should use the generated API. The runtime should decide how that API executes against PostgreSQL, MySQL, SQLite, embedded SQLite, or memory.

Provider Matrix

ProviderBest for
SQLx PostgreSQLproduction-grade backend services, complex queries, transactions, aggregation
SQLx MySQLenterprise MySQL systems and migration scenarios
SQLx SQLitelocal-first apps, tests, lightweight services
rusqlite SQLiteembedded, router, edge, sync execution, multi-architecture devices
MemoryRepositoryno-database tests, demos, fast model validation

PostgreSQL

PostgreSQL is the strongest default for production backend systems that need:

  • transactions;
  • rich query behavior;
  • grouped aggregation;
  • Decimal/NUMERIC support;
  • schema bootstrap;
  • id-space generation;
  • production database tooling.

TeaQL's SQLx PostgreSQL provider keeps PostgreSQL-specific execution behind the repository boundary.

MySQL

MySQL remains common in enterprise business systems. TeaQL's SQLx MySQL provider is intended for teams that want generated business APIs while staying on a familiar MySQL backend.

This is especially useful when moving away from handwritten mapper-heavy persistence without moving the database first.

SQLite

SQLite has two important TeaQL paths.

SQLx SQLite is useful for async local-first apps, integration tests, small services, and portable demos.

rusqlite is useful when synchronous embedded SQLite is a better fit:

  • devices;
  • routers;
  • edge deployments;
  • appliance controllers;
  • local agent memory.

MemoryRepository

Not every generated API test needs a database.

MemoryRepository gives TeaQL a no-database path for:

  • unit tests;
  • model validation;
  • lightweight demos;
  • fast runtime simulation.

The goal is to test generated API behavior without requiring a database server.

Runtime Assembly

The provider is registered below UserContext:

Generated service crate
-> RuntimeModule
-> UserContext
-> Repository API
-> selected provider

Generated crates can expose helpers for module registration, behavior/checker registration, provider-backed runtime setup, and schema bootstrap.

Why Providers Matter

Without a provider boundary, application code tends to mix business intent with database details.

With providers, the generated API remains stable:

Q::platforms()
.select_merchant_list_with(Q::merchants().select_name())
.execute_for_list(&ctx)
.await?;

The runtime decides whether that request executes through PostgreSQL, MySQL, SQLite, rusqlite, or memory.

That is the point of TeaQL's multi-database runtime direction.

Why TeaQL Supports Both SQLx and rusqlite

· 2 min read
TeaQL Code Gen
Core Contributor

TeaQL Rust supports both SQLx and rusqlite because they solve different deployment problems.

This is not duplication. It is provider choice.

The generated business API should remain stable while the runtime provider changes underneath.

SQLx: Async Backend Services

SQLx is a strong fit for async server-side Rust services.

TeaQL uses SQLx providers for:

  • PostgreSQL;
  • MySQL;
  • SQLite.

SQLx fits services that already run inside an async runtime, use connection pools, and need production backend behavior such as transactions, schema bootstrap, row decoding, and database-specific SQL execution.

Good SQLx targets:

  • API servers;
  • backend services;
  • PostgreSQL business systems;
  • MySQL enterprise systems;
  • local-first services that still use async SQLite.

rusqlite: Embedded SQLite

rusqlite is a strong fit for synchronous embedded SQLite.

That matters for deployments where the database is not a remote backend service:

  • routers;
  • edge devices;
  • appliance controllers;
  • offline local tools;
  • multi-architecture devices;
  • small embedded runtimes;
  • local agent memory.

In those cases, an async pool-oriented provider may be unnecessary weight. A synchronous SQLite provider can be easier to deploy and reason about.

Same Business API, Different Provider

The application should still use generated APIs:

let rows = Q::orders()
.select_self()
.select_line_item_list_with(Q::line_items().select_self())
.execute_for_list(&ctx)
.await?;

The question of SQLx SQLite versus rusqlite SQLite should be a runtime decision, not a reason to rewrite business query code.

Provider Boundary

The boundary looks like this:

Generated Q API
-> UserContext
-> Repository API
-> SQLx PostgreSQL / SQLx MySQL / SQLx SQLite / rusqlite SQLite

This keeps database execution below generated business intent.

Choosing Between Them

Use SQLx when:

  • the app is async;
  • the database is part of a backend service;
  • pooling and async transactions matter;
  • the provider is PostgreSQL or MySQL;
  • SQLite is used in an async service/test path.

Use rusqlite when:

  • SQLite is embedded;
  • sync execution is simpler;
  • deployment footprint matters;
  • the target is edge, device, or local runtime;
  • the app should avoid an async database stack.

Why This Matters for TeaQL

TeaQL is not only about database support. It is about keeping domain APIs independent of storage execution.

Supporting both SQLx and rusqlite lets the same generated model fit more deployment shapes without changing the programming model.

TeaQL Rust Core Runtime

· One min read
TeaQL Code Gen
Core Contributor

TeaQL expands into Rust. The core runtime ships with procedural macros, dual database support, and a unified id space.

Why Rust

Java served us well for enterprise backends. Rust brings zero-cost abstractions, memory safety without GC, and native performance. The goal is not to replace the Java stack but to offer a lean alternative for performance-critical services.

Procedural Macros

#[derive(TeaQLEntity)]
struct User {
id: u64,
name: String,
}

The TeaQLEntity macro derives:

  • Schema mapping
  • Query DSL methods
  • Graph relation helpers

Database Support

DatabaseSchema EnsuringStatus
SQLiteensure_schemaReady
PostgreSQLensure_schemaReady
let db = SqliteBackend::open("app.db").await?;
db.ensure_schema::<User>().await?;

u64 Id Space

All entity ids moved from i32 to u64:

  • 64-bit range eliminates overflow concerns
  • Consistent with Snowflake-style distributed ids
  • Progress tracking built into the runtime

What's Next

Graph writes and a query DSL are already in progress.

Internationalization and SQLite Enhancements

· One min read
TeaQL Code Gen
Core Contributor

Internationalization milestone with SQLite schema migration enhancements.

Traditional Chinese Support

+ Full Traditional Chinese (zh-TW) translation
+ BaseLanguageTranslator base class

Supported languages: English (en), Simplified Chinese (zh-CN), Traditional Chinese (zh-TW).

SQLite ALTER COLUMN

SQLite's limited ALTER TABLE support implemented via table recreation:

+ SQLiteRepository: alter column via table recreation
+ Data preservation during table recreation

CODE_AS_IS Constant Strategy

Constant values emitted exactly as defined in the domain model without transformation.

Boolean Property Naming

Default boolean naming changed from hasXxx to haveXxx:

// Before
user.hasPermission()

// After (default)
user.havePermission()

Legacy projects can set use_has='true' to maintain compatibility.