Skip to content
Merged
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
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.9.1] - 2026-05-07

### Fixed

- **PRAGMA Statement Routing** - PRAGMA statements are now correctly routed through the `query()` path rather than the execute path, fixing incorrect behaviour when reading PRAGMA values (e.g. `PRAGMA journal_mode`, `PRAGMA synchronous`) via the Ecto adapter.

### Changed

- **Upstream Status Notice** - Added a note to the README and Hex documentation about Turso's transition away from libSQL toward their new Turso library (a full SQLite rewrite in Rust). `ecto_libsql` will continue to receive bug fixes and security updates; see the README for more context.
- **Dependency Updates** - Bumped `db_connection` 2.9.0 → 2.10.0, `ecto` 3.13.5 → 3.13.6, `jason` 1.4.4 → 1.4.5, `rustler` 0.37.3 → 0.37.4, `libsql` crates 0.9.29 → 0.9.30, plus various transitive Rust dependency updates.
- **CI Toolchain** - Replaced `erlef/setup-beam` with `mise` for Elixir/OTP version management; updated to current Elixir/OTP versions; applied `zizmor` GitHub Actions security hardening.

### Security

- Acknowledged three additional `rustls-webpki` 0.102.x advisories (RUSTSEC-2026-0049, RUSTSEC-2026-0098, RUSTSEC-2026-0099, RUSTSEC-2026-0104) in `cargo deny` - all are transitive via libsql's pinned `rustls 0.22.x` dependency and cannot be resolved until libsql updates upstream.

## [0.9.0] - 2026-02-02

