Skip to content

Releases: jubilee-works/sea-orm-spanner

v0.1.0

07 Apr 05:25
4938653

Choose a tag to compare

v0.1.0 — Initial Release

Google Cloud Spanner backend for SeaORM. Write Spanner applications using SeaORM's familiar ActiveRecord pattern.

Crates

Crate Version Description
sea-orm-spanner 0.1.0 SeaORM integration via ProxyDatabaseTrait
sea-query-spanner 0.1.0 Spanner SQL dialect for SeaQuery (@p1, @p2 parameters, backtick quoting)
sea-orm-migration-spanner 0.1.0 Migration CLI & library with Spanner-native DDL builders

Highlights

Full SeaORM CRUD Support

Standard SeaORM operations work out of the box — insert, find, update, delete, find_by_id, and query builders. Uses MySQL backend internally because Spanner doesn't support RETURNING clause.

Connection Management

  • SpannerDatabase::connect() — auto-detects environment: emulator (via SPANNER_EMULATOR_HOST) or GCP (via Application Default Credentials)
  • connect_with_config() — full control with custom ClientConfig
  • connect_with_emulator() / connect_with_emulator_host() — explicit emulator connection
  • connect_or_create_with_emulator() — auto-provisions instance and database on emulator for testing
  • TLS — automatic rustls crypto provider setup for GCP connections

Spanner Type System

Comprehensive mapping from SeaORM types to Spanner's native types:

Spanner Type Rust Type Feature Flag
INT64 i64
FLOAT64 f64
STRING String
BOOL bool
BYTES Vec<u8>
TIMESTAMP DateTimeUtc with-chrono
DATE Date with-chrono
UUID Uuid with-uuid
JSON serde_json::Value with-json
NUMERIC rust_decimal::Decimal with-rust_decimal
ARRAY<T> Vec<T> with-array

Migration System (sea-orm-migration-spanner)

Full migration CLI with Spanner-native DDL support:

  • Commands: init, generate, up, down, status, fresh, reset
  • SpannerTableBuilder — fluent API for CREATE TABLE with support for interleaved tables, row deletion policies, generated columns, and default expressions
  • SpannerIndexBuilderCREATE INDEX with unique, null-filtered, storing, and interleave options
  • SpannerAlterTableADD COLUMN, DROP COLUMN, ALTER COLUMN, ADD FOREIGN KEY, DROP CONSTRAINT
  • MySQL DDL auto-conversion — SeaQuery's MySQL DDL output is automatically translated to Spanner DDL (type mappings, syntax adjustments)
  • --env-file flag — load different .env files per environment (e.g., .env.stg, .env.prod)
  • Migration tracking — uses seaql_migrations table

DML Execution in Migrations (#25)

SchemaManager now holds a DatabaseConnection internally, enabling DML (INSERT, UPDATE, DELETE) alongside DDL within migrations:

  • get_connection() — returns &DatabaseConnection for full SeaORM query access
  • execute_unprepared(sql) — execute raw DML statements directly
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
    manager.create_table(/* ... */).await?;

    // Seed data within the same migration
    manager.execute_unprepared(
        "INSERT INTO config (`key`, `value`) VALUES ('version', '1')"
    ).await?;

    // Or use full SeaORM queries via get_connection()
    let db = manager.get_connection();
    db.execute_unprepared("UPDATE config SET `value` = '2' WHERE `key` = 'version'").await?;
    Ok(())
}

Breaking change: SchemaManager::new() is now async and returns Result<Self, DbErr>.

DEFAULT Clause Support (#26)

The DDL converter now properly converts MySQL DEFAULT clauses to Spanner's DEFAULT (value) syntax instead of stripping them:

MySQL Spanner
DEFAULT 'hello' DEFAULT ('hello')
DEFAULT 0 DEFAULT (0)
DEFAULT -1 DEFAULT (-1)
DEFAULT 3.14 DEFAULT (3.14)
DEFAULT NULL DEFAULT (NULL)
DEFAULT TRUE DEFAULT (TRUE)
DEFAULT CURRENT_TIMESTAMP DEFAULT (CURRENT_TIMESTAMP())

MySQL backslash escaping (\') is automatically normalized to Spanner's double-quote escaping ('').

SQL Query Builder (sea-query-spanner)

Translates SeaQuery AST into Spanner-compatible SQL:

  • Parameter placeholders: ?@p1, @p2, ...
  • Identifier quoting with backticks (auto-quotes identifiers containing hyphens or special characters)
  • Full SeaQuery ColumnType → Spanner type mapping

Feature Flags

Feature Description
with-chrono TIMESTAMP / DATE support via chrono
with-uuid Native UUID type support
with-json JSON column support
with-rust_decimal NUMERIC support via rust_decimal
with-array ARRAY<INT64>, ARRAY<FLOAT64>, ARRAY<STRING>, ARRAY<BOOL>
macros SeaORM derive macros (DeriveEntityModel, etc.)
runtime-tokio-native-tls Tokio + native-tls runtime
runtime-tokio-rustls Tokio + rustls runtime

All type features are enabled by default.

Dependencies

  • sea-orm 2.0.0-rc.37 (proxy backend)
  • sea-query 1.0.0-rc.31
  • gcloud-spanner 1.7.0 (official Rust SDK)
  • Rust 1.80+ (bumped from 1.75 for LazyLock)

Known Limitations

  • Integer types: Spanner only has INT64 — use i64 for all integer fields
  • Float types: Spanner only has FLOAT64 — use f64, not f32
  • TIMESTAMP: Returns DateTimeUtc (DateTime<Utc>) — not NaiveDateTime
  • BYTES vs STRING: Distinguished via base64 heuristics; empty byte arrays may be misread as strings
  • JSON primitives: Numeric JSON values (42, 3.14) may be indistinguishable from INT64/FLOAT64 — wrap in objects
  • Empty arrays: Cannot be reliably read back due to SDK type information loss — use NULL instead
  • NUMERIC edge cases: Zero values may be misinterpreted when coexisting with STRING columns

License

MIT OR Apache-2.0