Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.10.0] - 2026-10-20

### Added

- **Nested Transactions via Savepoints** - `handle_begin/2`, `handle_commit/2` and `handle_rollback/2` now honour DBConnection's `mode: :savepoint`, so a `Repo.transaction/1` inside an open transaction creates a savepoint instead of failing with `cannot start a transaction within a transaction`. This makes application code that uses transactions testable under `Ecto.Adapters.SQL.Sandbox` (e.g. a `phx.gen.auth` test suite). The adapter's own libSQL transaction modes (`:deferred`, `:immediate`, `:exclusive`, `:read_only`) are unaffected. (Thanks [@BeagleSoftwareUK](https://github.com/BeagleSoftwareUK) for [PR #122](https://github.com/ocean/ecto_libsql/pull/122)!)
- **`datetime_add/3` and `date_add/3` Support** - `ago/2`, `from_now/2`, `datetime_add/3` and `date_add/3` now generate correct SQL. Week, millisecond and microsecond intervals are converted to modifiers SQLite supports, and interpolated counts (`ago(^n, "day")`) are bound as parameters. (Thanks [@BeagleSoftwareUK](https://github.com/BeagleSoftwareUK) for [PR #123](https://github.com/ocean/ecto_libsql/pull/123)!)
- **Arithmetic Operators** - `+`, `-`, `*` and `/` are now supported in query expressions (e.g. `where: s.count + 1 > 5`, `select: s.count * 2`), parenthesised so precedence survives nesting. (Thanks [@BeagleSoftwareUK](https://github.com/BeagleSoftwareUK) for [PR #124](https://github.com/ocean/ecto_libsql/pull/124)!)

### Fixed

- **`ago/2` Silently Ignored Its Interval** - `ago/2` and `from_now/2` previously fell through to a bare `?` placeholder, so `where: t.inserted_at > ago(14, "day")` compared against the current time and the interval never applied. Expiry checks built on this (e.g. session token validity windows) rejected live rows while never enforcing the window.
- **Arithmetic and Unary Minus Rendered as `?`** - Arithmetic expressions and negated values were emitted as an unbound `?`, returning wrong results rather than raising. Unary minus is now rendered correctly.
- **Embedded Replica Initial Sync** - `connect/1` now performs an initial sync before serving any reads when an embedded replica is opened with `sync: true`. LibSQL pushes local writes to the primary on its own, but it never pulls remote changes unless `sync/1` is called, so a freshly opened replica read from an empty or stale local file - contradicting the README's claim that initial sync happens when you first connect. (Reported in [#118](https://github.com/ocean/ecto_libsql/issues/118))
- **Savepoint Failure Leaves Connection in Pool** - A failed `RELEASE` or `ROLLBACK TO` now disconnects the connection instead of returning it to the pool with an indeterminate transaction state.

### Changed

- **Breaking: `ago/2`/`from_now/2` Comparisons Against Microsecond Columns Now Raise** - Comparing a `:utc_datetime_usec` or `:naive_datetime_usec` field against `ago/2`, `from_now/2`, `datetime_add/3` or `date_add/3` in a schema query now raises `ArgumentError` instead of returning subtly wrong results. SQLite's date functions only work to millisecond precision, so the cutoff cannot be compared correctly against stored microsecond values. Ordinary comparisons against bound values on these columns, second-precision datetime columns (`:utc_datetime`, `:naive_datetime`), and `:date` columns are unaffected. Workaround: compute the cutoff in Elixir and bind it, e.g. `where: t.inserted_at > ^DateTime.add(DateTime.utc_now(), -14, :day)`. (Closes [#128](https://github.com/ocean/ecto_libsql/issues/128))
- **Replica Sync Documentation** - Corrected the README's description of automatic sync. Remote changes made *after* you connect are not pulled in the background; `sync/1` is still required to observe them.
- **Dependency Updates** - Bumped `rustler` 0.37 → 0.38, `rustler_precompiled` 0.9.0 → 0.10.0, `ecto` → 3.14.2, `ecto_sql` → 3.14.0 (with the `insert/8` callback adapted for ecto_sql 3.14), `db_connection` → 2.10.2, `tokio` → 1.53.1, `uuid` → 1.26.1, `bytes` → 1.12.1, plus various dev and transitive dependency updates.
- **CI Toolchain** - Updated CI to Erlang/OTP 29 and Elixir 1.20; bumped GitHub Actions (`checkout` v7, `cache` v6, `zizmor-action` 0.6).
- **Hex Package Contents** - The Hex package now includes only the Rust sources, `Cargo.toml` and `deny.toml` from `native/`, rather than the whole directory.

### Security

- Updated `decimal` 3.1.1 → 3.2.0 in the lockfile (EEF-CVE-2026-97853). This only affects this repository's own builds - downstream projects resolve their own `decimal` version.
- Updated `anyhow` to 1.0.104 (RUSTSEC-2026-0190 fixed in 1.0.103).
- Acknowledged RUSTSEC-2026-0346 and RUSTSEC-2026-0349 (`rustls` 0.22.x) in `cargo deny` - transitive via libsql's `hyper-rustls` 0.25, fixed only in `rustls` 0.23.46+, so they cannot be resolved until libsql updates upstream.
- Acknowledged RUSTSEC-2026-0258 (`h2` 0.3.x empty DATA frames) in `cargo deny` - transitive via libsql's `hyper` 0.14/`tonic` 0.11, and the fix only exists in `h2` 0.4.x, so it cannot be resolved until libsql updates upstream.

## [0.9.1] - 2026-05-07

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Add `ecto_libsql` to your dependencies in `mix.exs`:
```elixir
def deps do
[
{:ecto_libsql, "~> 0.9.0"}
{:ecto_libsql, "~> 0.10.0"}
]
end
```
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule EctoLibSql.MixProject do
use Mix.Project

@version "0.9.1"
@version "0.10.0"
@source_url "https://github.com/ocean/ecto_libsql"
@dev? String.ends_with?(@version, "-dev")
@force_build? System.get_env("ECTO_LIBSQL_BUILD") in ["1", "true"]
Expand Down
2 changes: 1 addition & 1 deletion native/ecto_libsql/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ecto_libsql"
version = "0.9.1"
version = "0.10.0"
authors = []
edition = "2021"
description = "Rust NIF (Native Implemented Function) for EctoLibSql - High-performance Ecto adapter for LibSQL/Turso databases"
Expand Down
8 changes: 8 additions & 0 deletions native/ecto_libsql/deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ ignore = [
# Fix only exists in h2 >=0.4.16, but hyper 0.14 (via tonic 0.11) requires h2 0.3.x and
# 0.3.27 is the final 0.3.x release, so `cargo update -p h2` cannot resolve this
{ id = "RUSTSEC-2026-0258", reason = "Transitive dependency of libsql via hyper 0.14/tonic 0.11, waiting for upstream update" },
# rustls 0.22.x derived `Debug` on client session values exposes TLS secrets; only reachable through a
# custom ClientSessionStore that logs values, which neither ecto_libsql nor libsql provides
# Fix available in >=0.23.46 but libsql pins rustls 0.22.x via hyper-rustls 0.25 - waiting for upstream update
{ id = "RUSTSEC-2026-0346", reason = "Transitive dependency of libsql via hyper-rustls 0.25, waiting for upstream update" },
# rustls 0.22.x records the server-selected key exchange group before authentication, allowing a
# network attacker to steer later handshakes away from the hybrid post-quantum group
# Fix available in >=0.23.46 but libsql pins rustls 0.22.x via hyper-rustls 0.25 - waiting for upstream update
{ id = "RUSTSEC-2026-0349", reason = "Transitive dependency of libsql via hyper-rustls 0.25, waiting for upstream update" },
]
# If this is true, then cargo deny will use the git executable to fetch advisory database.
# If this is false, then it uses a built-in git library.
Expand Down
Loading