Skip to content

Conversation

@ocean
Copy link
Owner

@ocean ocean commented Dec 28, 2025

Write fuzz tests, improve Elixir to make code more idiomatic

Summary by CodeRabbit

  • New Features

    • Richer public types/specs and expanded result/command kinds; connection mode and sync detection exposed.
  • Bug Fixes

    • Safer constraint handling, stricter PRAGMA identifier validation, and environment sanitised when extracting DB schema.
  • Tests

    • Added extensive property‑based fuzzing and expanded tests for SQL, transactions, batching, edge cases and stability.
  • Chores / CI

    • CI gains strict static‑analysis and security checks; tooling and changelog updated.

✏️ Tip: You can customize this high-level summary in your review settings.

This commit includes a thorough code audit with the following improvements:

Code Quality & Idiomaticity:
- Simplified detect_sync/1 in State module - removed unnecessary intermediate
  variable and nested case statements
- Fixed duplicate detect_mode() call in connect/1 - now calls once and reuses
- Removed unnecessary pattern matches (trx_id in disconnect)
- Improved detect_command/1 in Native module - more efficient first-word extraction
  using :binary.match instead of String.split()
- Added nil handlers for reference_on_delete/1 and reference_on_update/1 to prevent
  function clause errors

Type Safety:
- Added comprehensive typespecs to EctoLibSql.State (t(), mode(), sync_mode())
- Added typespec to EctoLibSql.Query (t())
- Extended command_type in EctoLibSql.Result to include all used values
  (:batch, :create, :begin, :commit, :rollback, :pragma, :unknown)
- Added typespecs to connect/1, ping/1, disconnect/2, handle_execute/4,
  detect_mode/1, detect_sync/1, detect_command/1

Testing:
- Added StreamData dependency for property-based testing
- Created comprehensive fuzz tests (test/fuzz_test.exs) covering:
  - State module mode/sync detection with arbitrary inputs
  - Native module command detection with arbitrary strings
  - Query parameter handling with SQL injection attempts
  - Savepoint name validation against injection attacks
  - Connection ID handling with invalid/malicious inputs
  - Batch operations with arbitrary SQL
  - Large input handling

Static Analysis:
- Added Credo dependency for stricter linting
- Created .credo.exs with comprehensive check configuration
- Updated .dialyzer_ignore.exs with clearer comments and regex patterns

Spelling (British English consistency):
- Changed 'optimization' to 'optimisation' in connect/1 comment
Apply Elixir formatter rules to multi-line typespecs for
disconnect/2 and handle_execute/4 functions.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 28, 2025

Walkthrough

Adds strict static analysis and CI checks, expands typespecs/@specs across core Elixir modules, normalises batch/result parsing, tightens identifier validation and constraint handling, and introduces a broad StreamData fuzz test suite with CI integration.

Changes

Cohort / File(s) Summary
Static analysis & CI
/.credo.exs, .github/workflows/ci.yml
Adds Credo configuration and CI steps to run mix credo and mix sobelow; ensures cargo-deny install step for Rust checks.
Dialyzer ignores
/.dialyzer_ignore.exs
Replaces many explicit ignores with consolidated pattern/regex-based ignore entries and comments.
Core API specs & control flow
lib/ecto_libsql.ex, lib/ecto_libsql/native.ex
Adds public @specs for connect/ping/disconnect/handle_execute and native funcs; refactors detect_command; centralises batch result parsing; normalises cursor empty-checks.
Types & struct types
lib/ecto_libsql/query.ex, lib/ecto_libsql/result.ex, lib/ecto_libsql/state.ex
Introduces typedocs and @type definitions (Query.t, expanded Result.command_type, Result.t, State mode/sync_mode/t) and related specs.
Connection & constraint handling
lib/ecto/adapters/libsql/connection.ex, lib/ecto/adapters/libsql.ex
Omits on_delete/on_update when nil, narrows on_conflict matching to non-empty targets, and clears env when invoking sqlite3 in structure_dump.
Pragmas & identifier validation
lib/ecto_libsql/pragma.ex
Adds @specs and sanitises table_info/2 input via valid_identifier?/1, returning {:error, {:invalid_identifier, ...}} for invalid names.
Batch/result normalisation
lib/ecto_libsql/native.ex
Adds parse_batch_results/1 and routes batch/batch_transactional through it to standardise {:ok, list(EctoLibSql.Result.t())} or {:error, term()} results.
Dependencies
mix.exs
Adds dev/test deps: credo (> 1.7), stream_data (> 1.0) and sobelow.
Fuzzing & tests
test/fuzz_test.exs, test/**/*_test.exs
Adds EctoLibSql.FuzzTest (StreamData property tests) and updates many tests to destructure expanded return tuples (_query, _result, _state) and use direct emptiness checks (rows == []).
Changelog & docs
CHANGELOG.md
Documents tooling, fuzzing infra, types/spec changes, CI enhancements and other high-level changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant EctoLibSql
  participant Native
  participant SQLite as DB

  rect rgb(230,245,255)
  Client->>EctoLibSql: handle_execute(query, params)
  EctoLibSql->>Native: prepare/detect_command(query)
  Native->>Native: parse_batch_results / detect_command
  Native->>DB: execute (SQL / batch)
  DB-->>Native: rows / results
  Native-->>EctoLibSql: {:ok, QueryStruct, Result, State} | {:error, err, State}
  EctoLibSql-->>Client: returns tuple with _query, _result, _state
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through specs and Credo trails,
I fuzzed the burrow with wild data sails,
I parsed each batch, checked names for harm,
Tests now whisper safe and calm,
A rabbit nods — tidy, bright, and hale.

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is vague and generic, using non-descriptive terms like 'check over and improve' that don't convey meaningful information about the specific changes made. Consider a more specific title that highlights the primary changes, such as 'Add Credo configuration, fuzz tests, and type specifications' or 'Improve code quality with linting, testing, and type safety'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/audit-ecto-libsql-Cme33

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c27bd4 and a3f06d1.

📒 Files selected for processing (4)
  • .github/workflows/ci.yml
  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/ci.yml
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS use British/Australian English spelling and grammar for code, comments, and documentation, except where required for function calls, SQL keywords, error messages, or compatibility with external systems that may use US English