### Added
Expand All @@ -16,7 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- **`Repo.exists?` Generates Valid SQL** - Fixed empty SELECT clause generating invalid SQL (`SELECT FROM "users"` instead of `SELECT 1 FROM "users"`), causing syntax errors. (Thanks [@ricardo-valero](https://github.com/ricardo-valero) for [PR #69](https://github.com/ocean/ecto_libsql/pull/69)!)
- **NIF Cross-Compilation Workflow** - Fixed multiple issues preventing successful cross-compilation in GitHub Actions:
- Fixed Cargo workspace target directory mismatch build output goes to the workspace root `target/` directory, not the crate subdirectory
- Fixed Cargo workspace target directory mismatch - build output goes to the workspace root `target/` directory, not the crate subdirectory
- Moved `.cargo/config.toml` to workspace root so musl `-crt-static` rustflags are found when building from workspace root
- Added `Cross.toml` for `RUSTLER_NIF_VERSION` environment passthrough to cross containers
- Consolidated macOS runners to macos-15 (Apple Silicon) for both architectures
Expand Down
54 changes: 27 additions & 27 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,25 @@
1. Run formatters: `mix format && cd native/ecto_libsql && cargo fmt`
2. Verify checks pass: `mix format --check-formatted && cargo fmt --check`
3. **Only then** commit: `git commit -m "..."`
- **NEVER use `.unwrap()` in production Rust code** use `safe_lock` helpers (see [Error Handling](#error-handling-patterns))
- **NEVER use `.unwrap()` in production Rust code** - use `safe_lock` helpers (see [Error Handling](#error-handling-patterns))
- **Tests MAY use `.unwrap()`** for simplicity

---

## Landing the Plane (Session Completion)

**MANDATORY WORKFLOW work is NOT complete until `git commit` succeeds:**
**MANDATORY WORKFLOW - work is NOT complete until `git commit` succeeds:**

1. **File issues for remaining work** create Beads issues for anything needing follow-up
2. **Run quality gates** (if code changed) tests, linters, builds
3. **Update issue status** close finished work, update in-progress items
1. **File issues for remaining work** - create Beads issues for anything needing follow-up
2. **Run quality gates** (if code changed) - tests, linters, builds
3. **Update issue status** - close finished work, update in-progress items
4. **COMMIT**:
```bash
git commit -m "Your commit message"
bd sync
```
5. **Clean up** clear stashes, prune remote branches
6. **Verify** all changes committed
5. **Clean up** - clear stashes, prune remote branches
6. **Verify** - all changes committed
7. **Hand off** - provide context for next session

**If commit fails, resolve and retry until it succeeds.**
Expand Down Expand Up @@ -71,11 +71,11 @@ Rust NIF (libsql-rs, connection registry, async runtime)
### Key Files

**Elixir:**
- `lib/ecto_libsql.ex` DBConnection protocol
- `lib/ecto_libsql/native.ex` NIF wrappers
- `lib/ecto_libsql/state.ex` Connection state
- `lib/ecto/adapters/libsql.ex` Main adapter
- `lib/ecto/adapters/libsql/connection.ex` SQL generation
- `lib/ecto_libsql.ex` - DBConnection protocol
- `lib/ecto_libsql/native.ex` - NIF wrappers
- `lib/ecto_libsql/state.ex` - Connection state
- `lib/ecto/adapters/libsql.ex` - Main adapter
- `lib/ecto/adapters/libsql/connection.ex` - SQL generation

**Rust** (`native/ecto_libsql/src/`):

Expand All @@ -98,8 +98,8 @@ Rust NIF (libsql-rs, connection registry, async runtime)
| `tests/` | Test modules |

**Tests:**
- `test/*.exs` Elixir tests (adapter, integration, migrations, error handling, Turso)
- `native/ecto_libsql/src/tests/` Rust tests (constants, utils, integration)
- `test/*.exs` - Elixir tests (adapter, integration, migrations, error handling, Turso)
- `native/ecto_libsql/src/tests/` - Rust tests (constants, utils, integration)

### Key Data Structures

Expand Down Expand Up @@ -139,7 +139,7 @@ git checkout -b feature-descriptive-name # or bugfix-descriptive-name
- **NEVER run `git clean`** without explicit user approval
- **NEVER run `git checkout .`** or `git restore .` on the whole repo
- **NEVER run `git reset --hard`** without explicit user approval
- Untracked files stay in place across branch switches this is expected
- Untracked files stay in place across branch switches - this is expected

### PR Workflow

Expand All @@ -158,7 +158,7 @@ git branch -d feature-descriptive-name

### Pre-Commit Checklist

**STRICT ORDER do NOT skip steps or reorder:**
**STRICT ORDER - do NOT skip steps or reorder:**

```bash
# 1. Format code (must come FIRST)
Expand Down Expand Up @@ -221,11 +221,11 @@ git add . && git commit -m "..."

## Adding a New NIF Function

**Modern Rustler auto-detects all `#[rustler::nif]` functions no manual registration needed.**
**Modern Rustler auto-detects all `#[rustler::nif]` functions - no manual registration needed.**

1. **Choose the right module** connection lifecycle → `connection.rs`, query execution → `query.rs`, transactions → `transaction.rs`, batch → `batch.rs`, statements → `statement.rs`, cursors → `cursor.rs`, replication → `replication.rs`, metadata → `metadata.rs`, savepoints → `savepoint.rs`
2. **Define the Rust NIF** with `#[rustler::nif(schedule = "DirtyIo")]` use `safe_lock` (never `.unwrap()`) see [Error Handling](#error-handling-patterns)
3. **Add Elixir wrapper** in `lib/ecto_libsql/native.ex` NIF stub + safe wrapper using `EctoLibSql.State`
1. **Choose the right module** - connection lifecycle → `connection.rs`, query execution → `query.rs`, transactions → `transaction.rs`, batch → `batch.rs`, statements → `statement.rs`, cursors → `cursor.rs`, replication → `replication.rs`, metadata → `metadata.rs`, savepoints → `savepoint.rs`
2. **Define the Rust NIF** with `#[rustler::nif(schedule = "DirtyIo")]` - use `safe_lock` (never `.unwrap()`) - see [Error Handling](#error-handling-patterns)
3. **Add Elixir wrapper** in `lib/ecto_libsql/native.ex` - NIF stub + safe wrapper using `EctoLibSql.State`
4. **Add tests** in both Rust (`native/ecto_libsql/src/tests/`) and Elixir (`test/`)
5. **Update documentation** in `USAGE.md` and `CHANGELOG.md`

Expand All @@ -242,7 +242,7 @@ git add . && git commit -m "..."

### Rust Patterns (CRITICAL!)

**NEVER use `.unwrap()` in production code** see `RUST_ERROR_HANDLING.md` for comprehensive patterns.
**NEVER use `.unwrap()` in production code** - see `RUST_ERROR_HANDLING.md` for comprehensive patterns.

#### Pattern 1: Lock a Registry
```rust
Expand Down Expand Up @@ -443,12 +443,12 @@ if entry.conn_id != conn_id {

### Internal Documentation

- **[USAGE.md](USAGE.md)** API reference for library users
- **[README.md](README.md)** User-facing documentation
- **[CHANGELOG.md](CHANGELOG.md)** Version history
- **[ECTO_MIGRATION_GUIDE.md](ECTO_MIGRATION_GUIDE.md)** Migrating from PostgreSQL/MySQL
- **[RUST_ERROR_HANDLING.md](RUST_ERROR_HANDLING.md)** Error pattern reference
- **[TESTING.md](TESTING.md)** Testing strategy and organisation
- **[USAGE.md](USAGE.md)** - API reference for library users
- **[README.md](README.md)** - User-facing documentation
- **[CHANGELOG.md](CHANGELOG.md)** - Version history
- **[ECTO_MIGRATION_GUIDE.md](ECTO_MIGRATION_GUIDE.md)** - Migrating from PostgreSQL/MySQL
- **[RUST_ERROR_HANDLING.md](RUST_ERROR_HANDLING.md)** - Error pattern reference
- **[TESTING.md](TESTING.md)** - Testing strategy and organisation

### External Documentation

Expand Down
62 changes: 32 additions & 30 deletions Cargo.lock

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

5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@

`ecto_libsql` is an (unofficial) Elixir [Ecto](https://github.com/elixir-ecto/ecto) database adapter for [LibSQL](https://github.com/tursodatabase/libsql) database files, and databases hosted on [Turso](https://turso.tech/), built with Rust NIFs. It supports local libSQL/SQLite files, remote replica with synchronisation, and remote only Turso databases.

> [!NOTE]
> **Upstream status:** [Turso is now closer to transitioning away from libSQL](https://turso.tech/blog/sync-benchmark) (their fork of SQLite) in favour of their new [Turso](https://turso.tech/turso) library - their full rewrite of SQLite in Rust. Activity on the [libSQL repository](https://github.com/tursodatabase/libsql) has slowed significantly as a result. We are monitoring the situation. `ecto_libsql` will continue to receive bug fixes and security updates, but is likely to transition to maintenance mode as the Elixir/Turso ecosystem matures. For those interested in using the new Turso library, [turso_ex](https://github.com/bytebottom/turso_ex) is an early-stage Elixir adapter currently under development.

## Installation

Add `ecto_libsql` to your dependencies in `mix.exs`:

```elixir
def deps do
[
{:ecto_libsql, "~> 0.8.0"}
{:ecto_libsql, "~> 0.9.0"}
]
end
```
Expand Down
8 changes: 4 additions & 4 deletions RELEASE_PROCESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ git push

## 2. Create the GitHub release (triggers CI)

The CI workflow triggers on tags matching `*.*.*`. The tag must match the version in `mix.exs` exactly no `v` prefix, as the `base_url` in `native.ex` uses the raw version string.
The CI workflow triggers on tags matching `*.*.*`. The tag must match the version in `mix.exs` exactly - no `v` prefix, as the `base_url` in `native.ex` uses the raw version string.

```bash
gh release create X.Y.Z --title "vX.Y.Z" --draft --generate-notes
Expand Down Expand Up @@ -54,7 +54,7 @@ git commit -m "chore: update checksums for vX.Y.Z"
git push
```

This step is critical the checksum file must be in the package so Hex.pm users can verify the downloaded NIFs.
This step is critical - the checksum file must be in the package so Hex.pm users can verify the downloaded NIFs.

## 6. Publish the GitHub release

Expand All @@ -72,7 +72,7 @@ mix hex.publish

## Key Gotchas

- **Tag format**: Use `0.9.1` not `v0.9.1` the `base_url` in `native.ex` is `releases/download/#{version}`, so the tag and version must match exactly.
- **Tag format**: Use `0.9.1` not `v0.9.1` - the `base_url` in `native.ex` is `releases/download/#{version}`, so the tag and version must match exactly.
- **Checksum before publish**: Always regenerate and commit the checksum file *before* `mix hex.publish`. Without it, users get integrity errors when installing.
- **`--ignore-unavailable`**: Use with caution only after confirming all 6 CI target builds have succeeded and all 6 release artefacts are present; otherwise it can mask missing binaries.
- **`--ignore-unavailable`**: Use with caution - only after confirming all 6 CI target builds have succeeded and all 6 release artefacts are present; otherwise it can mask missing binaries.
- **Test run option**: The `workflow_dispatch` trigger on the release workflow has a `test_only` input that skips the `gh release upload` step, useful for testing the build matrix without creating a real release.
Loading
Loading