Changelog¶
Scythe follows Keep a Changelog and Semantic Versioning.
For the latest changes, see the CHANGELOG.md in the repository root.
[0.6.1] - 2026-04-10¶
Added¶
:optquery command -- Returns zero or one row as an optional/nullable type across all backends. Distinct from:onewhich expects exactly one row and errors if missing.- tokio-postgres options --
serdeandderiveoptions for generated structs viaapply_options(). Custom derives (e.g.,serde::Serialize) propagate to all generated structs, enums, and batch params. - GenericClient support -- tokio-postgres functions now accept
&(impl GenericClient + Sync)instead of&Client, enabling use with transactions and connection pools directly. - Nullable INSERT parameters -- Column nullability is now propagated to INSERT parameter types, generating
Option<T>/T | Nonefor nullable columns.
Changed¶
- tokio-postgres batch functions no longer wrap operations in implicit transactions -- callers control transaction boundaries.
[0.6.0] - 2026-04-08¶
Added¶
- Microsoft SQL Server (MSSQL) -- T-SQL support with tiberius (Rust), pyodbc (Python), mssql/tedious (TypeScript), go-mssqldb (Go), JDBC/R2DBC (Java/Kotlin), Microsoft.Data.SqlClient (C#), tiny_tds (Ruby), PDO (PHP), tds (Elixir)
- Oracle Database -- PL/SQL support with sibyl (Rust), oracledb (Python/TypeScript), godror (Go), JDBC/R2DBC (Java/Kotlin), ODP.NET (C#), ruby-oci8 (Ruby), PDO (PHP), jamdb_oracle (Elixir)
- MariaDB -- Native UUID type support, INSERT/DELETE RETURNING, dedicated manifests for all MySQL-compatible backends
- Amazon Redshift -- PostgreSQL-based with SUPER type support, IDENTITY columns, all existing PG backends
- Snowflake -- VARIANT/OBJECT/ARRAY types, TIMESTAMP variants, snowflake-connector (Python), snowflake-sdk (TypeScript), gosnowflake (Go), JDBC (Java/Kotlin), Snowflake.Data (C#), PDO (PHP)
- 17 new backend drivers: rust-tiberius, rust-sibyl, python-pyodbc, python-oracledb, python-snowflake, typescript-mssql, typescript-oracledb, typescript-snowflake, go-godror, go-gosnowflake, csharp-sqlclient, csharp-oracle, csharp-snowflake, ruby-tiny-tds, ruby-oci8, elixir-tds, elixir-jamdb
- 51 new type mapping manifests for engine/backend combinations
- Test fixtures for all new engines
- Integration test SQL schemas for MSSQL, Oracle, MariaDB, Redshift, Snowflake
[0.5.0] - 2026-04-08¶
Added¶
- DuckDB engine support -- 5 backends (python-duckdb, typescript-duckdb, go-database-sql, java-jdbc, kotlin-jdbc) for embedded analytical database
- CockroachDB engine support -- PostgreSQL-compatible alias, all PostgreSQL backends automatically work
- Java R2DBC backend -- reactive database access with Project Reactor (Mono/Flux)
- Kotlin R2DBC backend -- reactive database access with coroutines (suspend/Flow)
- Kotlin Exposed backend -- generates Exposed Table objects with transaction{}/exec() query pattern
- @returns :grouped -- new return type for nested result structs with
@group_byannotation - Homebrew bottles -- pre-built binaries via goreleaser brews section (faster brew install)
- Integration test generator -- generates all 39+ backend test suites from minijinja templates
[0.4.0] - 2026-04-08¶
Added¶
- Pydantic v2 row types --
row_type = "pydantic"in[[sql.gen]]generatesBaseModelclasses instead of@dataclassfor all 4 Python backends - msgspec row types --
row_type = "msgspec"generatesmsgspec.Structclasses for all 4 Python backends - Zod v4 schemas --
row_type = "zod"in[[sql.gen]]generatesz.object()schemas withz.infer<>types for all 4 TypeScript backends @optionalannotation -- dynamic WHERE clauses via@optional param_name, rewritescol = $1to($1 IS NULL OR col = $1). Supports =, <>, !=, >, <, >=, <=, LIKE, ILIKE operators. Validates param names at analysis time.- Real
:batchoperations --:batchnow generates dedicated batch functions with transaction wrapping and driver-specific batch APIs (executemany, addBatch, etc.) across all backends - Custom type overrides --
type_overridesin scythe.toml now functional (previously parsed but unused). Column-level and db_type-level overrides intercept type resolution. - Ruby Trilogy backend -- new
ruby-trilogybackend for GitHub's Trilogy MySQL client - Elixir Ecto backend -- new
elixir-ectobackend generating Ecto-compatible query modules withEcto.Adapters.SQL.query - PHP AMPHP backend -- new
php-amphpbackend for async PHP withAmp\Sql\SqlConnectionPool - GenOptions infrastructure -- per-backend configuration via
[[sql.gen]]extra keys (enables row_type, future options) - 11 unit tests for
rewrite_optional_paramsSQL rewriting - 7 snapshot tests for new backends and row type variants
Fixed¶
- Ruby Trilogy batch -- no longer generates double function signature
- Elixir Ecto @optional -- properly uses SQL rewriting for optional params
- PHP AMPHP batch -- generates transaction-wrapped batch function instead of generator
- Python ExecResult/ExecRows -- now returns
int(row count) instead ofNonefor all 4 Python backends - @optional qualified columns -- handles
t.col = $1patterns (table-qualified names) - @optional param validation -- errors on unknown param names instead of silent ignore
- Elixir Ecto Multi.run -- callback uses transaction's repo parameter
- PHP AMPHP MySQL manifest -- added missing
rangecontainer - Python import ordering -- pydantic/msgspec imports correctly separated from stdlib
[0.3.0] - 2026-04-07¶
Added¶
- Snippet runner tool -- Rust CLI that validates documentation code snippets across 13 languages (syntax, compile, run levels). Adapted from kreuzberg, supports HTML comment annotations (
<!-- snippet:skip -->, etc.) - SCREAMING_SNAKE_CASE support in
apply_casefor enum variant naming conventions
Changed¶
- PHP (breaking): generated code now uses
namespace App\Generated, wraps query functions infinal class Querieswithpublic staticmethods,:manyqueries return\Generatorinstead ofarray - Ruby (breaking): all generated code wrapped in
module Queries ... end; call viaQueries.method_nameinstead of bare functions - C# SQLite (breaking): generated code now uses async API (
ExecuteReaderAsync,ReadAsync, etc.) matching the Npgsql and MySqlConnector backends
Fixed¶
- PHP: functions no longer in global namespace; result sets use lazy generators instead of eager
fetchAll() - Ruby: enum constants now correctly use SCREAMING_SNAKE_CASE (
ACTIVEinstead ofactive) - Ruby mysql2:
affected_rowsnow called onclientinstead ofstmt - Rust tokio-postgres: enum parsing uses descriptive panic message instead of bare
.unwrap() - C# all backends:
Enum.Parsereplaced withEnum.TryParse+InvalidOperationExceptionfor clearer error messages - Python aiosqlite:
decimaltype now maps todecimal.Decimalinstead offloat - Go database-sql MySQL:
decimaltype now maps tofloat64instead ofstring - Go database-sql MySQL: added missing
timeimport rule fortime.Timetypes
[0.2.0] - 2026-04-07¶
Added¶
- Engine-aware backend architecture --
get_backend(name, engine)loads engine-specific manifests - 12 new language backends for MySQL and SQLite: go-database-sql, python-aiomysql, python-aiosqlite, typescript-mysql2, typescript-better-sqlite3, ruby-mysql2, ruby-sqlite3, csharp-mysqlconnector, csharp-microsoft-sqlite, elixir-myxql, elixir-exqlite
- Multi-backend CLI config via
[[sql.gen]]array syntax in scythe.toml - Full MySQL and SQLite support across all 10 languages
- 33 real integration tests against PostgreSQL, MySQL, and SQLite
supported_engines(),manifest(), andfile_footer()methods on CodegenBackend trait
Changed¶
get_backend()now requires engine parameter for database-aware code generation- Backend constructors accept engine parameter and load appropriate manifests
- PG-only backends reject non-PostgreSQL engines with clear error messages
Fixed¶
- Python codegen: multiline SQL now uses triple-quoted strings, added missing
import decimal - TypeScript pg codegen: multiline SQL now uses backtick template literals
- C# codegen: generated code wrapped in
public static class Queries { }, enum handling improvements - PHP codegen: MySQL
?placeholders use positional arrays, enum and DateTimeImmutable handling - Go codegen: added missing
timeanddecimalimports - Java codegen: added import statements to file header
- Ruby mysql2 codegen:
affected_rowscalled on statement instead of client
[0.1.0] - 2026-04-06¶
Added¶
- SQL analysis: Full PostgreSQL, MySQL, and SQLite dialect support
- Code generation: 13 backends across Rust, Python, TypeScript, Go, Java, Kotlin, C#, Elixir, Ruby, and PHP
- Linting: 22 built-in rules + 71 sqruff rule categories
- Formatting: SQL formatting via sqruff integration
- Type system: Neutral type abstraction with automatic SQL-to-language type mapping
- Catalog: DDL parsing for tables, enums, composites, domains, and views