Files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
**/*.{ex,exs}

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS run the Elixir formatter (mix format --check-formatted) before committing changes and fix any issues

**/*.{ex,exs}: For Ecto schema definitions in Elixir, use Ecto.Schema and Ecto.Changeset modules to define data models with proper validation and type annotations
Use prepared statements with automatic caching for repeated queries in ecto_libsql to achieve ~10-15x performance improvement; statements are cached internally and bindings are cleared via stmt.reset() between calls
For bulk insert operations in ecto_libsql, use batch_transactional/2 to group multiple inserts into a single atomic transaction, providing better performance than individual inserts
Always use pattern matching for database operation results in ecto_libsql to handle both success and error cases; never use bare unwrap patterns that could crash the VM
For read-heavy workloads with ecto_libsql, use remote replica mode (libsql:// URI with local database file and sync: true) to achieve microsecond read latency from local SQLite while auto-syncing writes to remote Turso
Use vector embeddings with ecto_libsql for semantic search by creating vector columns with EctoLibSql.Native.vector_type/2, storing embeddings via vector() SQL function, and querying with vector_distance_cos/2 for cosine distance calculation
For transaction handling in ecto_libsql, use transaction behaviours (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_ONLY) to control lock acquisition; use IMMEDIATE for write-heavy workloads to prevent writer starvation
Use savepoints (create_savepoint, release_savepoint_by_name, rollback_to_savepoint_by_name) within transactions for partial rollback and error recovery, particularly in batch import scenarios
For large result set processing in ecto_libsql, use DBConnection.stream/3 with cursor-based streaming instead of loading all rows into memory; configure batch size with max_rows option
Use EctoLibSql.Pragma module to configure SQLite parameters: enable_foreign_keys/1, set_journal_mode/2 (p...

Files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
lib/ecto_libsql/native.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/ecto_libsql/native.ex: For each new Rust NIF function, add corresponding Elixir NIF stubs and safe wrapper functions in lib/ecto_libsql/native.ex, with proper state management via EctoLibSql.State
For explicitly unsupported functions, update the Elixir wrapper with comprehensive documentation explaining why the feature is unsupported, what architectural constraints prevent it, and what alternative approaches users can take

Files:

  • lib/ecto_libsql/native.ex
lib/**/*.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/**/*.ex: When updating Elixir code, follow the pattern of case matching on NIF results: {:ok, _, result, new_state} for successful query execution or {:error, reason} for failures
In Elixir error handling, prefer with clauses for chaining multiple operations that return Result tuples, providing clear error handling with an else clause
In Ecto changesets, use the cast function to automatically attempt type conversions for fields, which will raise ChangeError if types don't match schema expectations
Use transactions with appropriate isolation behaviours when executing database operations: :deferred for mixed workloads, :immediate for write-heavy operations, :exclusive for critical operations requiring exclusive locks, :read_only for read-only queries
When working with database locks, use transactions with proper timeout configuration, ensure connections are properly closed in try-after blocks, and use immediate/exclusive transaction behaviours for write-heavy workloads to minimise lock contention
When handling vector search operations, verify LibSQL version supports vectors, use correct vector syntax with EctoLibSql.Native.vector() function, insert vectors with vector(?) SQL syntax, and query with vector distance functions like vector_distance_cos

Files:

  • lib/ecto_libsql/native.ex
test/**/*.exs

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.exs: Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions
Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections

Files:

  • test/ecto_libsql_test.exs
test/**/*.{ex,exs}

📄 CodeRabbit inference engine (AGENTS.md)

test/**/*.{ex,exs}: For testing, use fixtures or factories (e.g., ExMachina) to create test data in a predictable, maintainable way rather than hardcoding test data
Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications

Files:

  • test/ecto_libsql_test.exs
🧠 Learnings (38)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Before committing code changes, verify that `mix format --check-formatted` passes and that both `mix test` and `cd native/ecto_libsql && cargo test` succeed without errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust, all non-test code must have no `.unwrap()` calls; this was a critical refactoring in v0.5.0 to eliminate 146 unwrap calls and prevent BEAM VM crashes from panics in native code
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : In Ecto migrations with ecto_libsql, use ALTER COLUMN to modify column attributes (type, NOT NULL, DEFAULT, CHECK, REFERENCES); note that changes only apply to new/updated rows and existing data is not revalidated

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust, all non-test code must have no `.unwrap()` calls; this was a critical refactoring in v0.5.0 to eliminate 146 unwrap calls and prevent BEAM VM crashes from panics in native code

Applied to files:

  • CHANGELOG.md
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : Include comprehensive Rust documentation comments (/// comments) on all public NIF functions explaining purpose, arguments, return values (success and error cases), and usage examples

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : When migrating from standard SQLite to libSQL with ALTER COLUMN, understand that changes only affect new/updated rows; use table recreation pattern on standard SQLite if full revalidation is needed

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto_libsql/native.ex : For explicitly unsupported functions, update the Elixir wrapper with comprehensive documentation explaining why the feature is unsupported, what architectural constraints prevent it, and what alternative approaches users can take

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql.ex : When implementing Ecto storage operations (create, drop, status) in lib/ecto/adapters/libsql.ex, ensure they properly handle both local SQLite and remote Turso databases via the connection mode in EctoLibSql.State

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : When adding a new NIF function in Rust, place it in the appropriate module based on functionality: connection.rs (lifecycle), query.rs (execution), transaction.rs (transactions), batch.rs (batch operations), statement.rs (prepared statements), cursor.rs (streaming), replication.rs (replica sync), metadata.rs (metadata access), or savepoint.rs (nested transactions)

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust async blocks within NIFs, drop registry locks before entering the `TOKIO_RUNTIME.block_on(async { ... })` call to prevent deadlocks, then re-acquire locks if needed after the async block completes

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto_libsql/native.ex : For each new Rust NIF function, add corresponding Elixir NIF stubs and safe wrapper functions in lib/ecto_libsql/native.ex, with proper state management via EctoLibSql.State

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When handling vector search operations, verify LibSQL version supports vectors, use correct vector syntax with `EctoLibSql.Native.vector()` function, insert vectors with `vector(?)` SQL syntax, and query with vector distance functions like `vector_distance_cos`

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : In lib/ecto/adapters/libsql/connection.ex, implement SQL expression handlers for SQLite functions by pattern matching on function names and converting them to SQL fragments, respecting SQLite syntax and limitations

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use prepared statements with automatic caching for repeated queries in ecto_libsql to achieve ~10-15x performance improvement; statements are cached internally and bindings are cleared via stmt.reset() between calls

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always use pattern matching for database operation results in ecto_libsql to handle both success and error cases; never use bare unwrap patterns that could crash the VM

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When updating Elixir code, follow the pattern of case matching on NIF results: `{:ok, _, result, new_state}` for successful query execution or `{:error, reason}` for failures

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : In Ecto changesets, use the `cast` function to automatically attempt type conversions for fields, which will raise ChangeError if types don't match schema expectations

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For read-heavy workloads with ecto_libsql, use remote replica mode (libsql:// URI with local database file and sync: true) to achieve microsecond read latency from local SQLite while auto-syncing writes to remote Turso

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : Use transactions with appropriate isolation behaviours when executing database operations: `:deferred` for mixed workloads, `:immediate` for write-heavy operations, `:exclusive` for critical operations requiring exclusive locks, `:read_only` for read-only queries

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For transaction handling in ecto_libsql, use transaction behaviours (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_ONLY) to control lock acquisition; use IMMEDIATE for write-heavy workloads to prevent writer starvation

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always clean up prepared statement resources by calling EctoLibSql.Native.close_stmt/1 when statements are no longer needed

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For bulk insert operations in ecto_libsql, use batch_transactional/2 to group multiple inserts into a single atomic transaction, providing better performance than individual inserts

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When working with database locks, use transactions with proper timeout configuration, ensure connections are properly closed in try-after blocks, and use immediate/exclusive transaction behaviours for write-heavy workloads to minimise lock contention

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to config/**/*.{exs,ex} : For ecto_libsql, use local mode (database: "file.db") for development and testing; use remote replica mode for production

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always handle database connection errors gracefully by pattern matching on {:ok, state} and {:error, reason} tuples; use supervision trees to manage connection lifecycle

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*migration*test.exs : For SQLite migrations that require column type changes or drops (which SQLite doesn't support via ALTER), use the table recreation pattern: create new table, copy data with transformations, swap tables, and recreate indexes

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to config/**/*.{exs,ex} : For Phoenix applications using ecto_libsql, configure remote replica mode in prod environment with database file, Turso URI, auth token, and pool_size settings

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use transactions (handle_begin/2, handle_commit/2, handle_rollback/2) for multi-step operations that must succeed or fail atomically, such as financial transfers or order creation

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use Repo.transaction/1 with with/1 clauses to handle multiple database operations atomically and rollback on error

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Before committing code changes, verify that `mix format --check-formatted` passes and that both `mix test` and `cd native/ecto_libsql && cargo test` succeed without errors

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/turso_remote_test.exs : For Turso remote tests, use environment variables TURSO_DB_URI and TURSO_AUTH_TOKEN, loading them from .env.local file before running tests; remote tests should be skipped by default if credentials are missing

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use EctoLibSql.Pragma module to configure SQLite parameters: enable_foreign_keys/1, set_journal_mode/2 (preferably WAL), set_cache_size/2, set_synchronous/2, and user_version/1 for schema versioning

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : Document RANDOM ROWID usage in migrations as a libSQL extension not available in standard SQLite; note that it is mutually exclusive with WITHOUT ROWID and AUTOINCREMENT

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : In Ecto migrations with ecto_libsql, use RANDOM ROWID table option (options: [random_rowid: true]) to prevent ID enumeration attacks and conceal business metrics through pseudorandom row IDs instead of sequential integers

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use vector embeddings with ecto_libsql for semantic search by creating vector columns with EctoLibSql.Native.vector_type/2, storing embeddings via vector() SQL function, and querying with vector_distance_cos/2 for cosine distance calculation

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use Ecto queries with where/2, select/2, order_by/2, limit/2, and preload/2 to construct efficient database queries instead of raw SQL when possible

Applied to files:

  • test/ecto_libsql_test.exs
🧬 Code graph analysis (2)
lib/ecto_libsql/native.ex (1)
native/ecto_libsql/src/batch.rs (2)
  • execute_batch (29-91)
  • execute_transactional_batch (111-185)
test/ecto_libsql_test.exs (1)
lib/ecto_libsql.ex (7)
  • connect (77-108)
  • ping (116-121)
  • handle_execute (148-160)
  • handle_begin (169-174)
  • handle_commit (177-179)
  • handle_commit (188-198)
  • disconnect (131-133)
🪛 LanguageTool
CHANGELOG.md

[duplication] ~129-~129: Possible typo: you repeated a word.
Context: ...ests.rs` with structured SQL generation tests - Tests query type detection with generated SQL...

(ENGLISH_WORD_REPEAT_RULE)


[uncategorized] ~173-~173: The preposition ‘to’ seems more likely in this position.
Context: ...er?/1function to sanitise table names intable_info/2` - Prevents potential S...

(AI_HYDRA_LEO_REPLACE_IN_TO)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Elixir 1.17.0 / OTP 26.2 / ubuntu-latest
  • GitHub Check: Elixir 1.17.0 / OTP 26.2 / macos-latest
  • GitHub Check: Rust Checks (macos-latest, stable)
  • GitHub Check: Rust Checks (ubuntu-latest, stable)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (3)
test/ecto_libsql_test.exs (1)

33-33: LGTM! Test patterns correctly updated to match new return shapes.

The test assertions have been properly updated to handle the expanded return tuples from EctoLibSql functions. The patterns consistently use descriptive variable names (_query, _result, _state, _begin_result, _commit_result, _rolled_back_state, _committed_state, _ping_state, _final_state, _reason) which improves readability and follows Elixir best practices for unused variables in pattern matching.

Also applies to: 38-38, 46-46, 57-57, 64-64, 79-79, 100-100, 116-116, 129-129, 139-139, 149-149, 165-165, 172-172, 188-189, 205-205, 212-212, 230-230, 239-239, 244-244, 256-256, 259-265, 274-280, 286-292, 316-316, 335-341, 351-365, 373-379, 388-394, 399-405, 408-414, 523-523, 577-577, 580-580, 587-587

lib/ecto_libsql/native.ex (2)

273-273: LGTM! Proper typespecs added for public functions.

The @spec annotations correctly define the input and return types for sync/1, begin/2, commit/1, and rollback/1. These improve type safety and documentation, making the API clearer for users and enabling Dialyzer to perform better type checking.

Also applies to: 420-421, 446-446, 463-463


787-808: LGTM! Clean helper function for batch result normalisation.

The parse_batch_results/1 helper properly handles both success and error cases. It converts raw batch results into structured EctoLibSql.Result structs with appropriate pattern matching. The implementation follows Elixir best practices with clear pattern clauses for list results and error tuples.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
test/fuzz_test.exs (1)

271-302: Verify state handling in SQL injection test.

The test reuses the original state from the setup context for the table existence check (lines 292-298), but the preceding handle_execute at line 277 returns an updated state that is not captured. While this likely works because the connection ID remains the same, capturing and using the returned state would be more idiomatic and consistent with the coding guidelines for pattern matching on database operation results.

🔎 Suggested improvement
       result =
         try do
-          {:ok, _, result, _state} = EctoLibSql.handle_execute(sql, [injection], [], state)
+          {:ok, _, result, state} = EctoLibSql.handle_execute(sql, [injection], [], state)
           result
         rescue
           e -> {:exception, e}
         end

Note: Since the variable is scoped within the try block, you may need to restructure if you want to use the updated state for the verification query.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bdb216d and cc36dd9.

📒 Files selected for processing (10)
  • .credo.exs
  • .dialyzer_ignore.exs
  • lib/ecto/adapters/libsql/connection.ex
  • lib/ecto_libsql.ex
  • lib/ecto_libsql/native.ex
  • lib/ecto_libsql/query.ex
  • lib/ecto_libsql/result.ex
  • lib/ecto_libsql/state.ex
  • mix.exs
  • test/fuzz_test.exs
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS use British/Australian English spelling and grammar for code, comments, and documentation, except where required for function calls, SQL keywords, error messages, or compatibility with external systems that may use US English

Files:

  • lib/ecto_libsql/query.ex
  • lib/ecto/adapters/libsql/connection.ex
  • test/fuzz_test.exs
  • lib/ecto_libsql/state.ex
  • lib/ecto_libsql.ex
  • mix.exs
  • lib/ecto_libsql/result.ex
  • lib/ecto_libsql/native.ex
**/*.{ex,exs}

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS run the Elixir formatter (mix format --check-formatted) before committing changes and fix any issues

**/*.{ex,exs}: For Ecto schema definitions in Elixir, use Ecto.Schema and Ecto.Changeset modules to define data models with proper validation and type annotations
Use prepared statements with automatic caching for repeated queries in ecto_libsql to achieve ~10-15x performance improvement; statements are cached internally and bindings are cleared via stmt.reset() between calls
For bulk insert operations in ecto_libsql, use batch_transactional/2 to group multiple inserts into a single atomic transaction, providing better performance than individual inserts
Always use pattern matching for database operation results in ecto_libsql to handle both success and error cases; never use bare unwrap patterns that could crash the VM
For read-heavy workloads with ecto_libsql, use remote replica mode (libsql:// URI with local database file and sync: true) to achieve microsecond read latency from local SQLite while auto-syncing writes to remote Turso
Use vector embeddings with ecto_libsql for semantic search by creating vector columns with EctoLibSql.Native.vector_type/2, storing embeddings via vector() SQL function, and querying with vector_distance_cos/2 for cosine distance calculation
For transaction handling in ecto_libsql, use transaction behaviours (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_ONLY) to control lock acquisition; use IMMEDIATE for write-heavy workloads to prevent writer starvation
Use savepoints (create_savepoint, release_savepoint_by_name, rollback_to_savepoint_by_name) within transactions for partial rollback and error recovery, particularly in batch import scenarios
For large result set processing in ecto_libsql, use DBConnection.stream/3 with cursor-based streaming instead of loading all rows into memory; configure batch size with max_rows option
Use EctoLibSql.Pragma module to configure SQLite parameters: enable_foreign_keys/1, set_journal_mode/2 (p...

Files:

  • lib/ecto_libsql/query.ex
  • lib/ecto/adapters/libsql/connection.ex
  • test/fuzz_test.exs
  • lib/ecto_libsql/state.ex
  • lib/ecto_libsql.ex
  • mix.exs
  • lib/ecto_libsql/result.ex
  • lib/ecto_libsql/native.ex
lib/**/*.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/**/*.ex: When updating Elixir code, follow the pattern of case matching on NIF results: {:ok, _, result, new_state} for successful query execution or {:error, reason} for failures
In Elixir error handling, prefer with clauses for chaining multiple operations that return Result tuples, providing clear error handling with an else clause
In Ecto changesets, use the cast function to automatically attempt type conversions for fields, which will raise ChangeError if types don't match schema expectations
Use transactions with appropriate isolation behaviours when executing database operations: :deferred for mixed workloads, :immediate for write-heavy operations, :exclusive for critical operations requiring exclusive locks, :read_only for read-only queries
When working with database locks, use transactions with proper timeout configuration, ensure connections are properly closed in try-after blocks, and use immediate/exclusive transaction behaviours for write-heavy workloads to minimise lock contention
When handling vector search operations, verify LibSQL version supports vectors, use correct vector syntax with EctoLibSql.Native.vector() function, insert vectors with vector(?) SQL syntax, and query with vector distance functions like vector_distance_cos

Files:

  • lib/ecto_libsql/query.ex
  • lib/ecto/adapters/libsql/connection.ex
  • lib/ecto_libsql/state.ex
  • lib/ecto_libsql.ex
  • lib/ecto_libsql/result.ex
  • lib/ecto_libsql/native.ex
lib/ecto/adapters/libsql/connection.ex

📄 CodeRabbit inference engine (CLAUDE.md)

In lib/ecto/adapters/libsql/connection.ex, implement SQL expression handlers for SQLite functions by pattern matching on function names and converting them to SQL fragments, respecting SQLite syntax and limitations

Files:

  • lib/ecto/adapters/libsql/connection.ex
test/**/*.exs

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.exs: Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions
Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections

Files:

  • test/fuzz_test.exs
test/**/*.{ex,exs}

📄 CodeRabbit inference engine (AGENTS.md)

test/**/*.{ex,exs}: For testing, use fixtures or factories (e.g., ExMachina) to create test data in a predictable, maintainable way rather than hardcoding test data
Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications

Files:

  • test/fuzz_test.exs
mix.exs

📄 CodeRabbit inference engine (CLAUDE.md)

In the Hex package release, ensure mix.exs files configuration includes all necessary file patterns: ~w(lib priv .formatter.exs mix.exs README* LICENSE* CHANGELOG* AGENT* native), excluding test directories and build artifacts

Files:

  • mix.exs
lib/ecto_libsql/native.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/ecto_libsql/native.ex: For each new Rust NIF function, add corresponding Elixir NIF stubs and safe wrapper functions in lib/ecto_libsql/native.ex, with proper state management via EctoLibSql.State
For explicitly unsupported functions, update the Elixir wrapper with comprehensive documentation explaining why the feature is unsupported, what architectural constraints prevent it, and what alternative approaches users can take

Files:

  • lib/ecto_libsql/native.ex
🧠 Learnings (29)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Before committing code changes, verify that `mix format --check-formatted` passes and that both `mix test` and `cd native/ecto_libsql && cargo test` succeed without errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql.ex : In type loaders/dumpers in lib/ecto/adapters/libsql.ex, ensure bidirectional conversion: loaders convert SQLite values to Elixir types on retrieval, dumpers convert Elixir types to SQLite on storage
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : When migrating from standard SQLite to libSQL with ALTER COLUMN, understand that changes only affect new/updated rows; use table recreation pattern on standard SQLite if full revalidation is needed
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*migration*test.exs : For SQLite migrations that require column type changes or drops (which SQLite doesn't support via ALTER), use the table recreation pattern: create new table, copy data with transformations, swap tables, and recreate indexes
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql.ex : When implementing Ecto storage operations (create, drop, status) in lib/ecto/adapters/libsql.ex, ensure they properly handle both local SQLite and remote Turso databases via the connection mode in EctoLibSql.State
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use EctoLibSql.Pragma module to configure SQLite parameters: enable_foreign_keys/1, set_journal_mode/2 (preferably WAL), set_cache_size/2, set_synchronous/2, and user_version/1 for schema versioning
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : In lib/ecto/adapters/libsql/connection.ex, implement SQL expression handlers for SQLite functions by pattern matching on function names and converting them to SQL fragments, respecting SQLite syntax and limitations
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to **/*.{ex,exs} : ALWAYS run the Elixir formatter (`mix format --check-formatted`) before committing changes and fix any issues

Applied to files:

  • .credo.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to mix.exs : In the Hex package release, ensure mix.exs files configuration includes all necessary file patterns: ~w(lib priv .formatter.exs mix.exs README* LICENSE* CHANGELOG* AGENT* native), excluding test directories and build artifacts

Applied to files:

  • .credo.exs
  • mix.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use EctoLibSql.Pragma module to configure SQLite parameters: enable_foreign_keys/1, set_journal_mode/2 (preferably WAL), set_cache_size/2, set_synchronous/2, and user_version/1 for schema versioning

Applied to files:

  • .credo.exs
  • .dialyzer_ignore.exs
  • lib/ecto_libsql.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to config/**/*.{exs,ex} : For ecto_libsql, use local mode (database: "file.db") for development and testing; use remote replica mode for production

Applied to files:

  • .credo.exs
  • lib/ecto_libsql/state.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : In Ecto migrations with ecto_libsql, use ALTER COLUMN to modify column attributes (type, NOT NULL, DEFAULT, CHECK, REFERENCES); note that changes only apply to new/updated rows and existing data is not revalidated

Applied to files:

  • lib/ecto_libsql/query.ex
  • lib/ecto/adapters/libsql/connection.ex
  • .dialyzer_ignore.exs
  • lib/ecto_libsql/state.ex
  • lib/ecto_libsql.ex
  • lib/ecto_libsql/result.ex
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use prepared statements with automatic caching for repeated queries in ecto_libsql to achieve ~10-15x performance improvement; statements are cached internally and bindings are cleared via stmt.reset() between calls

Applied to files:

  • lib/ecto_libsql/query.ex
  • lib/ecto_libsql.ex
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql.ex : In type loaders/dumpers in lib/ecto/adapters/libsql.ex, ensure bidirectional conversion: loaders convert SQLite values to Elixir types on retrieval, dumpers convert Elixir types to SQLite on storage

Applied to files:

  • lib/ecto_libsql/query.ex
  • lib/ecto/adapters/libsql/connection.ex
  • .dialyzer_ignore.exs
  • lib/ecto_libsql.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When handling vector search operations, verify LibSQL version supports vectors, use correct vector syntax with `EctoLibSql.Native.vector()` function, insert vectors with `vector(?)` SQL syntax, and query with vector distance functions like `vector_distance_cos`

Applied to files:

  • lib/ecto_libsql/query.ex
  • .dialyzer_ignore.exs
  • lib/ecto_libsql.ex
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto_libsql/native.ex : For explicitly unsupported functions, update the Elixir wrapper with comprehensive documentation explaining why the feature is unsupported, what architectural constraints prevent it, and what alternative approaches users can take

Applied to files:

  • lib/ecto_libsql/query.ex
  • lib/ecto/adapters/libsql/connection.ex
  • .dialyzer_ignore.exs
  • lib/ecto_libsql/state.ex
  • lib/ecto_libsql.ex
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : Use foreign key constraints in migrations with references/2 and on_delete options (delete_all, nilify_all) to maintain referential integrity

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : In lib/ecto/adapters/libsql/connection.ex, implement SQL expression handlers for SQLite functions by pattern matching on function names and converting them to SQL fragments, respecting SQLite syntax and limitations

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
  • .dialyzer_ignore.exs
  • lib/ecto_libsql.ex
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql.ex : When implementing Ecto storage operations (create, drop, status) in lib/ecto/adapters/libsql.ex, ensure they properly handle both local SQLite and remote Turso databases via the connection mode in EctoLibSql.State

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
  • .dialyzer_ignore.exs
  • lib/ecto_libsql/state.ex
  • lib/ecto_libsql.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : When migrating from standard SQLite to libSQL with ALTER COLUMN, understand that changes only affect new/updated rows; use table recreation pattern on standard SQLite if full revalidation is needed

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
  • .dialyzer_ignore.exs
  • lib/ecto_libsql/result.ex
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
  • .dialyzer_ignore.exs
  • test/fuzz_test.exs
  • lib/ecto_libsql/state.ex
  • lib/ecto_libsql.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always use pattern matching for database operation results in ecto_libsql to handle both success and error cases; never use bare unwrap patterns that could crash the VM

Applied to files:

  • .dialyzer_ignore.exs
  • test/fuzz_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When updating Elixir code, follow the pattern of case matching on NIF results: `{:ok, _, result, new_state}` for successful query execution or `{:error, reason}` for failures

Applied to files:

  • .dialyzer_ignore.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust, all non-test code must have no `.unwrap()` calls; this was a critical refactoring in v0.5.0 to eliminate 146 unwrap calls and prevent BEAM VM crashes from panics in native code

Applied to files:

  • .dialyzer_ignore.exs
  • test/fuzz_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always handle database connection errors gracefully by pattern matching on {:ok, state} and {:error, reason} tuples; use supervision trees to manage connection lifecycle

Applied to files:

  • .dialyzer_ignore.exs
  • test/fuzz_test.exs
  • lib/ecto_libsql.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions

Applied to files:

  • test/fuzz_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections

Applied to files:

  • test/fuzz_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : When adding a new NIF function in Rust, place it in the appropriate module based on functionality: connection.rs (lifecycle), query.rs (execution), transaction.rs (transactions), batch.rs (batch operations), statement.rs (prepared statements), cursor.rs (streaming), replication.rs (replica sync), metadata.rs (metadata access), or savepoint.rs (nested transactions)

Applied to files:

  • test/fuzz_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : For testing, use fixtures or factories (e.g., ExMachina) to create test data in a predictable, maintainable way rather than hardcoding test data

Applied to files:

  • test/fuzz_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: When debugging failing tests, run with trace (`mix test file.exs --trace`), verify NIF compilation (`File.exists?("priv/native/ecto_libsql.so")`), check Rust output with `cargo test -- --nocapture`, and run Rust tests independently to isolate issues

Applied to files:

  • test/fuzz_test.exs
  • mix.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For large result set processing in ecto_libsql, use DBConnection.stream/3 with cursor-based streaming instead of loading all rows into memory; configure batch size with max_rows option

Applied to files:

  • test/fuzz_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For bulk insert operations in ecto_libsql, use batch_transactional/2 to group multiple inserts into a single atomic transaction, providing better performance than individual inserts

Applied to files:

  • test/fuzz_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For read-heavy workloads with ecto_libsql, use remote replica mode (libsql:// URI with local database file and sync: true) to achieve microsecond read latency from local SQLite while auto-syncing writes to remote Turso

Applied to files:

  • lib/ecto_libsql/state.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto_libsql/native.ex : For each new Rust NIF function, add corresponding Elixir NIF stubs and safe wrapper functions in lib/ecto_libsql/native.ex, with proper state management via EctoLibSql.State

Applied to files:

  • lib/ecto_libsql.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use Ecto queries with where/2, select/2, order_by/2, limit/2, and preload/2 to construct efficient database queries instead of raw SQL when possible

Applied to files:

  • lib/ecto_libsql/native.ex
🧬 Code graph analysis (1)
lib/ecto_libsql.ex (1)
lib/ecto_libsql/state.ex (1)
  • detect_mode (62-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / ubuntu-latest
  • GitHub Check: Rust Checks (macos-latest, stable)
  • GitHub Check: Rust Checks (ubuntu-latest, stable)
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / macos-latest
  • GitHub Check: Analyze (rust)
🔇 Additional comments (15)
mix.exs (1)

51-59: LGTM! Dependencies properly scoped for development and testing.

The additions of credo and stream_data are correctly configured:

  • credo has runtime: false since it's a static analysis tool
  • Both are scoped to :dev and :test environments only
lib/ecto/adapters/libsql/connection.ex (1)

321-331: LGTM! Defensive nil handling for foreign key constraint options.

Adding explicit nil handlers for reference_on_delete/1 and reference_on_update/1 prevents FunctionClauseError when these options are unspecified. The empty string return correctly omits the ON DELETE/ON UPDATE clause, which matches the behaviour of the :nothing clause. This aligns with the coding guidelines for handling database edge cases gracefully.

.dialyzer_ignore.exs (1)

1-15: LGTM! Well-documented Dialyzer ignore configuration.

The added comments clearly explain the rationale for each suppressed warning category:

  • Ecto adapter callback mismatches (expected)
  • IO list construction for performance (intentional)
  • Complex type union pattern matching (Dialyzer limitation)

Using a regex pattern for the type union warnings is a pragmatic approach to handle multiple related false positives.

.credo.exs (1)

1-155: LGTM! Comprehensive Credo configuration.

The configuration is well-structured with sensible defaults for a database adapter:

  • Strict mode ensures thorough analysis
  • Exclusion of /native/ correctly skips Rust code
  • Thresholds (complexity: 15, arity: 8, nesting: 4) are appropriate for adapter code which often has inherent complexity
  • Disabled checks are justified - the formatter handles MultiAliasImportRequireUse
lib/ecto_libsql/query.ex (1)

23-31: LGTM! Public type specification for Query struct.

The type definition accurately reflects the struct's fields and their optional nature. The type field correctly excludes nil since it has a default value of :binary in the defstruct.

test/fuzz_test.exs (1)

1-525: Comprehensive fuzz testing suite - excellent addition.

This property-based testing suite provides strong coverage for:

  • State mode detection with arbitrary inputs
  • SQL command detection and robustness
  • SQL injection prevention via parameterised queries
  • Savepoint name validation
  • Connection ID handling
  • Large input handling

The tests align well with the coding guidelines for documenting and testing database edge cases. The @tag :slow on large input tests and max_runs: 10 are sensible for performance.

lib/ecto_libsql/result.ex (1)

41-63: LGTM! Expanded command type system with proper documentation.

The enhanced command_type union covers all SQL command categories:

  • DML operations (:select, :insert, :update, :delete)
  • DDL operations (:create - also used for DROP/ALTER)
  • Transaction control (:begin, :commit, :rollback)
  • Utility commands (:pragma, :batch)
  • Fallback cases (:unknown, :other, nil)

Using term() for row values is appropriate given SQLite's dynamic typing. The type references command_type() consistently, improving maintainability.

lib/ecto_libsql/native.ex (1)

465-510: LGTM! Improved command detection with efficient parsing.

The refactored detect_command/1 is more maintainable and efficient:

  • Using :binary.match/2 with delimiters is faster than regex for first-word extraction
  • The fallback clause for non-binary inputs provides defensive handling
  • Type specification references EctoLibSql.Result.command_type() for consistency

DDL command grouping: Lines 507-508 map "drop" and "alter" to :create, grouping all DDL operations under a single atom. This mapping is intentional and necessary, as the command_type() definition only includes :create, not separate atoms for these operations.

lib/ecto_libsql.ex (4)

76-107: LGTM! Well-structured connection initialisation with proper typespec.

The single detect_mode/1 call at line 78 is a good improvement - computing mode once and reusing it avoids redundant logic. The graceful handling of busy_timeout failures (logging but not failing the connection) is appropriate for an optimisation setting.


114-121: LGTM! Correct DBConnection ping semantics.

The typespec accurately reflects the return values, and returning {:disconnect, :ping_failed, state} on failure correctly signals to the connection pool that the connection should be removed.


140-160: LGTM! Comprehensive typespec for query execution.

The multi-clause typespec correctly documents both the query input flexibility (struct or string) and the possible return shapes. The transaction-aware branching logic is clean.


129-131: Typo in typespec: EctoLibSql.Sql.State.t() should be EctoLibSql.State.t().

There's an extra .Sql in the error tuple return type which references a non-existent module. This will cause Dialyzer warnings.

🔎 Proposed fix
   @spec disconnect(Keyword.t(), EctoLibSql.State.t()) ::
-          :ok | {:error, term(), EctoLibSql.Sql.State.t()}
+          :ok | {:error, term(), EctoLibSql.State.t()}
⛔ Skipped due to learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always handle database connection errors gracefully by pattern matching on {:ok, state} and {:error, reason} tuples; use supervision trees to manage connection lifecycle
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql.ex : When implementing Ecto storage operations (create, drop, status) in lib/ecto/adapters/libsql.ex, ensure they properly handle both local SQLite and remote Turso databases via the connection mode in EctoLibSql.State
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always clean up prepared statement resources by calling EctoLibSql.Native.close_stmt/1 when statements are no longer needed
lib/ecto_libsql/state.ex (3)

23-35: LGTM! Well-defined public types with appropriate documentation.

The type definitions provide clear contracts for the module's API. Including | nil for mode and sync in the struct type correctly reflects that these fields may be uninitialised before detect_mode/1 and detect_sync/1 are called.


82-100: LGTM! Clean implementation with good doctests.

The simplified case expression is idiomatic Elixir. The doctests effectively demonstrate the behaviour for all three cases: true, false, and missing key.


61-74: Clarify documentation: remote_replica detection based on parameter presence, not sync value.

The condition sync != nil correctly allows both sync: true and sync: false to trigger :remote_replica mode, which is intentional. The remote_replica mode is determined by the presence of all four parameters (uri, auth_token, database, sync), not by the sync value itself. The actual sync behaviour (enable or disable) is controlled separately via detect_sync/1. However, the documentation example showing only sync: true creates ambiguity. Consider updating the example to show sync: false also results in :remote_replica mode, with a note that the sync control is separate.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
test/statement_ownership_test.exs (1)

276-276: LGTM! More idiomatic emptiness check.

Replacing length(rows) > 0 with rows != [] is more efficient and idiomatic Elixir. This avoids the O(n) length calculation when only checking for emptiness.

test/connection_features_test.exs (1)

30-143: LGTM! Improved test pattern matching consistency.

Updating the pattern matches from {:ok, _, result, _} to {:ok, _query, result, _state} improves code readability and aligns with the test suite standardisation documented in CHANGELOG (lines 150-153). The more descriptive variable names make it clearer what values are being discarded.

test/pragma_test.exs (1)

81-243: LGTM! Consistent variable naming improvements.

The updates to variable bindings make the test code more readable and self-documenting:

  • _set_result, _jm_result, _sync_result clearly indicate what intermediate results represent
  • {:ok, _query, _result, state} pattern is more descriptive than {:ok, _, result, state}

This aligns with the broader test suite standardisation effort documented in CHANGELOG (lines 150-153).

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc36dd9 and 0024826.

⛔ Files ignored due to path filters (1)
  • mix.lock is excluded by !**/*.lock
📒 Files selected for processing (21)
  • .credo.exs
  • .dialyzer_ignore.exs
  • .github/workflows/ci.yml
  • CHANGELOG.md
  • lib/ecto/adapters/libsql.ex
  • lib/ecto/adapters/libsql/connection.ex
  • lib/ecto_libsql.ex
  • lib/ecto_libsql/native.ex
  • lib/ecto_libsql/pragma.ex
  • mix.exs
  • test/advanced_features_test.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/fuzz_test.exs
  • test/pragma_test.exs
  • test/savepoint_test.exs
  • test/security_test.exs
  • test/statement_features_test.exs
  • test/statement_ownership_test.exs
  • test/turso_remote_test.exs
✅ Files skipped from review due to trivial changes (1)
  • test/turso_remote_test.exs
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/ecto_libsql.ex
  • lib/ecto/adapters/libsql/connection.ex
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS use British/Australian English spelling and grammar for code, comments, and documentation, except where required for function calls, SQL keywords, error messages, or compatibility with external systems that may use US English

Files:

  • test/statement_ownership_test.exs
  • lib/ecto_libsql/pragma.ex
  • test/fuzz_test.exs
  • test/advanced_features_test.exs
  • CHANGELOG.md
  • test/savepoint_test.exs
  • mix.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • lib/ecto/adapters/libsql.ex
  • test/security_test.exs
  • test/pragma_test.exs
  • lib/ecto_libsql/native.ex
**/*.{ex,exs}

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS run the Elixir formatter (mix format --check-formatted) before committing changes and fix any issues

**/*.{ex,exs}: For Ecto schema definitions in Elixir, use Ecto.Schema and Ecto.Changeset modules to define data models with proper validation and type annotations
Use prepared statements with automatic caching for repeated queries in ecto_libsql to achieve ~10-15x performance improvement; statements are cached internally and bindings are cleared via stmt.reset() between calls
For bulk insert operations in ecto_libsql, use batch_transactional/2 to group multiple inserts into a single atomic transaction, providing better performance than individual inserts
Always use pattern matching for database operation results in ecto_libsql to handle both success and error cases; never use bare unwrap patterns that could crash the VM
For read-heavy workloads with ecto_libsql, use remote replica mode (libsql:// URI with local database file and sync: true) to achieve microsecond read latency from local SQLite while auto-syncing writes to remote Turso
Use vector embeddings with ecto_libsql for semantic search by creating vector columns with EctoLibSql.Native.vector_type/2, storing embeddings via vector() SQL function, and querying with vector_distance_cos/2 for cosine distance calculation
For transaction handling in ecto_libsql, use transaction behaviours (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_ONLY) to control lock acquisition; use IMMEDIATE for write-heavy workloads to prevent writer starvation
Use savepoints (create_savepoint, release_savepoint_by_name, rollback_to_savepoint_by_name) within transactions for partial rollback and error recovery, particularly in batch import scenarios
For large result set processing in ecto_libsql, use DBConnection.stream/3 with cursor-based streaming instead of loading all rows into memory; configure batch size with max_rows option
Use EctoLibSql.Pragma module to configure SQLite parameters: enable_foreign_keys/1, set_journal_mode/2 (p...

Files:

  • test/statement_ownership_test.exs
  • lib/ecto_libsql/pragma.ex
  • test/fuzz_test.exs
  • test/advanced_features_test.exs
  • test/savepoint_test.exs
  • mix.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • lib/ecto/adapters/libsql.ex
  • test/security_test.exs
  • test/pragma_test.exs
  • lib/ecto_libsql/native.ex
test/**/*.exs

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.exs: Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions
Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections

Files:

  • test/statement_ownership_test.exs
  • test/fuzz_test.exs
  • test/advanced_features_test.exs
  • test/savepoint_test.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
  • test/pragma_test.exs
test/**/*.{ex,exs}

📄 CodeRabbit inference engine (AGENTS.md)

test/**/*.{ex,exs}: For testing, use fixtures or factories (e.g., ExMachina) to create test data in a predictable, maintainable way rather than hardcoding test data
Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications

Files:

  • test/statement_ownership_test.exs
  • test/fuzz_test.exs
  • test/advanced_features_test.exs
  • test/savepoint_test.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
  • test/pragma_test.exs
lib/**/*.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/**/*.ex: When updating Elixir code, follow the pattern of case matching on NIF results: {:ok, _, result, new_state} for successful query execution or {:error, reason} for failures
In Elixir error handling, prefer with clauses for chaining multiple operations that return Result tuples, providing clear error handling with an else clause
In Ecto changesets, use the cast function to automatically attempt type conversions for fields, which will raise ChangeError if types don't match schema expectations
Use transactions with appropriate isolation behaviours when executing database operations: :deferred for mixed workloads, :immediate for write-heavy operations, :exclusive for critical operations requiring exclusive locks, :read_only for read-only queries
When working with database locks, use transactions with proper timeout configuration, ensure connections are properly closed in try-after blocks, and use immediate/exclusive transaction behaviours for write-heavy workloads to minimise lock contention
When handling vector search operations, verify LibSQL version supports vectors, use correct vector syntax with EctoLibSql.Native.vector() function, insert vectors with vector(?) SQL syntax, and query with vector distance functions like vector_distance_cos

Files:

  • lib/ecto_libsql/pragma.ex
  • lib/ecto/adapters/libsql.ex
  • lib/ecto_libsql/native.ex
mix.exs

📄 CodeRabbit inference engine (CLAUDE.md)

In the Hex package release, ensure mix.exs files configuration includes all necessary file patterns: ~w(lib priv .formatter.exs mix.exs README* LICENSE* CHANGELOG* AGENT* native), excluding test directories and build artifacts

Files:

  • mix.exs
lib/ecto/adapters/libsql.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/ecto/adapters/libsql.ex: When implementing Ecto storage operations (create, drop, status) in lib/ecto/adapters/libsql.ex, ensure they properly handle both local SQLite and remote Turso databases via the connection mode in EctoLibSql.State
In type loaders/dumpers in lib/ecto/adapters/libsql.ex, ensure bidirectional conversion: loaders convert SQLite values to Elixir types on retrieval, dumpers convert Elixir types to SQLite on storage

Files:

  • lib/ecto/adapters/libsql.ex
lib/ecto_libsql/native.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/ecto_libsql/native.ex: For each new Rust NIF function, add corresponding Elixir NIF stubs and safe wrapper functions in lib/ecto_libsql/native.ex, with proper state management via EctoLibSql.State
For explicitly unsupported functions, update the Elixir wrapper with comprehensive documentation explaining why the feature is unsupported, what architectural constraints prevent it, and what alternative approaches users can take

Files:

  • lib/ecto_libsql/native.ex
🧠 Learnings (55)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Before committing code changes, verify that `mix format --check-formatted` passes and that both `mix test` and `cd native/ecto_libsql && cargo test` succeed without errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications

Applied to files:

  • test/statement_ownership_test.exs
  • test/fuzz_test.exs
  • test/advanced_features_test.exs
  • CHANGELOG.md
  • test/savepoint_test.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
  • test/pragma_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections

Applied to files:

  • test/statement_ownership_test.exs
  • test/fuzz_test.exs
  • test/advanced_features_test.exs
  • test/savepoint_test.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
  • test/pragma_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For large result set processing in ecto_libsql, use DBConnection.stream/3 with cursor-based streaming instead of loading all rows into memory; configure batch size with max_rows option

Applied to files:

  • test/statement_ownership_test.exs
  • test/advanced_features_test.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/security_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*migration*test.exs : For SQLite migrations that require column type changes or drops (which SQLite doesn't support via ALTER), use the table recreation pattern: create new table, copy data with transformations, swap tables, and recreate indexes

Applied to files:

  • test/statement_ownership_test.exs
  • test/fuzz_test.exs
  • test/advanced_features_test.exs
  • test/batch_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • lib/ecto/adapters/libsql.ex
  • test/security_test.exs
  • test/pragma_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use EctoLibSql.Pragma module to configure SQLite parameters: enable_foreign_keys/1, set_journal_mode/2 (preferably WAL), set_cache_size/2, set_synchronous/2, and user_version/1 for schema versioning

Applied to files:

  • lib/ecto_libsql/pragma.ex
  • .dialyzer_ignore.exs
  • test/ecto_libsql_test.exs
  • lib/ecto/adapters/libsql.ex
  • .credo.exs
  • test/pragma_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : In Ecto migrations with ecto_libsql, use ALTER COLUMN to modify column attributes (type, NOT NULL, DEFAULT, CHECK, REFERENCES); note that changes only apply to new/updated rows and existing data is not revalidated

Applied to files:

  • lib/ecto_libsql/pragma.ex
  • CHANGELOG.md
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • lib/ecto/adapters/libsql.ex
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql.ex : In type loaders/dumpers in lib/ecto/adapters/libsql.ex, ensure bidirectional conversion: loaders convert SQLite values to Elixir types on retrieval, dumpers convert Elixir types to SQLite on storage

Applied to files:

  • lib/ecto_libsql/pragma.ex
  • lib/ecto/adapters/libsql.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : When migrating from standard SQLite to libSQL with ALTER COLUMN, understand that changes only affect new/updated rows; use table recreation pattern on standard SQLite if full revalidation is needed

Applied to files:

  • lib/ecto_libsql/pragma.ex
  • CHANGELOG.md
  • test/batch_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • lib/ecto/adapters/libsql.ex
  • test/pragma_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql.ex : When implementing Ecto storage operations (create, drop, status) in lib/ecto/adapters/libsql.ex, ensure they properly handle both local SQLite and remote Turso databases via the connection mode in EctoLibSql.State

Applied to files:

  • lib/ecto_libsql/pragma.ex
  • test/advanced_features_test.exs
  • CHANGELOG.md
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • lib/ecto/adapters/libsql.ex
  • test/security_test.exs
  • test/pragma_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto_libsql/native.ex : For explicitly unsupported functions, update the Elixir wrapper with comprehensive documentation explaining why the feature is unsupported, what architectural constraints prevent it, and what alternative approaches users can take

Applied to files:

  • lib/ecto_libsql/pragma.ex
  • CHANGELOG.md
  • test/statement_features_test.exs
  • test/security_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use prepared statements with automatic caching for repeated queries in ecto_libsql to achieve ~10-15x performance improvement; statements are cached internally and bindings are cleared via stmt.reset() between calls

Applied to files:

  • lib/ecto_libsql/pragma.ex
  • test/advanced_features_test.exs
  • test/savepoint_test.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • lib/ecto/adapters/libsql.ex
  • test/security_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : In lib/ecto/adapters/libsql/connection.ex, implement SQL expression handlers for SQLite functions by pattern matching on function names and converting them to SQL fragments, respecting SQLite syntax and limitations

Applied to files:

  • lib/ecto_libsql/pragma.ex
  • test/advanced_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • lib/ecto/adapters/libsql.ex
  • test/security_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When handling vector search operations, verify LibSQL version supports vectors, use correct vector syntax with `EctoLibSql.Native.vector()` function, insert vectors with `vector(?)` SQL syntax, and query with vector distance functions like `vector_distance_cos`

Applied to files:

  • lib/ecto_libsql/pragma.ex
  • test/advanced_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : Use foreign key constraints in migrations with references/2 and on_delete options (delete_all, nilify_all) to maintain referential integrity

Applied to files:

  • lib/ecto_libsql/pragma.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When updating Elixir code, follow the pattern of case matching on NIF results: `{:ok, _, result, new_state}` for successful query execution or `{:error, reason}` for failures

Applied to files:

  • lib/ecto_libsql/pragma.ex
  • test/advanced_features_test.exs
  • .dialyzer_ignore.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
  • test/pragma_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions

Applied to files:

  • test/fuzz_test.exs
  • test/advanced_features_test.exs
  • CHANGELOG.md
  • test/savepoint_test.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
  • test/pragma_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : When adding a new NIF function in Rust, place it in the appropriate module based on functionality: connection.rs (lifecycle), query.rs (execution), transaction.rs (transactions), batch.rs (batch operations), statement.rs (prepared statements), cursor.rs (streaming), replication.rs (replica sync), metadata.rs (metadata access), or savepoint.rs (nested transactions)

Applied to files:

  • test/fuzz_test.exs
  • CHANGELOG.md
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : For testing, use fixtures or factories (e.g., ExMachina) to create test data in a predictable, maintainable way rather than hardcoding test data

Applied to files:

  • test/fuzz_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust, all non-test code must have no `.unwrap()` calls; this was a critical refactoring in v0.5.0 to eliminate 146 unwrap calls and prevent BEAM VM crashes from panics in native code

Applied to files:

  • test/fuzz_test.exs
  • test/advanced_features_test.exs
  • CHANGELOG.md
  • test/savepoint_test.exs
  • mix.exs
  • test/batch_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
  • test/pragma_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always use pattern matching for database operation results in ecto_libsql to handle both success and error cases; never use bare unwrap patterns that could crash the VM

Applied to files:

  • test/fuzz_test.exs
  • test/advanced_features_test.exs
  • .dialyzer_ignore.exs
  • test/savepoint_test.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
  • test/pragma_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Before committing code changes, verify that `mix format --check-formatted` passes and that both `mix test` and `cd native/ecto_libsql && cargo test` succeed without errors

Applied to files:

  • .github/workflows/ci.yml
  • CHANGELOG.md
  • test/ecto_libsql_test.exs
  • test/security_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to **/*.{ex,exs} : ALWAYS run the Elixir formatter (`mix format --check-formatted`) before committing changes and fix any issues

Applied to files:

  • .github/workflows/ci.yml
  • .credo.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: When debugging failing tests, run with trace (`mix test file.exs --trace`), verify NIF compilation (`File.exists?("priv/native/ecto_libsql.so")`), check Rust output with `cargo test -- --nocapture`, and run Rust tests independently to isolate issues

Applied to files:

  • .github/workflows/ci.yml
  • mix.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to mix.exs : In the Hex package release, ensure mix.exs files configuration includes all necessary file patterns: ~w(lib priv .formatter.exs mix.exs README* LICENSE* CHANGELOG* AGENT* native), excluding test directories and build artifacts

Applied to files:

  • .github/workflows/ci.yml
  • mix.exs
  • .credo.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : Implement after_compile hooks in migrations to validate migration dependencies and prevent accidental schema corruption

Applied to files:

  • .github/workflows/ci.yml
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use Ecto.Query.from/2 with explicit binding variables for complex queries involving multiple tables and subqueries

Applied to files:

  • test/advanced_features_test.exs
  • test/connection_features_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always handle database connection errors gracefully by pattern matching on {:ok, state} and {:error, reason} tuples; use supervision trees to manage connection lifecycle

Applied to files:

  • test/advanced_features_test.exs
  • .dialyzer_ignore.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto_libsql/native.ex : For each new Rust NIF function, add corresponding Elixir NIF stubs and safe wrapper functions in lib/ecto_libsql/native.ex, with proper state management via EctoLibSql.State

Applied to files:

  • test/advanced_features_test.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to config/**/*.{exs,ex} : For ecto_libsql, use local mode (database: "file.db") for development and testing; use remote replica mode for production

Applied to files:

  • test/advanced_features_test.exs
  • test/ecto_libsql_test.exs
  • lib/ecto/adapters/libsql.ex
  • .credo.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always clean up prepared statement resources by calling EctoLibSql.Native.close_stmt/1 when statements are no longer needed

Applied to files:

  • test/advanced_features_test.exs
  • test/batch_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • test/security_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When working with database locks, use transactions with proper timeout configuration, ensure connections are properly closed in try-after blocks, and use immediate/exclusive transaction behaviours for write-heavy workloads to minimise lock contention

Applied to files:

  • test/advanced_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use Ecto queries with where/2, select/2, order_by/2, limit/2, and preload/2 to construct efficient database queries instead of raw SQL when possible

Applied to files:

  • test/advanced_features_test.exs
  • test/connection_features_test.exs
  • test/ecto_libsql_test.exs
  • test/security_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : Include comprehensive Rust documentation comments (/// comments) on all public NIF functions explaining purpose, arguments, return values (success and error cases), and usage examples

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust async blocks within NIFs, drop registry locks before entering the `TOKIO_RUNTIME.block_on(async { ... })` call to prevent deadlocks, then re-acquire locks if needed after the async block completes

Applied to files:

  • CHANGELOG.md
  • test/security_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use savepoints (create_savepoint, release_savepoint_by_name, rollback_to_savepoint_by_name) within transactions for partial rollback and error recovery, particularly in batch import scenarios

Applied to files:

  • test/savepoint_test.exs
  • test/security_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use transactions (handle_begin/2, handle_commit/2, handle_rollback/2) for multi-step operations that must succeed or fail atomically, such as financial transfers or order creation

Applied to files:

  • test/savepoint_test.exs
  • test/batch_features_test.exs
  • test/ecto_libsql_test.exs
  • test/security_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use Repo.transaction/1 with with/1 clauses to handle multiple database operations atomically and rollback on error

Applied to files:

  • test/savepoint_test.exs
  • test/batch_features_test.exs
  • test/ecto_libsql_test.exs
  • test/security_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/savepoint.rs : In savepoint operations in native/ecto_libsql/src/savepoint.rs, validate that the transaction belongs to the connection by comparing entry.conn_id with the provided conn_id parameter

Applied to files:

  • test/savepoint_test.exs
  • test/security_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For bulk insert operations in ecto_libsql, use batch_transactional/2 to group multiple inserts into a single atomic transaction, providing better performance than individual inserts

Applied to files:

  • test/batch_features_test.exs
  • test/ecto_libsql_test.exs
  • test/statement_features_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : Use transactions with appropriate isolation behaviours when executing database operations: `:deferred` for mixed workloads, `:immediate` for write-heavy operations, `:exclusive` for critical operations requiring exclusive locks, `:read_only` for read-only queries

Applied to files:

  • test/batch_features_test.exs
  • test/ecto_libsql_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use Ecto.Repo.insert_all/3 and Ecto.Repo.update_all/2 for bulk operations instead of looping with individual insert/update calls

Applied to files:

  • test/batch_features_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For read-heavy workloads with ecto_libsql, use remote replica mode (libsql:// URI with local database file and sync: true) to achieve microsecond read latency from local SQLite while auto-syncing writes to remote Turso

Applied to files:

  • test/ecto_libsql_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to config/**/*.{exs,ex} : For Phoenix applications using ecto_libsql, configure remote replica mode in prod environment with database file, Turso URI, auth token, and pool_size settings

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For transaction handling in ecto_libsql, use transaction behaviours (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_ONLY) to control lock acquisition; use IMMEDIATE for write-heavy workloads to prevent writer starvation

Applied to files:

  • test/ecto_libsql_test.exs
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/turso_remote_test.exs : For Turso remote tests, use environment variables TURSO_DB_URI and TURSO_AUTH_TOKEN, loading them from .env.local file before running tests; remote tests should be skipped by default if credentials are missing

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : Document RANDOM ROWID usage in migrations as a libSQL extension not available in standard SQLite; note that it is mutually exclusive with WITHOUT ROWID and AUTOINCREMENT

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : In Ecto migrations with ecto_libsql, use RANDOM ROWID table option (options: [random_rowid: true]) to prevent ID enumeration attacks and conceal business metrics through pseudorandom row IDs instead of sequential integers

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use vector embeddings with ecto_libsql for semantic search by creating vector columns with EctoLibSql.Native.vector_type/2, storing embeddings via vector() SQL function, and querying with vector_distance_cos/2 for cosine distance calculation

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Store encryption keys in environment variables or secret management services, not hardcoded; use at least 32-character encryption keys for database encryption with ecto_libsql

Applied to files:

  • lib/ecto/adapters/libsql.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust NIFs marked with `#[rustler::nif]`, always use the `?` operator for error propagation to automatically convert errors to NifResult and return them to Elixir callers

Applied to files:

  • test/security_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : NEVER use `.unwrap()` in production Rust code; all Rust production code must use safe error handling via `safe_lock` helpers, `ok_or_else` for Option types, and the `?` operator for error propagation

Applied to files:

  • test/security_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/transaction.rs : Use the TransactionEntry struct in Rust transaction operations to track which connection owns each transaction, validating ownership in savepoint and transaction operations to prevent cross-connection misuse

Applied to files:

  • test/security_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: When a function cannot be implemented due to architectural constraints, explicitly mark it as unsupported by returning an `:unsupported` atom error rather than returning vague errors or silently failing

Applied to files:

  • test/security_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : In Elixir error handling, prefer `with` clauses for chaining multiple operations that return Result tuples, providing clear error handling with an `else` clause

Applied to files:

  • test/security_test.exs
🧬 Code graph analysis (7)
test/advanced_features_test.exs (2)
lib/ecto_libsql.ex (1)
  • handle_execute (148-160)
lib/ecto_libsql/native.ex (1)
  • freeze_replica (1699-1701)
test/savepoint_test.exs (1)
lib/ecto_libsql/native.ex (4)
  • commit (447-451)
  • create_savepoint (1337-1339)
  • rollback (464-468)
  • rollback_to_savepoint_by_name (1409-1411)
test/batch_features_test.exs (2)
lib/ecto_libsql.ex (1)
  • handle_execute (148-160)
lib/ecto_libsql/native.ex (2)
  • batch_transactional (765-772)
  • batch (740-744)
test/ecto_libsql_test.exs (2)
lib/ecto_libsql.ex (7)
  • connect (77-108)
  • ping (116-121)
  • handle_execute (148-160)
  • handle_begin (169-174)
  • handle_commit (177-179)
  • handle_commit (188-198)
  • disconnect (131-133)
lib/ecto_libsql/native.ex (2)
  • rollback (464-468)
  • begin (422-432)
test/statement_features_test.exs (1)
lib/ecto_libsql.ex (1)
  • handle_execute (148-160)
test/security_test.exs (2)
lib/ecto_libsql.ex (1)
  • ping (116-121)
lib/ecto_libsql/native.ex (2)
  • create_savepoint (1337-1339)
  • release_savepoint_by_name (1368-1370)
test/pragma_test.exs (1)
lib/ecto_libsql.ex (1)
  • handle_execute (148-160)
🪛 LanguageTool
CHANGELOG.md

[duplication] ~130-~130: Possible typo: you repeated a word.
Context: ...ests.rs` with structured SQL generation tests - Tests query type detection with generated SQL...

(ENGLISH_WORD_REPEAT_RULE)


[typographical] ~135-~135: Do not use a colon (:) before a series that is introduced by a preposition (‘for’). Remove the colon or add a noun or a noun phrase after the preposition.
Context: ...ml`) for dependency auditing - Checks for: license compliance, security advisories...

(RP_COLON)


[uncategorized] ~174-~174: The preposition ‘to’ seems more likely in this position.
Context: ...er?/1function to sanitise table names intable_info/2` - Prevents potential S...

(AI_HYDRA_LEO_REPLACE_IN_TO)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Rust Checks (macos-latest, stable)
  • GitHub Check: Rust Checks (ubuntu-latest, stable)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (31)
.dialyzer_ignore.exs (2)

17-17: Suppression of "pattern can never match" warnings is justified here.

These warnings in ecto_libsql arise from Dialyzer's type analysis of complex patterns—particularly map destructuring in pragma operations and regex pattern matching in error handling. The code demonstrates proper error handling with explicit pattern matching for database operations (as shown in lib/ecto_libsql/pragma.ex and lib/ecto_libsql/error.ex), and the suppression targets a specific warning type with clear documentation. This approach is appropriate for Ecto adapters where type system complexity commonly produces false positives.


6-18: Dialyzer is not configured to run in CI, so these ignore patterns are never validated.

The mix.exs configuration includes list_unused_filters: true, which means Dialyzer would report any patterns that don't match actual warnings. However, the CI workflow doesn't run mix dialyzer, so these patterns are never tested. Consider adding mix check.dialyzer to the CI pipeline to verify that each pattern suppresses only intended warnings and that no new warnings are inadvertently ignored.

mix.exs (1)

51-60: LGTM! Quality tooling dependencies properly configured.

The addition of Credo, Sobelow, and StreamData aligns perfectly with the PR objectives to improve code quality and add property-based fuzzing. All dependencies are correctly scoped to development and testing environments with appropriate runtime flags.

lib/ecto/adapters/libsql.ex (1)

161-162: LGTM! Important security enhancement.

Clearing the environment before invoking sqlite3 is a sound security practice that prevents potentially sensitive environment variables (authentication tokens, encryption keys, etc.) from leaking to the subprocess. The schema dump operation doesn't require access to environment variables, making this a safe and appropriate hardening measure.

test/fuzz_test.exs (6)

16-106: LGTM! Well-designed fuzz test infrastructure.

The test setup and generators demonstrate excellent property-based testing practices:

  • Unique database files prevent test interference
  • Graceful cleanup with try/rescue for disconnect failures
  • Comprehensive SQL injection patterns covering common attack vectors
  • Safe identifier generation follows SQL naming constraints properly

271-306: LGTM! Critical security validation.

This property test is essential for verifying SQL injection prevention. The approach is sound:

  1. Attempts injection via parameterised query
  2. Verifies the fuzz_test table still exists (proving no DROP TABLE executed)
  3. Properly threads state through operations

This provides strong evidence that parameterised queries prevent SQL injection attacks.


313-372: LGTM! Comprehensive savepoint security validation.

The savepoint fuzzing tests provide excellent coverage:

  • Arbitrary names handled gracefully without crashes
  • SQL injection attempts in savepoint names properly rejected
  • Fresh transaction for each iteration prevents state pollution
  • ArgumentError rescue appropriate for non-UTF8 binary limitations in NIFs

The assertion at line 361-362 ensures all injection patterns are blocked, which is critical for nested transaction security.


736-767: LGTM! Essential binary data integrity verification.

The binary round-trip test is well-designed:

  • Verifies BLOB data integrity through insert/select cycle
  • Uses last_insert_rowid for reliable row identification
  • Gracefully handles fuzz test failures (acceptable in property testing)
  • Validates the BLOB encoding improvements documented in CHANGELOG v0.7.0

This ensures binary data is preserved correctly through the Rust NIF boundary.


560-658: LGTM! Thorough transaction and prepared statement coverage.

These property tests validate critical functionality:

  • All transaction behaviours (deferred, immediate, exclusive) tested
  • Nested operations within transactions verified stable
  • Prepared statements tested with diverse parameter types
  • Proper resource cleanup with close_stmt

This validates the statement caching optimisations documented in CHANGELOG v0.7.0 and ensures transactions handle arbitrary operation sequences safely.


664-711: LGTM! Essential edge case coverage.

The extreme value tests are critical for validating type handling:

  • SQLite INTEGER (64-bit signed) boundary values tested
  • Float edge cases (NaN, Infinity) handled gracefully
  • Proper exception handling for fuzz test context

These tests ensure the type conversion layer between Elixir and Rust handles edge cases without panics or data corruption.

CHANGELOG.md (1)

99-186: LGTM! Comprehensive and well-structured changelog.

The changelog entries thoroughly document the quality improvements introduced in this PR:

  • Clear categorisation of tooling additions (Credo, Sobelow, Dialyxir)
  • Detailed coverage of property-based and fuzz testing infrastructure
  • Well-organised Fixed section documenting security improvements

The documentation aligns with the actual code changes observed in the PR and follows the Keep a Changelog format properly.

test/security_test.exs (1)

20-20: LGTM! Pattern matching updates align with expanded return shapes.

The updated pattern matching consistently captures _query, _result, and _state (or _reason for errors) instead of anonymous bindings. This improves code clarity and aligns with the broader API changes across the codebase.

Also applies to: 182-182, 199-199, 222-223, 239-239, 313-313, 364-364, 435-435, 443-443

test/statement_features_test.exs (1)

18-18: LGTM! Consistent pattern matching updates throughout.

All changes consistently destructure the expanded return tuples from handle_execute/4 and related functions, capturing _query, _result, and _state explicitly. This improves maintainability and aligns with the test suite conventions established across the PR.

Also applies to: 53-53, 104-105, 126-126, 149-149, 178-178, 203-203, 209-210, 262-262, 287-287, 297-297, 383-383, 418-418, 440-440

test/savepoint_test.exs (1)

51-51: LGTM! Improved state tracking in transaction operations.

The changes introduce explicit bindings for post-operation states (_committed_state, _rolled_back_state) and update assertions for clarity (e.g., result.rows == [] instead of length(result.rows) == 0 on line 156). These changes improve code readability and maintain proper transaction/savepoint semantics.

Also applies to: 62-62, 70-70, 90-90, 127-127, 152-152, 156-156, 188-188, 204-204, 238-238, 263-263, 285-285, 295-295, 315-315, 354-354, 392-392, 446-446, 479-479, 484-484

lib/ecto_libsql/pragma.ex (2)

70-71: LGTM! Improved type documentation with public specs.

The added @spec annotations for query/2 and enable_foreign_keys/1 improve documentation and enable better static analysis. These specs align with the return types used throughout the module.

Also applies to: 129-129


338-352: Excellent security improvement with identifier validation.

The addition of valid_identifier?/1 and input sanitisation in table_info/2 prevents SQL injection attacks via table names. The regex pattern ^[a-zA-Z_][a-zA-Z0-9_.]*$ is appropriate for SQL identifiers and supports schema-qualified names with dots.

Whilst direct string interpolation is used on line 341, this is acceptable because PRAGMA statements don't support parameterised queries in SQLite. The validation ensures only safe identifiers are interpolated.

Based on learnings, input validation is a critical security measure for database operations.

test/advanced_features_test.exs (1)

52-52: LGTM! Consistent pattern matching with improved variable naming.

The pattern matching updates align with the expanded return shapes, and the rename of result to freeze_result on line 157 improves clarity by distinguishing it from the subsequent select_result.

Also applies to: 60-60, 140-140, 148-148, 157-158, 161-161

test/ecto_libsql_test.exs (1)

33-33: LGTM! Comprehensive pattern matching updates across all test scenarios.

The file has been systematically updated to use explicit bindings (_query, _result, _state, _reason) instead of anonymous patterns. These changes span connection tests, transaction tests, vector operations, encryption tests, and metadata tests, maintaining consistency across the entire test suite.

Also applies to: 38-38, 46-46, 57-57, 64-64, 79-79, 100-100, 116-116, 129-129, 139-139, 149-149, 165-165, 172-172, 188-190, 206-206, 213-213, 231-231, 240-240, 245-245, 257-257, 260-260, 275-275, 287-287, 317-317, 336-336, 352-352, 360-360, 374-374, 389-389, 400-400, 409-409, 524-524, 578-578, 581-581, 588-588

.credo.exs (1)

1-155: LGTM! Comprehensive static analysis configuration.

This Credo configuration establishes a robust code quality framework with:

  • Broad coverage: Consistency, Design, Readability, Refactoring, and Warning checks
  • Reasonable thresholds: Cyclomatic complexity (15), function arity (8), nesting depth (4), module dependencies (25)
  • Sensible exclusions: Disables overly pedantic checks like OnePipePerLine and delegates alias formatting to the Elixir formatter
  • Appropriate scope: Includes lib/ and excludes build artefacts and native code

This aligns well with the PR objective to improve code quality through static analysis.

Based on learnings, ensuring mix format --check-formatted passes is part of the commit verification process.

test/batch_features_test.exs (1)

37-37: LGTM! Consistent pattern matching for batch operations.

The pattern matching updates throughout the batch tests consistently capture _query, _result, and _state from handle_execute/4 calls, and _reason from error tuples. These changes align with the expanded return shapes introduced for batch operations across the codebase.

Also applies to: 46-46, 55-55, 70-70, 73-73, 110-110, 142-142, 145-145, 161-161, 164-164, 182-182, 221-221, 236-236, 239-239

lib/ecto_libsql/native.ex (11)

273-273: LGTM! Typespec added for sync/1.

The typespec accurately reflects the function's signature and return values.


420-421: LGTM! Typespec added for begin/2.

The typespec correctly captures the function's parameters and return values.


446-446: LGTM! Typespec added for commit/1.


463-463: LGTM! Typespec added for rollback/1.


470-493: Well-structured refactoring of detect_command/1.

The refactored implementation provides a clear, maintainable pipeline for command detection with proper fallback handling for invalid inputs. The enhanced documentation with examples is helpful.


495-502: Efficient binary-based word extraction.

The use of :binary.match for finding the first delimiter is a performant approach, and the handling of the no-match case is correct.


727-729: LGTM! Improved parameter documentation.

The clarification that statements are tuples of {sql, args} makes the API clearer.


738-744: Excellent refactoring to use shared parser.

The extraction of result parsing logic into parse_batch_results/1 improves maintainability and reduces duplication. The typespec correctly reflects the function signature.


752-754: LGTM! Consistent documentation update.

Matches the clarification made to batch/2 documentation.


763-772: Consistent refactoring with shared parser.

The use of the same parse_batch_results/1 helper as batch/2 ensures consistent behaviour and reduces code duplication.


774-796: No changes required—batch command type is valid per the Result struct definition.

The Result struct's command_type union type already includes :batch as a valid command type (defined in lib/ecto_libsql/result.ex lines 37–51). Setting command: :batch in parse_batch_results is correct and consistent with the type contract. The NIF batch operations return only result maps without the original SQL, so detecting individual command types per statement isn't possible; using the unified :batch command is the appropriate design choice.

Comment on lines +144 to +148
- name: Run Credo code quality checks
run: mix credo

- name: Run Sobelow security audit
run: mix sobelow --config
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check CHANGELOG for credo references
echo "=== CHANGELOG credo references ==="
rg -n "credo" CHANGELOG.md | head -20

# Check if .credo.exs exists and its content
echo -e "\n=== .credo.exs configuration ==="
if [ -f ".credo.exs" ]; then
  head -50 .credo.exs
else
  echo ".credo.exs not found"
fi

# Verify CI workflow credo step
echo -e "\n=== CI workflow credo steps ==="
rg -n -A 2 "mix credo" .github/workflows/ci.yml

# Check for elixir-tests-compatibility job
echo -e "\n=== Checking for compatibility job ==="
rg -n "elixir-tests-compatibility" .github/workflows/ci.yml || echo "No compatibility job found"

# Get context around line 145
echo -e "\n=== Context around line 145 ==="
sed -n '140,150p' .github/workflows/ci.yml

Repository: ocean/ecto_libsql

Length of output: 2831


🏁 Script executed:

# Check what steps are in the elixir-tests-compatibility job
echo "=== elixir-tests-compatibility job content ==="
sed -n '156,250p' .github/workflows/ci.yml | grep -A 100 "elixir-tests-compatibility:" | head -80

# Also check if credo/sobelow are in that job
echo -e "\n=== Checking for credo/sobelow in compatibility job ==="
sed -n '156,280p' .github/workflows/ci.yml | grep -E "(credo|sobelow)" || echo "No credo or sobelow found in compatibility job section"

# Verify full credo configuration - strict setting context
echo -e "\n=== Full credo default config strict setting ==="
rg -n -B 2 -A 2 "strict:" .credo.exs

Repository: ocean/ecto_libsql

Length of output: 2572


Update CHANGELOG or CI workflow for credo consistency.

The CHANGELOG (line 104) documents "CI now runs: mix credo --strict", but the workflow (line 145) runs mix credo without the --strict flag. The .credo.exs configuration also specifies strict: false. Resolve this inconsistency between documentation and implementation.

Consider adding the credo and sobelow checks to the elixir-tests-compatibility job (which currently runs only compilation and tests) to ensure code quality validation across all Elixir/OTP version combinations, matching the checks already present in the elixir-tests-latest job.

🤖 Prompt for AI Agents
.github/workflows/ci.yml lines 144-148: the CI workflow runs `mix credo`
(non-strict) while the CHANGELOG states `mix credo --strict` and .credo.exs has
`strict: false`; update the workflow and related config for consistency by (A)
changing the `Run Credo code quality checks` step to run `mix credo --strict`
and (B) set `strict: true` in .credo.exs (or update the CHANGELOG to reflect
non-strict if you prefer the opposite); additionally, add the same Credo and
Sobelow steps to the `elixir-tests-compatibility` job so those checks run across
all Elixir/OTP combinations (mirror the commands and placement used in the
`elixir-tests-latest` job).

Comment on lines 504 to 516
defp command_atom("select"), do: :select
defp command_atom("insert"), do: :insert
defp command_atom("update"), do: :update
defp command_atom("delete"), do: :delete
defp command_atom("begin"), do: :begin
defp command_atom("commit"), do: :commit
defp command_atom("create"), do: :create
defp command_atom("rollback"), do: :rollback
defp command_atom("drop"), do: :create
defp command_atom("alter"), do: :create
defp command_atom("pragma"), do: :pragma
defp command_atom(_), do: :unknown

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Search for command_type type definition
rg -n 'command_type' lib/ecto_libsql/ --type=elixir -B2 -A5

Repository: ocean/ecto_libsql

Length of output: 1404


🏁 Script executed:

# Look for Result module and its type definitions
fd 'result\.' lib/ecto_libsql/ --type f

Repository: ocean/ecto_libsql

Length of output: 86


🏁 Script executed:

# Check if there's a Result module
rg -n '@type.*command' lib/ --type=elixir -B1 -A3

Repository: ocean/ecto_libsql

Length of output: 373


🏁 Script executed:

# Look at how command_atom is called and what happens with the result
rg -n 'command_atom' lib/ecto_libsql/ --type=elixir -B2 -A2

Repository: ocean/ecto_libsql

Length of output: 1307


Type safety violation: detect_command/1 returns values outside the defined command_type specification.

The function's spec declares it returns EctoLibSql.Result.command_type(), but the command_type type definition (lib/ecto_libsql/result.ex lines 42-47) only includes :select, :insert, :update, :delete, and :batch. The command_atom/1 function returns additional atoms—:begin, :commit, :create, :rollback, :pragma, and :unknown—that fall outside this type definition, violating type safety. Either extend the command_type definition to include all possible return values from command_atom/1, or narrow the return type of detect_command/1 and handle invalid command types appropriately.

🤖 Prompt for AI Agents
lib/ecto_libsql/native.ex lines 504-516: command_atom/1 returns atoms (:begin,
:commit, :create, :rollback, :pragma, :unknown) that are not part of the
EctoLibSql.Result.command_type() spec; fix by either (A) updating
lib/ecto_libsql/result.ex to expand the command_type type to include all atoms
returned by command_atom/1 (add :begin, :commit, :create, :rollback, :pragma,
:unknown or any appropriate subset), or (B) narrow command_atom/1 to only return
the existing command_type values (map other SQL verbs to :unknown or :batch as
appropriate) and update detect_command/1 spec and any callers to handle the
changed/unknown values; ensure typespecs and callers are consistent after the
change.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/ecto_libsql/native.ex (1)

446-468: Update @spec declarations to match NIF return types.

The specs for commit/1 and rollback/1 incorrectly declare {:ok, EctoLibSql.State.t()}, but the Rust NIF commit_or_rollback_transaction/5 returns NifResult<(Atom, String)>, which becomes {:ok, String} in Elixir (containing a success message like "commit success"). The specs should be {:ok, String} | {:error, term()}.

🧹 Nitpick comments (1)
lib/ecto_libsql/native.ex (1)

506-517: Consider documenting the DDL command grouping or expanding command_type.

"drop" and "alter" are mapped to :create, which groups all DDL commands together. While functionally acceptable, this could be confusing when debugging or logging. Consider either:

  1. Adding a comment explaining the grouping rationale, or
  2. Expanding command_type to include :ddl or individual :drop/:alter variants if distinct handling is needed elsewhere.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0024826 and d702f33.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • lib/ecto/adapters/libsql/connection.ex
  • lib/ecto_libsql/native.ex
  • lib/ecto_libsql/result.ex
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/ecto/adapters/libsql/connection.ex
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS use British/Australian English spelling and grammar for code, comments, and documentation, except where required for function calls, SQL keywords, error messages, or compatibility with external systems that may use US English

Files:

  • lib/ecto_libsql/result.ex
  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
**/*.{ex,exs}

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS run the Elixir formatter (mix format --check-formatted) before committing changes and fix any issues

**/*.{ex,exs}: For Ecto schema definitions in Elixir, use Ecto.Schema and Ecto.Changeset modules to define data models with proper validation and type annotations
Use prepared statements with automatic caching for repeated queries in ecto_libsql to achieve ~10-15x performance improvement; statements are cached internally and bindings are cleared via stmt.reset() between calls
For bulk insert operations in ecto_libsql, use batch_transactional/2 to group multiple inserts into a single atomic transaction, providing better performance than individual inserts
Always use pattern matching for database operation results in ecto_libsql to handle both success and error cases; never use bare unwrap patterns that could crash the VM
For read-heavy workloads with ecto_libsql, use remote replica mode (libsql:// URI with local database file and sync: true) to achieve microsecond read latency from local SQLite while auto-syncing writes to remote Turso
Use vector embeddings with ecto_libsql for semantic search by creating vector columns with EctoLibSql.Native.vector_type/2, storing embeddings via vector() SQL function, and querying with vector_distance_cos/2 for cosine distance calculation
For transaction handling in ecto_libsql, use transaction behaviours (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_ONLY) to control lock acquisition; use IMMEDIATE for write-heavy workloads to prevent writer starvation
Use savepoints (create_savepoint, release_savepoint_by_name, rollback_to_savepoint_by_name) within transactions for partial rollback and error recovery, particularly in batch import scenarios
For large result set processing in ecto_libsql, use DBConnection.stream/3 with cursor-based streaming instead of loading all rows into memory; configure batch size with max_rows option
Use EctoLibSql.Pragma module to configure SQLite parameters: enable_foreign_keys/1, set_journal_mode/2 (p...

Files:

  • lib/ecto_libsql/result.ex
  • lib/ecto_libsql/native.ex
lib/**/*.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/**/*.ex: When updating Elixir code, follow the pattern of case matching on NIF results: {:ok, _, result, new_state} for successful query execution or {:error, reason} for failures
In Elixir error handling, prefer with clauses for chaining multiple operations that return Result tuples, providing clear error handling with an else clause
In Ecto changesets, use the cast function to automatically attempt type conversions for fields, which will raise ChangeError if types don't match schema expectations
Use transactions with appropriate isolation behaviours when executing database operations: :deferred for mixed workloads, :immediate for write-heavy operations, :exclusive for critical operations requiring exclusive locks, :read_only for read-only queries
When working with database locks, use transactions with proper timeout configuration, ensure connections are properly closed in try-after blocks, and use immediate/exclusive transaction behaviours for write-heavy workloads to minimise lock contention
When handling vector search operations, verify LibSQL version supports vectors, use correct vector syntax with EctoLibSql.Native.vector() function, insert vectors with vector(?) SQL syntax, and query with vector distance functions like vector_distance_cos

Files:

  • lib/ecto_libsql/result.ex
  • lib/ecto_libsql/native.ex
lib/ecto_libsql/native.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/ecto_libsql/native.ex: For each new Rust NIF function, add corresponding Elixir NIF stubs and safe wrapper functions in lib/ecto_libsql/native.ex, with proper state management via EctoLibSql.State
For explicitly unsupported functions, update the Elixir wrapper with comprehensive documentation explaining why the feature is unsupported, what architectural constraints prevent it, and what alternative approaches users can take

Files:

  • lib/ecto_libsql/native.ex
🧠 Learnings (25)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Before committing code changes, verify that `mix format --check-formatted` passes and that both `mix test` and `cd native/ecto_libsql && cargo test` succeed without errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: When debugging failing tests, run with trace (`mix test file.exs --trace`), verify NIF compilation (`File.exists?("priv/native/ecto_libsql.so")`), check Rust output with `cargo test -- --nocapture`, and run Rust tests independently to isolate issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For Ecto changesets, define validation functions using Ecto.Changeset.cast/3, validate_required/2, validate_format/3, and unique_constraint/2 to ensure data integrity
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust, all non-test code must have no `.unwrap()` calls; this was a critical refactoring in v0.5.0 to eliminate 146 unwrap calls and prevent BEAM VM crashes from panics in native code
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to **/*.{ex,exs} : ALWAYS run the Elixir formatter (`mix format --check-formatted`) before committing changes and fix any issues
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : In Ecto migrations with ecto_libsql, use ALTER COLUMN to modify column attributes (type, NOT NULL, DEFAULT, CHECK, REFERENCES); note that changes only apply to new/updated rows and existing data is not revalidated

Applied to files:

  • lib/ecto_libsql/result.ex
  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For large result set processing in ecto_libsql, use DBConnection.stream/3 with cursor-based streaming instead of loading all rows into memory; configure batch size with max_rows option

Applied to files:

  • lib/ecto_libsql/result.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : When migrating from standard SQLite to libSQL with ALTER COLUMN, understand that changes only affect new/updated rows; use table recreation pattern on standard SQLite if full revalidation is needed

Applied to files:

  • lib/ecto_libsql/result.ex
  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto_libsql/native.ex : For explicitly unsupported functions, update the Elixir wrapper with comprehensive documentation explaining why the feature is unsupported, what architectural constraints prevent it, and what alternative approaches users can take

Applied to files:

  • lib/ecto_libsql/result.ex
  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : Include comprehensive Rust documentation comments (/// comments) on all public NIF functions explaining purpose, arguments, return values (success and error cases), and usage examples

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Before committing code changes, verify that `mix format --check-formatted` passes and that both `mix test` and `cd native/ecto_libsql && cargo test` succeed without errors

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust, all non-test code must have no `.unwrap()` calls; this was a critical refactoring in v0.5.0 to eliminate 146 unwrap calls and prevent BEAM VM crashes from panics in native code

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql.ex : When implementing Ecto storage operations (create, drop, status) in lib/ecto/adapters/libsql.ex, ensure they properly handle both local SQLite and remote Turso databases via the connection mode in EctoLibSql.State

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : When adding a new NIF function in Rust, place it in the appropriate module based on functionality: connection.rs (lifecycle), query.rs (execution), transaction.rs (transactions), batch.rs (batch operations), statement.rs (prepared statements), cursor.rs (streaming), replication.rs (replica sync), metadata.rs (metadata access), or savepoint.rs (nested transactions)

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust async blocks within NIFs, drop registry locks before entering the `TOKIO_RUNTIME.block_on(async { ... })` call to prevent deadlocks, then re-acquire locks if needed after the async block completes

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When handling vector search operations, verify LibSQL version supports vectors, use correct vector syntax with `EctoLibSql.Native.vector()` function, insert vectors with `vector(?)` SQL syntax, and query with vector distance functions like `vector_distance_cos`

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto_libsql/native.ex : For each new Rust NIF function, add corresponding Elixir NIF stubs and safe wrapper functions in lib/ecto_libsql/native.ex, with proper state management via EctoLibSql.State

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : In lib/ecto/adapters/libsql/connection.ex, implement SQL expression handlers for SQLite functions by pattern matching on function names and converting them to SQL fragments, respecting SQLite syntax and limitations

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always use pattern matching for database operation results in ecto_libsql to handle both success and error cases; never use bare unwrap patterns that could crash the VM

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When updating Elixir code, follow the pattern of case matching on NIF results: `{:ok, _, result, new_state}` for successful query execution or `{:error, reason}` for failures

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : In Ecto changesets, use the `cast` function to automatically attempt type conversions for fields, which will raise ChangeError if types don't match schema expectations

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For read-heavy workloads with ecto_libsql, use remote replica mode (libsql:// URI with local database file and sync: true) to achieve microsecond read latency from local SQLite while auto-syncing writes to remote Turso

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : Use transactions with appropriate isolation behaviours when executing database operations: `:deferred` for mixed workloads, `:immediate` for write-heavy operations, `:exclusive` for critical operations requiring exclusive locks, `:read_only` for read-only queries

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For transaction handling in ecto_libsql, use transaction behaviours (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_ONLY) to control lock acquisition; use IMMEDIATE for write-heavy workloads to prevent writer starvation

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always clean up prepared statement resources by calling EctoLibSql.Native.close_stmt/1 when statements are no longer needed

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For bulk insert operations in ecto_libsql, use batch_transactional/2 to group multiple inserts into a single atomic transaction, providing better performance than individual inserts

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When working with database locks, use transactions with proper timeout configuration, ensure connections are properly closed in try-after blocks, and use immediate/exclusive transaction behaviours for write-heavy workloads to minimise lock contention

Applied to files:

  • lib/ecto_libsql/native.ex
🪛 LanguageTool
CHANGELOG.md

[duplication] ~129-~129: Possible typo: you repeated a word.
Context: ...ests.rs` with structured SQL generation tests - Tests query type detection with generated SQL...

(ENGLISH_WORD_REPEAT_RULE)


[typographical] ~134-~134: Do not use a colon (:) before a series that is introduced by a preposition (‘for’). Remove the colon or add a noun or a noun phrase after the preposition.
Context: ...ml`) for dependency auditing - Checks for: license compliance, security advisories...

(RP_COLON)


[uncategorized] ~173-~173: The preposition ‘to’ seems more likely in this position.
Context: ...er?/1function to sanitise table names intable_info/2` - Prevents potential S...

(AI_HYDRA_LEO_REPLACE_IN_TO)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Rust Checks (ubuntu-latest, stable)
  • GitHub Check: Rust Checks (macos-latest, stable)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (8)
CHANGELOG.md (1)

99-185: Comprehensive and well-structured changelog additions.

The new sections documenting Credo, Dialyxir, Sobelow integration, property-based fuzz testing, and Rust modernisations are thorough and well-documented. Examples, cross-references to code locations, and clear explanations of benefits make this accessible to maintainers and users. The use of British/Australian English spelling (sanitise, behaviour, etc.) is consistent with the coding guidelines.

lib/ecto_libsql/native.ex (4)

273-276: LGTM!

The added @spec accurately documents the function's contract, improving type safety and IDE support.


420-432: LGTM!

The spec correctly documents the function signature. The transaction behaviour options are well-documented in the preceding docstring.


495-504: LGTM!

Efficient binary-based word extraction. Using :binary.match with multiple delimiters is more performant than regex for this simple parsing task.


740-798: LGTM!

The parse_batch_results/1 helper centralises result parsing and eliminates duplication between batch/2 and batch_transactional/2. The fallback clause provides defensive handling for unexpected result shapes.

lib/ecto_libsql/result.ex (3)

11-11: LGTM!

Documentation accurately reflects the expanded command type variants.


41-55: LGTM! Type safety issue resolved.

The expanded command_type now includes all atoms returned by command_atom/1 in native.ex (:begin, :commit, :create, :rollback, :pragma, :unknown), resolving the type safety violation flagged in the past review.


57-63: LGTM!

Good improvements: using command_type() reference for DRY type definitions, and the corrected [[term()]] syntax for the rows type.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/ecto_libsql/native.ex (1)

740-757: LGTM! Batch functions refactored to use shared result parsing.

The batch/2 and batch_transactional/2 functions now use the parse_batch_results/1 helper instead of inline result conversion logic. This eliminates code duplication and improves maintainability. The documentation updates clearly explain the {sql, args} tuple format for statements, and the @spec annotations properly type the functions.

Also applies to: 765-785

♻️ Duplicate comments (1)
lib/ecto_libsql/native.ex (1)

485-528: Type safety violation: command_atom/1 returns atoms outside the command_type specification.

The @spec at line 485 declares that detect_command/1 returns EctoLibSql.Result.command_type(), but command_atom/1 (lines 507-528) returns additional atoms—:begin, :commit, :create, :rollback, :pragma, and :unknown—that fall outside the type definition. According to the past review, the command_type type in lib/ecto_libsql/result.ex only includes :select, :insert, :update, :delete, and :batch.

Either expand the command_type definition to include all possible return values from command_atom/1, or narrow the return type of detect_command/1 and handle invalid command types appropriately.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c27bd4 and a3f06d1.

📒 Files selected for processing (4)
  • .github/workflows/ci.yml
  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/ci.yml
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS use British/Australian English spelling and grammar for code, comments, and documentation, except where required for function calls, SQL keywords, error messages, or compatibility with external systems that may use US English

Files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
**/*.{ex,exs}

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS run the Elixir formatter (mix format --check-formatted) before committing changes and fix any issues

**/*.{ex,exs}: For Ecto schema definitions in Elixir, use Ecto.Schema and Ecto.Changeset modules to define data models with proper validation and type annotations
Use prepared statements with automatic caching for repeated queries in ecto_libsql to achieve ~10-15x performance improvement; statements are cached internally and bindings are cleared via stmt.reset() between calls
For bulk insert operations in ecto_libsql, use batch_transactional/2 to group multiple inserts into a single atomic transaction, providing better performance than individual inserts
Always use pattern matching for database operation results in ecto_libsql to handle both success and error cases; never use bare unwrap patterns that could crash the VM
For read-heavy workloads with ecto_libsql, use remote replica mode (libsql:// URI with local database file and sync: true) to achieve microsecond read latency from local SQLite while auto-syncing writes to remote Turso
Use vector embeddings with ecto_libsql for semantic search by creating vector columns with EctoLibSql.Native.vector_type/2, storing embeddings via vector() SQL function, and querying with vector_distance_cos/2 for cosine distance calculation
For transaction handling in ecto_libsql, use transaction behaviours (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_ONLY) to control lock acquisition; use IMMEDIATE for write-heavy workloads to prevent writer starvation
Use savepoints (create_savepoint, release_savepoint_by_name, rollback_to_savepoint_by_name) within transactions for partial rollback and error recovery, particularly in batch import scenarios
For large result set processing in ecto_libsql, use DBConnection.stream/3 with cursor-based streaming instead of loading all rows into memory; configure batch size with max_rows option
Use EctoLibSql.Pragma module to configure SQLite parameters: enable_foreign_keys/1, set_journal_mode/2 (p...

Files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
lib/ecto_libsql/native.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/ecto_libsql/native.ex: For each new Rust NIF function, add corresponding Elixir NIF stubs and safe wrapper functions in lib/ecto_libsql/native.ex, with proper state management via EctoLibSql.State
For explicitly unsupported functions, update the Elixir wrapper with comprehensive documentation explaining why the feature is unsupported, what architectural constraints prevent it, and what alternative approaches users can take

Files:

  • lib/ecto_libsql/native.ex
lib/**/*.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/**/*.ex: When updating Elixir code, follow the pattern of case matching on NIF results: {:ok, _, result, new_state} for successful query execution or {:error, reason} for failures
In Elixir error handling, prefer with clauses for chaining multiple operations that return Result tuples, providing clear error handling with an else clause
In Ecto changesets, use the cast function to automatically attempt type conversions for fields, which will raise ChangeError if types don't match schema expectations
Use transactions with appropriate isolation behaviours when executing database operations: :deferred for mixed workloads, :immediate for write-heavy operations, :exclusive for critical operations requiring exclusive locks, :read_only for read-only queries
When working with database locks, use transactions with proper timeout configuration, ensure connections are properly closed in try-after blocks, and use immediate/exclusive transaction behaviours for write-heavy workloads to minimise lock contention
When handling vector search operations, verify LibSQL version supports vectors, use correct vector syntax with EctoLibSql.Native.vector() function, insert vectors with vector(?) SQL syntax, and query with vector distance functions like vector_distance_cos

Files:

  • lib/ecto_libsql/native.ex
test/**/*.exs

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.exs: Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions
Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections

Files:

  • test/ecto_libsql_test.exs
test/**/*.{ex,exs}

📄 CodeRabbit inference engine (AGENTS.md)

test/**/*.{ex,exs}: For testing, use fixtures or factories (e.g., ExMachina) to create test data in a predictable, maintainable way rather than hardcoding test data
Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications

Files:

  • test/ecto_libsql_test.exs
🧠 Learnings (38)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Before committing code changes, verify that `mix format --check-formatted` passes and that both `mix test` and `cd native/ecto_libsql && cargo test` succeed without errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust, all non-test code must have no `.unwrap()` calls; this was a critical refactoring in v0.5.0 to eliminate 146 unwrap calls and prevent BEAM VM crashes from panics in native code
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add tests for all new features in appropriate Elixir test files (test/ecto_*_test.exs) and Rust test modules (native/ecto_libsql/src/tests/), covering happy path, error cases, edge cases, and type conversions

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : In Ecto migrations with ecto_libsql, use ALTER COLUMN to modify column attributes (type, NOT NULL, DEFAULT, CHECK, REFERENCES); note that changes only apply to new/updated rows and existing data is not revalidated

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust, all non-test code must have no `.unwrap()` calls; this was a critical refactoring in v0.5.0 to eliminate 146 unwrap calls and prevent BEAM VM crashes from panics in native code

Applied to files:

  • CHANGELOG.md
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : Include comprehensive Rust documentation comments (/// comments) on all public NIF functions explaining purpose, arguments, return values (success and error cases), and usage examples

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : When migrating from standard SQLite to libSQL with ALTER COLUMN, understand that changes only affect new/updated rows; use table recreation pattern on standard SQLite if full revalidation is needed

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto_libsql/native.ex : For explicitly unsupported functions, update the Elixir wrapper with comprehensive documentation explaining why the feature is unsupported, what architectural constraints prevent it, and what alternative approaches users can take

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql.ex : When implementing Ecto storage operations (create, drop, status) in lib/ecto/adapters/libsql.ex, ensure they properly handle both local SQLite and remote Turso databases via the connection mode in EctoLibSql.State

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : When adding a new NIF function in Rust, place it in the appropriate module based on functionality: connection.rs (lifecycle), query.rs (execution), transaction.rs (transactions), batch.rs (batch operations), statement.rs (prepared statements), cursor.rs (streaming), replication.rs (replica sync), metadata.rs (metadata access), or savepoint.rs (nested transactions)

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to native/ecto_libsql/src/!(tests)/**/*.rs : In Rust async blocks within NIFs, drop registry locks before entering the `TOKIO_RUNTIME.block_on(async { ... })` call to prevent deadlocks, then re-acquire locks if needed after the async block completes

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to test/**/*.{ex,exs} : Document and test all database edge cases: NULL handling, type coercions, constraint violations, and concurrent modifications

Applied to files:

  • CHANGELOG.md
  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto_libsql/native.ex : For each new Rust NIF function, add corresponding Elixir NIF stubs and safe wrapper functions in lib/ecto_libsql/native.ex, with proper state management via EctoLibSql.State

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When handling vector search operations, verify LibSQL version supports vectors, use correct vector syntax with `EctoLibSql.Native.vector()` function, insert vectors with `vector(?)` SQL syntax, and query with vector distance functions like `vector_distance_cos`

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : In lib/ecto/adapters/libsql/connection.ex, implement SQL expression handlers for SQLite functions by pattern matching on function names and converting them to SQL fragments, respecting SQLite syntax and limitations

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use prepared statements with automatic caching for repeated queries in ecto_libsql to achieve ~10-15x performance improvement; statements are cached internally and bindings are cleared via stmt.reset() between calls

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always use pattern matching for database operation results in ecto_libsql to handle both success and error cases; never use bare unwrap patterns that could crash the VM

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When updating Elixir code, follow the pattern of case matching on NIF results: `{:ok, _, result, new_state}` for successful query execution or `{:error, reason}` for failures

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : In Ecto changesets, use the `cast` function to automatically attempt type conversions for fields, which will raise ChangeError if types don't match schema expectations

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For read-heavy workloads with ecto_libsql, use remote replica mode (libsql:// URI with local database file and sync: true) to achieve microsecond read latency from local SQLite while auto-syncing writes to remote Turso

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : Use transactions with appropriate isolation behaviours when executing database operations: `:deferred` for mixed workloads, `:immediate` for write-heavy operations, `:exclusive` for critical operations requiring exclusive locks, `:read_only` for read-only queries

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For transaction handling in ecto_libsql, use transaction behaviours (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_ONLY) to control lock acquisition; use IMMEDIATE for write-heavy workloads to prevent writer starvation

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always clean up prepared statement resources by calling EctoLibSql.Native.close_stmt/1 when statements are no longer needed

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : For bulk insert operations in ecto_libsql, use batch_transactional/2 to group multiple inserts into a single atomic transaction, providing better performance than individual inserts

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to lib/**/*.ex : When working with database locks, use transactions with proper timeout configuration, ensure connections are properly closed in try-after blocks, and use immediate/exclusive transaction behaviours for write-heavy workloads to minimise lock contention

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*.exs : Add comprehensive tests for unsupported functions asserting that they always return {:error, :unsupported} and that they don't modify database state or corrupt connections

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to config/**/*.{exs,ex} : For ecto_libsql, use local mode (database: "file.db") for development and testing; use remote replica mode for production

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Always handle database connection errors gracefully by pattern matching on {:ok, state} and {:error, reason} tuples; use supervision trees to manage connection lifecycle

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/**/*migration*test.exs : For SQLite migrations that require column type changes or drops (which SQLite doesn't support via ALTER), use the table recreation pattern: create new table, copy data with transformations, swap tables, and recreate indexes

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to config/**/*.{exs,ex} : For Phoenix applications using ecto_libsql, configure remote replica mode in prod environment with database file, Turso URI, auth token, and pool_size settings

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use transactions (handle_begin/2, handle_commit/2, handle_rollback/2) for multi-step operations that must succeed or fail atomically, such as financial transfers or order creation

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use Repo.transaction/1 with with/1 clauses to handle multiple database operations atomically and rollback on error

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Before committing code changes, verify that `mix format --check-formatted` passes and that both `mix test` and `cd native/ecto_libsql && cargo test` succeed without errors

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-17T11:58:26.477Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-17T11:58:26.477Z
Learning: Applies to test/turso_remote_test.exs : For Turso remote tests, use environment variables TURSO_DB_URI and TURSO_AUTH_TOKEN, loading them from .env.local file before running tests; remote tests should be skipped by default if credentials are missing

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use EctoLibSql.Pragma module to configure SQLite parameters: enable_foreign_keys/1, set_journal_mode/2 (preferably WAL), set_cache_size/2, set_synchronous/2, and user_version/1 for schema versioning

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : Document RANDOM ROWID usage in migrations as a libSQL extension not available in standard SQLite; note that it is mutually exclusive with WITHOUT ROWID and AUTOINCREMENT

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to priv/repo/migrations/*.{ex,exs} : In Ecto migrations with ecto_libsql, use RANDOM ROWID table option (options: [random_rowid: true]) to prevent ID enumeration attacks and conceal business metrics through pseudorandom row IDs instead of sequential integers

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use vector embeddings with ecto_libsql for semantic search by creating vector columns with EctoLibSql.Native.vector_type/2, storing embeddings via vector() SQL function, and querying with vector_distance_cos/2 for cosine distance calculation

Applied to files:

  • test/ecto_libsql_test.exs
📚 Learning: 2025-12-27T00:00:44.643Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T00:00:44.643Z
Learning: Applies to **/*.{ex,exs} : Use Ecto queries with where/2, select/2, order_by/2, limit/2, and preload/2 to construct efficient database queries instead of raw SQL when possible

Applied to files:

  • test/ecto_libsql_test.exs
🧬 Code graph analysis (2)
lib/ecto_libsql/native.ex (1)
native/ecto_libsql/src/batch.rs (2)
  • execute_batch (29-91)
  • execute_transactional_batch (111-185)
test/ecto_libsql_test.exs (1)
lib/ecto_libsql.ex (7)
  • connect (77-108)
  • ping (116-121)
  • handle_execute (148-160)
  • handle_begin (169-174)
  • handle_commit (177-179)
  • handle_commit (188-198)
  • disconnect (131-133)
🪛 LanguageTool
CHANGELOG.md

[duplication] ~129-~129: Possible typo: you repeated a word.
Context: ...ests.rs` with structured SQL generation tests - Tests query type detection with generated SQL...

(ENGLISH_WORD_REPEAT_RULE)


[uncategorized] ~173-~173: The preposition ‘to’ seems more likely in this position.
Context: ...er?/1function to sanitise table names intable_info/2` - Prevents potential S...

(AI_HYDRA_LEO_REPLACE_IN_TO)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Elixir 1.17.0 / OTP 26.2 / ubuntu-latest
  • GitHub Check: Elixir 1.17.0 / OTP 26.2 / macos-latest
  • GitHub Check: Rust Checks (macos-latest, stable)
  • GitHub Check: Rust Checks (ubuntu-latest, stable)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (3)
test/ecto_libsql_test.exs (1)

33-33: LGTM! Test patterns correctly updated to match new return shapes.

The test assertions have been properly updated to handle the expanded return tuples from EctoLibSql functions. The patterns consistently use descriptive variable names (_query, _result, _state, _begin_result, _commit_result, _rolled_back_state, _committed_state, _ping_state, _final_state, _reason) which improves readability and follows Elixir best practices for unused variables in pattern matching.

Also applies to: 38-38, 46-46, 57-57, 64-64, 79-79, 100-100, 116-116, 129-129, 139-139, 149-149, 165-165, 172-172, 188-189, 205-205, 212-212, 230-230, 239-239, 244-244, 256-256, 259-265, 274-280, 286-292, 316-316, 335-341, 351-365, 373-379, 388-394, 399-405, 408-414, 523-523, 577-577, 580-580, 587-587

lib/ecto_libsql/native.ex (2)

273-273: LGTM! Proper typespecs added for public functions.

The @spec annotations correctly define the input and return types for sync/1, begin/2, commit/1, and rollback/1. These improve type safety and documentation, making the API clearer for users and enabling Dialyzer to perform better type checking.

Also applies to: 420-421, 446-446, 463-463


787-808: LGTM! Clean helper function for batch result normalisation.

The parse_batch_results/1 helper properly handles both success and error cases. It converts raw batch results into structured EctoLibSql.Result structs with appropriate pattern matching. The implementation follows Elixir best practices with clear pattern clauses for list results and error tuples.

@ocean ocean merged commit 9e4e94f into main Dec 29, 2025
14 checks passed
@ocean ocean deleted the claude/audit-ecto-libsql-Cme33 branch December 29, 2025 04:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants