Skip to content

Conversation

@ocean
Copy link
Owner

@ocean ocean commented Jan 12, 2026

Addresses issues from PR #57 where Oban failed due to unsupported parameter types.

Problem:

  • Rustler cannot serialise complex Elixir structs like DateTime, NaiveDateTime, Date, Time, and Decimal
  • This caused 'Unsupported argument type' errors when using Oban with ecto_libsql
  • Oban Lifeline plugin failed with Enumerable protocol errors

Solution:

  • Added encode/3 in DBConnection.Query implementation to convert temporal types and Decimal to ISO8601/string format before passing to Rust NIF
  • Added guard clause for non-list params to prevent crashes
  • decode/3 remains a simple pass-through as Native.ex already handles result normalisation correctly

Changes:

  • lib/ecto_libsql/query.ex: Added parameter encoding with type conversions
  • test/ecto_libsql_query_encoding_test.exs: Comprehensive test suite for parameter encoding and result pass-through

Testing:

  • All 638 existing tests pass
  • New test suite covers DateTime, NaiveDateTime, Date, Time, Decimal encoding
  • Tests verify nil, integer, float, string, binary, boolean pass-through unchanged
  • Tests verify mixed parameter types work correctly

Fixes #57

Summary by CodeRabbit

  • New Features

    • Automatic encoding of Elixir values to SQLite-friendly formats (temporal types to ISO8601, Decimal to string, booleans to 1/0, :null to NULL) and JSON encoding for plain maps passed as query parameters, including safe handling for native calls.
  • Bug Fixes

    • Safer handling of unexpected column DEFAULT values: unknown defaults are omitted and a warning is logged.
  • Documentation

    • Added a comprehensive type-encoding guide with examples and limitations.
  • Tests

    • Extensive unit and integration tests covering parameter encoding, NIF parameter handling and migration edge cases.
  • Chores

    • Updated ignore and local settings files.

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

Addresses issues from PR #57 where Oban failed due to unsupported parameter types.

**Problem**:
- Rustler cannot serialise complex Elixir structs like DateTime, NaiveDateTime, Date, Time, and Decimal
- This caused 'Unsupported argument type' errors when using Oban with ecto_libsql
- Oban Lifeline plugin failed with Enumerable protocol errors

**Solution**:
- Added encode/3 in DBConnection.Query implementation to convert temporal types and Decimal to ISO8601/string format before passing to Rust NIF
- Added guard clause for non-list params to prevent crashes
- decode/3 remains a simple pass-through as Native.ex already handles result normalisation correctly

**Changes**:
- lib/ecto_libsql/query.ex: Added parameter encoding with type conversions
- test/ecto_libsql_query_encoding_test.exs: Comprehensive test suite for parameter encoding and result pass-through

**Testing**:
- All 638 existing tests pass
- New test suite covers DateTime, NaiveDateTime, Date, Time, Decimal encoding
- Tests verify nil, integer, float, string, binary, boolean pass-through unchanged
- Tests verify mixed parameter types work correctly

Co-authored-by: nadilas <nadilas@users.noreply.github.com>
Fixes #57
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 12, 2026

Walkthrough

Adds param encoding for Elixir types (temporal types, Decimal, booleans, :null, plain maps→JSON), implements DBConnection.Query.encode/3 for param lists, encodes parameters before Rust NIF calls, adds a fallback for unexpected column_default values, and introduces extensive tests and docs for type encoding and edge cases.

Changes

Cohort / File(s) Summary
Query encoding
lib/ecto_libsql/query.ex
Adds def encode(_query, params, _opts) when is_list(params) and private encoders: DateTime/NaiveDateTime/Date/Time → ISO8601, Decimal → string, booleans → 1/0, :null → nil, plain maps → JSON; other values pass through.
NIF parameter bridge
lib/ecto_libsql/native.ex
Adds encode_parameters/1 and encode_param/1; updates call sites to pass encoded argument lists to NIF across query/execute/transaction paths.
DDL default handling
lib/ecto/adapters/libsql/connection.ex
Adds catch‑all column_default clause that logs a warning and omits DEFAULT for unexpected default types.
Unit tests — query encoding
test/ecto_libsql_query_encoding_test.exs
New tests for DBConnection.Query.encode/3 and decode/3 covering temporal, Decimal, boolean, nil, mixed params, and result pass‑through.
Integration tests — NIF params
test/ecto_integration_test.exs
New tests verifying plain map→JSON encoding for NIF params, nested map round‑trip, and struct (DateTime) handling.
Migration tests — defaults
test/ecto_migration_test.exs
New tests for column_default edge cases (nil, booleans, numeric, string, fragment, unexpected types ignored).
End‑to‑end type encoding tests
test/type_encoding_implementation_test.exs
Large test suite covering boolean, UUID, :null, strings, binaries, numerics, temporals and Ecto interactions; creates TestRepo/schema and end‑to‑end scenarios.
Docs & metadata
AGENTS.md, .claude/settings.local.json, .gitignore, .beads/*
Adds "Type Encoding and Parameter Conversion" docs, updates local CLI settings, .gitignore entries and .beads metadata.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Query as DBConnection.Query
    participant Native
    participant NIF as Rust NIF

    Client->>Query: DBConnection.Query.encode(params)
    Note over Query: map each param via encode_param/1\n(temporal → ISO8601, Decimal → string,\ntrue/false → 1/0, :null → nil, plain maps → JSON)
    Query-->>Client: encoded_params

    Client->>Native: do_query(encoded_params)
    Note over Native: encode_parameters/1 ensures plain maps→JSON\nand returns encoded arg list to NIF
    Native->>NIF: execute(encoded_args)
    NIF-->>Native: raw_result

    Native->>Query: DBConnection.Query.decode(raw_result)
    Note over Query: decode/3 normalises response (columns/rows)
    Query-->>Client: decoded_result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰
I hop through params, tidy each tail,
Dates go ISO, maps curl into JSON pale,
Ones and zeros drum where true/false play,
NIFs hum softly as queries sway,
A rabbit nibbles bugs away.

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Most changes are well-scoped to parameter encoding for Oban compatibility. However, several changes appear out-of-scope: float assertion tightening in existing tests, documentation additions to AGENTS.md, comprehensive type-encoding test suite covering UUIDs and booleans beyond issue #57, and gitignore/configuration modifications. Consider separating out-of-scope changes (test assertions, documentation, config) into separate pull requests focused on parameter encoding for Oban compatibility.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding DateTime/Decimal parameter encoding to fix Oban compatibility issues.
Linked Issues check ✅ Passed The pull request successfully implements all coding objectives from issue #57: converts DateTime, NaiveDateTime, Date, Time, and Decimal types to safe formats; guards against non-list params; preserves result normalisation via pass-through; and includes comprehensive tests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 fix-pr57-issues

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)
lib/ecto_libsql/query.ex (1)

50-55: Consider additional type encodings for completeness.

The current implementation covers the main types causing Oban issues. However, consider whether other types might need encoding:

  • UUID: Ecto may pass Ecto.UUID structs
  • Maps/lists: Nested structures might contain temporal types
  • Atoms: Some query params might be atoms (e.g., :null)

For now, these will pass through to the NIF and may fail if unsupported. This is acceptable if the current scope addresses the immediate Oban issues.

Based on learnings, if additional type conversion issues arise, also check the type loaders/dumpers in lib/ecto/adapters/libsql.ex.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d3fd488 and d00bea8.

📒 Files selected for processing (2)
  • lib/ecto_libsql/query.ex
  • test/ecto_libsql_query_encoding_test.exs
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Use British/Australian English for all code, comments, and documentation (except SQL keywords and compatibility requirements)

Files:

  • lib/ecto_libsql/query.ex
  • test/ecto_libsql_query_encoding_test.exs
lib/**/*.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/**/*.ex: Use proper transactions with timeout for database operations: Repo.transaction(fn -> ... end, timeout: 15_000) to avoid database locked errors
Ensure connections are closed in try/after blocks to prevent connection leaks
Use immediate transactions for write operations: begin(state, behavior: :immediate) for write-heavy workloads
Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Use cast/3 in changesets for automatic type conversion in Elixir

Files:

  • lib/ecto_libsql/query.ex
test/**/*.{exs,ex}

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming: state for connection scope, trx_state for transaction scope, cursor for cursor scope, stmt_id for prepared statement ID scope
When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments
When an error operation returns state in tests that is NOT needed for subsequent operations, discard it with underscore
For terminal test operations, use underscore variable names and assert error tuples with the pattern assert {:error, %EctoLibSql.Error{}, _conn}

Files:

  • test/ecto_libsql_query_encoding_test.exs
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support

Applied to files:

  • lib/ecto_libsql/query.ex
  • test/ecto_libsql_query_encoding_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues

Applied to files:

  • lib/ecto_libsql/query.ex
  • test/ecto_libsql_query_encoding_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir

Applied to files:

  • lib/ecto_libsql/query.ex
  • test/ecto_libsql_query_encoding_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use JSON functions from `EctoLibSql.JSON` module for working with JSON/JSONB data instead of raw SQL strings

Applied to files:

  • lib/ecto_libsql/query.ex
  • test/ecto_libsql_query_encoding_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to priv/repo/migrations/*.exs : For SQLite migrations requiring column type changes, use table recreation pattern: create new table with desired schema, copy data with transformation, drop old table, rename new table, recreate indexes (SQLite doesn't support ALTER COLUMN; SQLite < 3.35.0 doesn't support DROP COLUMN)

Applied to files:

  • lib/ecto_libsql/query.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use prepared statements with `EctoLibSql.Native.prepare/2` for queries executed more than once in a loop or high-frequency operation

Applied to files:

  • lib/ecto_libsql/query.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion

Applied to files:

  • lib/ecto_libsql/query.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For terminal test operations, use underscore variable names and assert error tuples with the pattern `assert {:error, %EctoLibSql.Error{}, _conn}`

Applied to files:

  • test/ecto_libsql_query_encoding_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors

Applied to files:

  • test/ecto_libsql_query_encoding_test.exs
⏰ 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: Elixir 1.18.0 / OTP 27.0 / macos-latest
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / ubuntu-latest
  • GitHub Check: Analyze (rust)
🔇 Additional comments (4)
test/ecto_libsql_query_encoding_test.exs (2)

169-182: Clarify expected behaviour for write operation columns/rows.

The PR objectives state "columns should be a list (not nil) for write commands", yet this test asserts that columns: nil and rows: nil are preserved for write operations. This appears to contradict the stated goal.

If normalisation happens in Native.ex (as the decode/3 docstring suggests), this test is correct for decode/3's pass-through behaviour. However, please verify the end-to-end behaviour aligns with Ecto/Oban expectations.


128-141: No action required. The test expectation is correct. Time.to_iso8601(~T[10:30:45]) outputs "10:30:45" because the Time struct has zero microsecond precision, and the ISO8601 format omits fractional seconds when precision is 0.

lib/ecto_libsql/query.ex (2)

41-48: LGTM!

The implementation correctly handles both list and non-list params. The guard clause ordering ensures list params are encoded while non-list params pass through safely, preventing crashes as mentioned in the PR objectives.


57-59: LGTM!

The pass-through implementation for decode/3 is appropriate given that Native.ex handles result normalisation. The comment clearly documents this design decision.

ocean added 2 commits January 13, 2026 12:02
Adds encode_parameters/1 and encode_param/1 functions to handle
plain Elixir maps in query parameters. Maps are JSON-encoded before
being passed to the Rust NIF, which cannot serialize plain map types.

This fix enables Oban compatibility and any other use cases where
plain maps are passed as query parameters (e.g., for JSON columns,
metadata fields).

Changes:
- Add encode_parameters/1 to map over parameter lists
- Add encode_param/1 to detect and encode plain maps (not structs)
- Update do_query/6 to encode parameters before query_args NIF call
- Update do_execute_with_trx/6 to encode parameters before both
  query_with_trx_args and execute_with_transaction NIF calls
- Add comprehensive tests for map encoding, nested maps, and
  struct handling

Fixes: el-oxv
Adds a catch-all pattern to column_default/1 to handle unexpected
types gracefully instead of raising FunctionClauseError. This prevents
crashes during migration generation when third-party code (like Oban)
passes unexpected default values such as empty maps {}, lists, or
non-boolean atoms.

The catch-all returns an empty string, effectively treating unexpected
types as having no default value, which is the safest fallback.

Changes:
- Add defp column_default(_), do: "" as final clause
- Add comprehensive tests for all supported default types (nil,
  boolean, string, number, fragment)
- Add tests for unexpected types (empty map, list, atom) to verify
  graceful handling

Fixes: el-6yg
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

🤖 Fix all issues with AI agents
In @test/ecto_integration_test.exs:
- Around line 865-895: The test "plain maps are encoded to JSON before passing
to NIF" currently pre-encodes the map with Jason.encode!(metadata), so change
the Ecto.Adapters.SQL.query! call to pass the raw metadata map (remove
Jason.encode!) to exercise the automatic encoding implemented in Native.ex; then
assert the query succeeds (result.num_rows) and inspect result.rows (or fetched
Post.body) to Jason.decode the returned JSON string and verify keys ("tags",
"priority") match expected values, ensuring no "Unsupported argument type" error
is raised.
- Around line 897-920: The test pre-encodes the nested map with Jason.encode!
instead of verifying the adapter's automatic encoding; update the test "nested
maps in parameters are encoded" to pass the raw complex_data as the parameter
(replace the Jason.encode!(complex_data) argument with complex_data) so
Ecto.Adapters.SQL.query! receives the nested map to encode itself, and keep the
existing assertions that decode/inspect the returned JSON to validate nested
values.
🧹 Nitpick comments (3)
lib/ecto/adapters/libsql/connection.ex (1)

425-426: Defensive catch-all clause for unexpected default types.

This addition prevents FunctionClauseError when migrations specify unexpected default types (e.g., empty maps from Oban or other third-party code). Silently returning an empty string (no DEFAULT clause) is a reasonable fallback.

Consider whether a warning log would be helpful for debugging unexpected defaults, though this is optional given the defensive nature of the change.

test/ecto_integration_test.exs (2)

922-936: Test verifies struct handling but not automatic encoding.

The test manually converts DateTime to ISO8601 string (line 931) before passing as parameter. This verifies the string works, but doesn't test that DateTime structs are automatically handled differently from plain maps by the encoding logic.

A more comprehensive test would pass the raw DateTime struct and verify it's correctly handled (either encoded or passed through to query.ex's encode logic).


858-863: Setup duplicates main setup block.

The describe block's setup (lines 859-863) duplicates the cleanup already performed by the main setup block (lines 103-108). While not harmful, this is redundant.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d00bea8 and 310029a.

📒 Files selected for processing (4)
  • lib/ecto/adapters/libsql/connection.ex
  • lib/ecto_libsql/native.ex
  • test/ecto_integration_test.exs
  • test/ecto_migration_test.exs
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Use British/Australian English for all code, comments, and documentation (except SQL keywords and compatibility requirements)

Files:

  • lib/ecto_libsql/native.ex
  • test/ecto_integration_test.exs
  • test/ecto_migration_test.exs
  • lib/ecto/adapters/libsql/connection.ex
lib/**/*.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/**/*.ex: Use proper transactions with timeout for database operations: Repo.transaction(fn -> ... end, timeout: 15_000) to avoid database locked errors
Ensure connections are closed in try/after blocks to prevent connection leaks
Use immediate transactions for write operations: begin(state, behavior: :immediate) for write-heavy workloads
Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Use cast/3 in changesets for automatic type conversion in Elixir

Files:

  • lib/ecto_libsql/native.ex
  • lib/ecto/adapters/libsql/connection.ex
test/**/*.{exs,ex}

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming: state for connection scope, trx_state for transaction scope, cursor for cursor scope, stmt_id for prepared statement ID scope
When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments
When an error operation returns state in tests that is NOT needed for subsequent operations, discard it with underscore
For terminal test operations, use underscore variable names and assert error tuples with the pattern assert {:error, %EctoLibSql.Error{}, _conn}

Files:

  • test/ecto_integration_test.exs
  • test/ecto_migration_test.exs
lib/ecto/adapters/libsql/connection.ex

📄 CodeRabbit inference engine (CLAUDE.md)

Update SQL generation in lib/ecto/adapters/libsql/connection.ex when adding SQLite function support

Files:

  • lib/ecto/adapters/libsql/connection.ex
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to priv/repo/migrations/*.exs : For SQLite migrations requiring column type changes, use table recreation pattern: create new table with desired schema, copy data with transformation, drop old table, rename new table, recreate indexes (SQLite doesn't support ALTER COLUMN; SQLite < 3.35.0 doesn't support DROP COLUMN)
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support

Applied to files:

  • lib/ecto_libsql/native.ex
  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues

Applied to files:

  • lib/ecto_libsql/native.ex
  • test/ecto_migration_test.exs
  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use named parameters (`:name`, `name`, `$name` syntax) with map-based parameters in `handle_execute/4` for complex queries with many parameters

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use prepared statements with `EctoLibSql.Native.prepare/2` for queries executed more than once in a loop or high-frequency operation

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Wrap multi-step database operations in transactions using `EctoLibSql.handle_begin/2`, execute operations, then `EctoLibSql.handle_commit/2` or `EctoLibSql.handle_rollback/2`

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use batch operations with `EctoLibSql.Native.batch_transactional/2` for bulk inserts instead of looping with individual inserts

Applied to files:

  • lib/ecto_libsql/native.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments

Applied to files:

  • test/ecto_integration_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For terminal test operations, use underscore variable names and assert error tuples with the pattern `assert {:error, %EctoLibSql.Error{}, _conn}`

Applied to files:

  • test/ecto_integration_test.exs
  • test/ecto_migration_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use Ecto changesets for all data validation and transformation in Phoenix/Elixir applications

Applied to files:

  • test/ecto_integration_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to priv/repo/migrations/*.exs : For SQLite migrations requiring column type changes, use table recreation pattern: create new table with desired schema, copy data with transformation, drop old table, rename new table, recreate indexes (SQLite doesn't support ALTER COLUMN; SQLite < 3.35.0 doesn't support DROP COLUMN)

Applied to files:

  • test/ecto_migration_test.exs
  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion

Applied to files:

  • test/ecto_migration_test.exs
  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors

Applied to files:

  • test/ecto_migration_test.exs
  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use generated columns with `generated: "expression"` option in migrations for computed values that should be automatically maintained

Applied to files:

  • test/ecto_migration_test.exs
  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Add comprehensive test coverage including happy path, error cases, edge cases, transaction rollback scenarios, type conversions, and concurrent operations

Applied to files:

  • test/ecto_migration_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Handle all database operations with case/2 or with/1 patterns to catch and log `{:error, reason}` tuples gracefully

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Ensure connections are closed in try/after blocks to prevent connection leaks

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
🧬 Code graph analysis (1)
lib/ecto_libsql/native.ex (2)
native/ecto_libsql/src/query.rs (1)
  • query_args (33-116)
native/ecto_libsql/src/transaction.rs (2)
  • query_with_trx_args (322-404)
  • execute_with_transaction (283-307)
⏰ 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: Elixir 1.18.0 / OTP 27.0 / ubuntu-latest
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / macos-latest
  • GitHub Check: Analyze (rust)
🔇 Additional comments (4)
lib/ecto_libsql/native.ex (3)

2176-2193: Parameter encoding implementation looks correct.

The encoding logic correctly:

  • Identifies plain maps (not structs) using is_map(value) and not is_struct(value)
  • Converts them to JSON strings before NIF invocation
  • Passes through all other values unchanged

One consideration: Jason.encode!/1 raises Jason.EncodeError if the map contains non-encodable terms (e.g., PIDs, references, or functions). For typical use cases like Oban job metadata, this should be fine. If robustness against malformed maps is desired, consider wrapping in a try/rescue or using Jason.encode/1 with error handling.


686-690: LGTM - Encoding applied correctly in non-transactional path.

The encoding step is appropriately placed after argument normalisation, ensuring that any map values in the parameter list are converted to JSON strings before being passed to the Rust NIF.


754-770: LGTM - Encoding consistently applied in transactional paths.

Both query_with_trx_args and execute_with_transaction correctly receive encoded arguments, maintaining consistency with the non-transactional path.

test/ecto_migration_test.exs (1)

881-978: Comprehensive test coverage for column_default edge cases.

The tests thoroughly cover:

  • Standard default types (nil, boolean, string, numeric, fragment)
  • Unexpected types (empty map, list, atom) that triggered the catch-all clause

The assertions correctly verify both presence and absence of DEFAULT clauses using regex patterns. Good use of comments explaining the context (e.g., "Empty maps can come from Oban migrations").

ocean added 5 commits January 13, 2026 14:47
- Implement boolean encoding (true→1, false→0) for SQLite compatibility
- Implement :null atom encoding (:null→nil for SQL NULL values)
- UUID encoding verified to work correctly as strings
- Add comprehensive test suite with 57 tests covering:
  * UUID encoding in query parameters and WHERE clauses
  * Boolean encoding in INSERT/UPDATE/DELETE and WHERE clauses
  * :null atom encoding for NULL values
  * Mixed type encoding in batch operations
  * Ecto schema integration with encoded types
  * Ecto.Query support with encoded type parameters
  * Edge cases: empty strings, large numbers, special chars, binary data
  * Temporal types (DateTime, NaiveDateTime, Date, Time)
  * Decimal and numeric edge cases
  * Nested structures limitation documentation

Tests pass: 94 tests in ecto_integration_test + type encoding tests

Documentation updates:
- Add Type Encoding and Parameter Conversion section to AGENTS.md
- Document all supported automatic type conversions
- Document nested structure limitation and workarounds
- Add examples for boolean, UUID, :null, and temporal types

Closes issues:
- el-5mr: Comprehensive type encoding tests
- el-e9r: Boolean encoding support
- el-pre: UUID encoding verification
- el-gwo: :null atom encoding support
- el-h0i: Document nested structure limitations
- Document relative date handling: compute absolute date first, then pass
- Add examples using Date.add() for future/past dates
- Document third-party date types (Timex, etc.) limitation
- Provide pattern for converting custom date structs to native types
- Clarify that encoder only handles native DateTime/Date/Time/NaiveDateTime
- Remove TYPE_ENCODING_SUMMARY.md from git (keep locally untracked)
- Remove .beads/.sync.lock and .beads/sync_base.jsonl from git
- Add .beads/ to .gitignore to prevent future tracking
- Add TYPE_ENCODING_SUMMARY.md to .gitignore
- These are local development artifacts and should not be committed
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

🤖 Fix all issues with AI agents
In @test/type_encoding_investigation_test.exs:
- Around line 1-2: The file EctoLibSql.TypeEncodingInvestigationTest is not
formatted per mix format; run mix format on
test/type_encoding_investigation_test.exs (or apply the formatting changes) so
the module definition and use line conform to project formatting rules;
specifically reformat the module declaration
EctoLibSql.TypeEncodingInvestigationTest and the use ExUnit.Case line by running
`mix format` (or fix spacing/indentation to match mix format output) and commit
the updated file.

In @TYPE_ENCODING_SUMMARY.md:
- Around line 140-152: The fenced code block showing the git commit (the block
starting with "commit 7671d65") lacks a language specifier and triggers
markdownlint MD040; update the opening fence for that block in
TYPE_ENCODING_SUMMARY.md to include a language such as "text" or "plaintext"
(e.g., change the opening ``` to ```text) so the linter is satisfied while
preserving the commit contents.
🧹 Nitpick comments (1)
test/type_encoding_investigation_test.exs (1)

259-271: Consider removing or using the unused variable.

The _list_pre_encoded variable is defined but never used in the test assertion. The test only verifies that a single integer parameter works, which doesn't actually test the pre-encoded list behaviour described in the test name.

💡 Suggested improvement

Either remove the unused variable and rename the test, or actually test with the pre-encoded values:

     test "list with pre-encoded temporal values works" do
       now = DateTime.utc_now()
-      _list_pre_encoded = [
+      list_pre_encoded = [
         DateTime.to_iso8601(now),
         "string",
         42
       ]
 
-      # Plain lists might work or fail depending on parameter handling
-      # Let's verify the behavior
-      result = SQL.query!(TestRepo, "SELECT ?", [1])
+      # Pre-encoded list passed as JSON string works
+      json = Jason.encode!(list_pre_encoded)
+      result = SQL.query!(TestRepo, "INSERT INTO test_types (text_col) VALUES (?)", [json])
       assert result.num_rows == 1
+
+      SQL.query!(TestRepo, "DELETE FROM test_types")
     end
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 310029a and 3d94b37.

⛔ Files ignored due to path filters (1)
  • .beads/.sync.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • .beads/last-touched
  • .beads/sync_base.jsonl
  • .claude/settings.local.json
  • AGENTS.md
  • TYPE_ENCODING_SUMMARY.md
  • lib/ecto_libsql/query.ex
  • test/type_encoding_implementation_test.exs
  • test/type_encoding_investigation_test.exs
✅ Files skipped from review due to trivial changes (2)
  • AGENTS.md
  • .beads/last-touched
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Use British/Australian English for all code, comments, and documentation (except SQL keywords and compatibility requirements)

Files:

  • test/type_encoding_investigation_test.exs
  • test/type_encoding_implementation_test.exs
  • TYPE_ENCODING_SUMMARY.md
  • lib/ecto_libsql/query.ex
test/**/*.{exs,ex}

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming: state for connection scope, trx_state for transaction scope, cursor for cursor scope, stmt_id for prepared statement ID scope
When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments
When an error operation returns state in tests that is NOT needed for subsequent operations, discard it with underscore
For terminal test operations, use underscore variable names and assert error tuples with the pattern assert {:error, %EctoLibSql.Error{}, _conn}

Files:

  • test/type_encoding_investigation_test.exs
  • test/type_encoding_implementation_test.exs
lib/**/*.ex

📄 CodeRabbit inference engine (CLAUDE.md)

lib/**/*.ex: Use proper transactions with timeout for database operations: Repo.transaction(fn -> ... end, timeout: 15_000) to avoid database locked errors
Ensure connections are closed in try/after blocks to prevent connection leaks
Use immediate transactions for write operations: begin(state, behavior: :immediate) for write-heavy workloads
Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Use cast/3 in changesets for automatic type conversion in Elixir

Files:

  • lib/ecto_libsql/query.ex
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use JSON functions from `EctoLibSql.JSON` module for working with JSON/JSONB data instead of raw SQL strings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use Ecto changesets for all data validation and transformation in Phoenix/Elixir applications
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues

Applied to files:

  • test/type_encoding_investigation_test.exs
  • test/type_encoding_implementation_test.exs
  • TYPE_ENCODING_SUMMARY.md
  • lib/ecto_libsql/query.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors

Applied to files:

  • test/type_encoding_investigation_test.exs
  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For terminal test operations, use underscore variable names and assert error tuples with the pattern `assert {:error, %EctoLibSql.Error{}, _conn}`

Applied to files:

  • test/type_encoding_investigation_test.exs
  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support

Applied to files:

  • test/type_encoding_investigation_test.exs
  • test/type_encoding_implementation_test.exs
  • TYPE_ENCODING_SUMMARY.md
  • lib/ecto_libsql/query.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir

Applied to files:

  • test/type_encoding_investigation_test.exs
  • test/type_encoding_implementation_test.exs
  • TYPE_ENCODING_SUMMARY.md
  • lib/ecto_libsql/query.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to priv/repo/migrations/*.exs : For SQLite migrations requiring column type changes, use table recreation pattern: create new table with desired schema, copy data with transformation, drop old table, rename new table, recreate indexes (SQLite doesn't support ALTER COLUMN; SQLite < 3.35.0 doesn't support DROP COLUMN)

Applied to files:

  • test/type_encoding_investigation_test.exs
  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion

Applied to files:

  • test/type_encoding_investigation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Add comprehensive test coverage including happy path, error cases, edge cases, transaction rollback scenarios, type conversions, and concurrent operations

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use JSON functions from `EctoLibSql.JSON` module for working with JSON/JSONB data instead of raw SQL strings

Applied to files:

  • lib/ecto_libsql/query.ex
🧬 Code graph analysis (1)
test/type_encoding_implementation_test.exs (1)
lib/ecto/adapters/libsql/connection.ex (3)
  • insert (647-668)
  • from (851-854)
  • all (590-621)
🪛 GitHub Actions: CI
test/type_encoding_investigation_test.exs

[error] 1-1: Mix format check failed. The following files are not formatted: /home/runner/work/ecto_libsql/ecto_libsql/test/type_encoding_investigation_test.exs

test/type_encoding_implementation_test.exs

[error] 1-1: Mix format check failed. The following files are not formatted: /home/runner/work/ecto_libsql/ecto_libsql/test/type_encoding_implementation_test.exs

🪛 LanguageTool
TYPE_ENCODING_SUMMARY.md

[uncategorized] ~87-~87: Loose punctuation mark.
Context: ... :boolean fields work seamlessly ### :null Atom Encoding Provides an alternati...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.18.1)
TYPE_ENCODING_SUMMARY.md

140-140: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ 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). (1)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (14)
.claude/settings.local.json (1)

52-56: LGTM!

The added GitHub CLI permissions (gh pr diff, gh pr checks, gh run view, gh pr checkout) are appropriate read-only operations that support PR review and CI workflows.

lib/ecto_libsql/query.ex (3)

41-55: LGTM!

The encode/3 implementation correctly handles list parameters by mapping each element through encode_param/1, and provides a safe pass-through for non-list params. This addresses the PR objective of preventing crashes when parameters aren't lists.


57-76: LGTM!

The encode_param/1 implementations are well-structured:

  • Temporal types correctly converted to ISO8601 strings via stdlib functions
  • Decimal converted to string representation
  • Booleans mapped to SQLite's integer convention (1/0)
  • :null atom support provides a useful alternative to nil
  • Pass-through catch-all handles primitives and already-compatible types

The clause ordering ensures specific patterns match before the catch-all.


78-80: LGTM!

The pass-through decode/3 is appropriate as documented—Native.ex already handles result normalisation.

TYPE_ENCODING_SUMMARY.md (1)

1-6: LGTM!

Comprehensive documentation that clearly explains the type encoding feature, its limitations, and workarounds. This will be valuable for developers integrating with Oban and similar libraries.

test/type_encoding_implementation_test.exs (6)

11-52: LGTM!

Good test setup with:

  • Inline TestRepo for isolation
  • User schema that matches the table structure
  • Proper cleanup via on_exit callback

54-148: LGTM!

Comprehensive boolean encoding tests covering:

  • Direct SQL with true/false parameters
  • WHERE clause comparisons
  • Ecto schema integration
  • Ecto.Query with pinned boolean values

150-216: LGTM!

UUID encoding tests appropriately validate that Ecto.UUID.generate() strings pass through the encoding pipeline correctly in various contexts.


218-262: LGTM!

Good coverage of :null atom encoding, verifying it produces SQL NULL values that work correctly with IS NULL and IS NOT NULL operators.


264-387: LGTM!

Thorough coverage of combined type scenarios and edge cases, including:

  • Multiple encoded types in single queries
  • Batch operations with mixed types
  • Boolean comparisons with != operator
  • UUID in aggregation queries
  • NULL handling with IS NULL/IS NOT NULL

1-2: Fix formatting to pass CI.

The CI pipeline is failing because this file doesn't pass mix format checks. Please run mix format to fix the formatting issues.

#!/bin/bash
# Check what formatting changes are needed
mix format --check-formatted test/type_encoding_implementation_test.exs 2>&1 || mix format --dry-run test/type_encoding_implementation_test.exs 2>&1 | head -50
⛔ Skipped due to learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For terminal test operations, use underscore variable names and assert error tuples with the pattern `assert {:error, %EctoLibSql.Error{}, _conn}`
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use JSON functions from `EctoLibSql.JSON` module for working with JSON/JSONB data instead of raw SQL strings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support
test/type_encoding_investigation_test.exs (3)

9-37: LGTM!

Good test setup with a generic table schema suitable for investigating various type encoding behaviours.


274-437: LGTM!

Excellent edge case coverage including:

  • Empty strings
  • i64 boundary values (max/min)
  • Float precision edge cases
  • Special characters, unicode, and whitespace
  • Binary data with null bytes and random bytes
  • Zero values across types

These tests provide good confidence in the encoding robustness.


439-575: LGTM!

Good coverage of:

  • Decimal encoding (including exponent notation and negative values)
  • Temporal type encoding with ISO8601 format verification via LIKE patterns
  • Mixed-type parameter handling in batch operations

Comment on lines 140 to 152
```
commit 7671d65
Author: Drew Robinson
Date: Tue Jan 13 2026
feat: Add comprehensive type encoding support and tests
- Implement boolean encoding (true→1, false→0)
- Implement :null atom encoding (:null→nil)
- Add 57 comprehensive tests
- Document type encoding in AGENTS.md
- Document nested structure limitation and workarounds
```
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

Add language specifier to fenced code block.

The git history code block is missing a language specifier, which triggers markdownlint MD040. While git isn't a standard language identifier, you can use text or plaintext to satisfy the linter.

📝 Proposed fix
-```
+```text
 commit 7671d65
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
commit 7671d65
Author: Drew Robinson
Date: Tue Jan 13 2026
feat: Add comprehensive type encoding support and tests
- Implement boolean encoding (true→1, false→0)
- Implement :null atom encoding (:null→nil)
- Add 57 comprehensive tests
- Document type encoding in AGENTS.md
- Document nested structure limitation and workarounds
```
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

140-140: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In @TYPE_ENCODING_SUMMARY.md around lines 140 - 152, The fenced code block
showing the git commit (the block starting with "commit 7671d65") lacks a
language specifier and triggers markdownlint MD040; update the opening fence for
that block in TYPE_ENCODING_SUMMARY.md to include a language such as "text" or
"plaintext" (e.g., change the opening ``` to ```text) so the linter is satisfied
while preserving the commit contents.

ocean added 7 commits January 13, 2026 14:57
- Add automatic JSON encoding for plain maps in EctoLibSql.Query.encode_param/1
  This allows raw maps to be passed to Ecto.Adapters.SQL.query! without pre-encoding

- Update test 'nested maps in parameters are encoded' to pass raw complex_data map
  instead of pre-encoding with Jason.encode! to verify adapter's automatic encoding

- Update test 'structs are not encoded as maps' to pass raw DateTime struct
  instead of pre-converting to ISO8601, and add assertions to verify proper encoding

- Remove redundant setup block in 'map parameter encoding' describe block
  The main setup (lines 103-108) already handles post/user cleanup

Fixes PR comments for improved test coverage of automatic type encoding
- Update 'plain maps are encoded to JSON before passing to NIF' test to pass
  the raw metadata map instead of pre-encoding with Jason.encode!

- This exercises the automatic JSON encoding in EctoLibSql.Query.encode_param/1

- Add assertion for nested object verification (decoded["nested"]["key"])

- Improves test coverage by ensuring no 'Unsupported argument type' error
  is raised when passing plain maps to raw SQL queries
…ations

- Enhanced the defensive catch-all clause in column_default/1 to log warnings
  when unexpected default types are encountered (e.g., empty maps from Oban)

- Logs include helpful context about common sources (Oban, third-party integrations)
  and clarify that no DEFAULT clause will be generated

- Maintains graceful fallback behavior while improving debugging visibility

- Tested with migration tests showing warnings for %{}, [], and unknown atoms
…mplementation

- Merged valuable tests from type_encoding_investigation_test.exs into
  type_encoding_implementation_test.exs

- Added new describe blocks for comprehensive edge case coverage:
  * string encoding edge cases (empty strings, special chars, unicode, whitespace)
  * binary encoding edge cases (null bytes, large data, mixed bytes)
  * numeric encoding edge cases (large integers, decimals, zero values)
  * temporal type encoding (DateTime, NaiveDateTime, Date, Time)

- Renamed nested TestTypes modules to be unique:
  * StringTestTypes, BinaryTestTypes, NumericTestTypes, TemporalTestTypes

- Removed type_encoding_investigation_test.exs (35 tests → consolidated into implementation)
- Now single comprehensive test file with 72 tests (37 integration + 35 type encoding)
The encode/3 function correctly converts boolean values to integers:
- true → 1
- false → 0

This is necessary because SQLite uses 0/1 for boolean values. The tests
were expecting the raw boolean values to pass through unchanged, which
was incorrect.

Fixed:
- test 'passes through boolean values unchanged' → now expects [1, 0]
- test 'handles mixed parameter types' → now expects 1 instead of true
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

🤖 Fix all issues with AI agents
In @.beads/.gitignore:
- Around line 35-38: This change touches repository housekeeping in
.beads/.gitignore by adding machine-specific patterns (.sync.lock and
sync_base.jsonl) which is unrelated to the Oban compatibility and
DateTime/Decimal encoding work; remove these lines from the current PR and
instead create a new branch/commit (or separate PR) that adds the .sync.lock and
sync_base.jsonl ignore entries, then update the current branch/PR to revert the
.beads/.gitignore edits so the PR contains only the Oban/encoding changes.
🧹 Nitpick comments (2)
lib/ecto_libsql/query.ex (1)

76-78: Consider graceful error handling for map encoding failures.

Jason.encode!/1 will raise Jason.EncodeError if the map contains unserializable values (PIDs, functions, references). While maps passed to database queries should typically be JSON-serializable, an encoding failure here could produce a confusing error message during query execution.

Consider wrapping with a more descriptive error, or documenting that maps must be JSON-serializable:

♻️ Optional: Add error context
     # Map encoding: plain maps (not structs) are encoded to JSON
     defp encode_param(value) when is_map(value) and not is_struct(value) do
-      Jason.encode!(value)
+      try do
+        Jason.encode!(value)
+      rescue
+        e in Jason.EncodeError ->
+          reraise ArgumentError,
+            "Failed to encode map parameter to JSON: #{Exception.message(e)}. " <>
+            "Map parameters must contain only JSON-serializable values.",
+            __STACKTRACE__
+      end
     end
test/type_encoding_implementation_test.exs (1)

409-418: Unused schema module.

StringTestTypes (and similarly BinaryTestTypes, NumericTestTypes, TemporalTestTypes in their respective describe blocks) defines an Ecto schema that is never used in the tests. The tests use raw SQL queries instead. Consider removing these unused modules to reduce confusion, or implementing Ecto.Repo-based tests that exercise the schema integration.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4682df7 and 5757a16.

📒 Files selected for processing (7)
  • .beads/.gitignore
  • .gitignore
  • lib/ecto/adapters/libsql/connection.ex
  • lib/ecto_libsql/query.ex
  • test/ecto_integration_test.exs
  • test/ecto_libsql_query_encoding_test.exs
  • test/type_encoding_implementation_test.exs
🚧 Files skipped from review as they are similar to previous changes (2)
  • .gitignore
  • test/ecto_libsql_query_encoding_test.exs
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Use British/Australian English for all code, comments, and documentation (except SQL keywords and compatibility requirements)

Files:

  • lib/ecto/adapters/libsql/connection.ex
  • test/ecto_integration_test.exs
  • lib/ecto_libsql/query.ex
  • test/type_encoding_implementation_test.exs
lib/ecto/adapters/libsql/connection.ex

📄 CodeRabbit inference engine (CLAUDE.md)

Update SQL generation in lib/ecto/adapters/libsql/connection.ex when adding SQLite function support

Files:

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

📄 CodeRabbit inference engine (CLAUDE.md)

lib/**/*.ex: Use proper transactions with timeout for database operations: Repo.transaction(fn -> ... end, timeout: 15_000) to avoid database locked errors
Ensure connections are closed in try/after blocks to prevent connection leaks
Use immediate transactions for write operations: begin(state, behavior: :immediate) for write-heavy workloads
Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Use cast/3 in changesets for automatic type conversion in Elixir

Files:

  • lib/ecto/adapters/libsql/connection.ex
  • lib/ecto_libsql/query.ex
test/**/*.{exs,ex}

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming: state for connection scope, trx_state for transaction scope, cursor for cursor scope, stmt_id for prepared statement ID scope
When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments
When an error operation returns state in tests that is NOT needed for subsequent operations, discard it with underscore
For terminal test operations, use underscore variable names and assert error tuples with the pattern assert {:error, %EctoLibSql.Error{}, _conn}

Files:

  • test/ecto_integration_test.exs
  • test/type_encoding_implementation_test.exs
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
  • lib/ecto_libsql/query.ex
  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
  • lib/ecto_libsql/query.ex
  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
  • test/ecto_integration_test.exs
  • lib/ecto_libsql/query.ex
  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Handle all database operations with case/2 or with/1 patterns to catch and log `{:error, reason}` tuples gracefully

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to priv/repo/migrations/*.exs : For SQLite migrations requiring column type changes, use table recreation pattern: create new table with desired schema, copy data with transformation, drop old table, rename new table, recreate indexes (SQLite doesn't support ALTER COLUMN; SQLite < 3.35.0 doesn't support DROP COLUMN)

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use generated columns with `generated: "expression"` option in migrations for computed values that should be automatically maintained

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `random_rowid: true` table option in migrations for security-sensitive tables to prevent ID enumeration attacks

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Create indexes in migrations for frequently queried columns (email, timestamps, foreign keys)

Applied to files:

  • lib/ecto/adapters/libsql/connection.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For terminal test operations, use underscore variable names and assert error tuples with the pattern `assert {:error, %EctoLibSql.Error{}, _conn}`

Applied to files:

  • test/ecto_integration_test.exs
  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments

Applied to files:

  • test/ecto_integration_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use Ecto changesets for all data validation and transformation in Phoenix/Elixir applications

Applied to files:

  • test/ecto_integration_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use JSON functions from `EctoLibSql.JSON` module for working with JSON/JSONB data instead of raw SQL strings

Applied to files:

  • lib/ecto_libsql/query.ex
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Add comprehensive test coverage including happy path, error cases, edge cases, transaction rollback scenarios, type conversions, and concurrent operations

Applied to files:

  • test/type_encoding_implementation_test.exs
🧬 Code graph analysis (2)
test/ecto_integration_test.exs (1)
lib/ecto/adapters/libsql/connection.ex (1)
  • all (601-632)
test/type_encoding_implementation_test.exs (2)
lib/ecto/adapters/libsql/connection.ex (2)
  • insert (658-679)
  • from (862-865)
lib/ecto_libsql/query.ex (1)
  • to_string (91-93)
⏰ 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: Elixir 1.18.0 / OTP 27.0 / macos-latest
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / ubuntu-latest
  • GitHub Check: Analyze (rust)
🔇 Additional comments (9)
lib/ecto/adapters/libsql/connection.ex (1)

425-437: Good defensive handling for unexpected default value types.

This catch-all clause gracefully handles edge cases from Oban or other third-party migrations. The warning log is helpful for debugging.

Minor improvement: Consider moving require Logger to the module level (near other aliases) for consistency, as require is typically placed at module scope. However, this works correctly as-is.

lib/ecto_libsql/query.ex (2)

41-53: Well-structured parameter encoding implementation.

The encode/3 function correctly handles the type conversions needed for Oban compatibility. The documentation comment clearly explains the supported conversions.


57-81: Type conversion implementations are correct.

The temporal type conversions, Decimal encoding, boolean-to-integer mapping, and :null handling are all implemented correctly and align with SQLite requirements. Based on learnings, these changes support proper type encoding for Oban compatibility.

test/ecto_integration_test.exs (1)

858-939: Comprehensive test coverage for map parameter encoding.

The tests effectively verify:

  1. Plain maps are JSON-encoded before NIF invocation
  2. Nested map structures are preserved through encoding
  3. Structs (DateTime) are handled separately via ISO8601 encoding

This directly validates the fixes for issue #57.

test/type_encoding_implementation_test.exs (5)

1-52: Well-structured test module setup.

The test configuration with async: false, dedicated test database, and proper cleanup is appropriate for integration testing with shared database state.


54-148: Thorough boolean encoding test coverage.

Tests cover boolean encoding in INSERT, WHERE, Ecto.Schema, and Ecto.Query contexts. The test patterns effectively validate true→1 and false→0 conversions.


150-216: UUID encoding tests are comprehensive.

Good coverage of UUID string handling in parameters, WHERE clauses, schema fields, and Ecto.Query integration.


218-270: :null atom encoding properly tested.

Tests correctly verify that :null atom is converted to nil (SQL NULL) and interacts properly with IS NULL/IS NOT NULL operators.


631-710: Temporal type encoding tests validate ISO8601 conversion.

The DateTime, NaiveDateTime, Date, and Time encoding tests verify the ISO8601 string output using LIKE pattern matching, which is appropriate for validating the format without being overly strict on timing.

ocean added 2 commits January 13, 2026 17:38
Replace Jason.encode!/1 with Jason.encode/1 to provide graceful error
handling and more descriptive error messages. Maps passed as query
parameters are encoded to JSON, but if they contain non-JSON-serializable
values (PIDs, functions, references, etc.), users now get a clear,
actionable error message.

Changes:
- Use Jason.encode/1 instead of Jason.encode! for better error handling
- Raise ArgumentError with descriptive message explaining:
  - What went wrong (contains non-JSON-serializable value)
  - What's allowed (strings, numbers, booleans, nil, lists, nested maps)
  - The actual error reason from Jason
  - The problematic map for debugging
- Updated comment to document JSON serialization requirements

This prevents confusing Jason.EncodeError from propagating up to the user.
The StringTestTypes, BinaryTestTypes, NumericTestTypes, and TemporalTestTypes
schema modules were defined but never used in their respective describe blocks.
All tests use raw SQL queries via SQL.query!/2 instead of Ecto.Repo operations.

Removing these schemas:
- Reduces test file clutter and confusion
- Clarifies that these tests verify parameter encoding, not Ecto schema integration
- Makes the file 50 lines shorter

If future tests need to exercise Ecto schema integration, they should be added
as separate test suites with proper Repo-based tests.
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 (3)
test/type_encoding_implementation_test.exs (3)

91-111: Consider using exact count assertions for better test precision.

These tests use assert count >= 1 when the exact count is predictable from the test setup. Weak assertions can mask data isolation issues or unintended side effects from other tests.

💡 Suggested improvement
     test "boolean true in WHERE clause" do
       SQL.query!(TestRepo, "DELETE FROM users")
       SQL.query!(TestRepo, "INSERT INTO users (name, active) VALUES (?, ?)", ["Alice", 1])
       SQL.query!(TestRepo, "INSERT INTO users (name, active) VALUES (?, ?)", ["Bob", 0])

       # Query with boolean parameter true (should match 1)
       result = SQL.query!(TestRepo, "SELECT COUNT(*) FROM users WHERE active = ?", [true])
       assert [[count]] = result.rows
-      assert count >= 1
+      assert count == 1
     end

     test "boolean false in WHERE clause" do
       SQL.query!(TestRepo, "DELETE FROM users")
       SQL.query!(TestRepo, "INSERT INTO users (name, active) VALUES (?, ?)", ["Alice", 1])
       SQL.query!(TestRepo, "INSERT INTO users (name, active) VALUES (?, ?)", ["Bob", 0])

       # Query with boolean parameter false (should match 0)
       result = SQL.query!(TestRepo, "SELECT COUNT(*) FROM users WHERE active = ?", [false])
       assert [[count]] = result.rows
-      assert count >= 1
+      assert count == 1
     end

495-515: Consider testing with larger binary data and consistent assertions.

The "large binary data" test uses only 125 bytes, which doesn't meaningfully test large data handling. SQLite BLOBs can handle megabytes. Additionally, lines 503-504 use a weaker size-only assertion compared to other binary tests that use pin matching for exact content verification.

💡 Suggested improvement
     test "large binary data" do
-      binary = :crypto.strong_rand_bytes(125)
+      # Test with 64KB to verify larger data handling
+      binary = :crypto.strong_rand_bytes(65_536)

       result = SQL.query!(TestRepo, "INSERT INTO test_types (blob_col) VALUES (?)", [binary])
       assert result.num_rows == 1

       result = SQL.query!(TestRepo, "SELECT blob_col FROM test_types ORDER BY id DESC LIMIT 1")
-      [[stored]] = result.rows
-      assert is_binary(stored)
-      assert byte_size(stored) == byte_size(binary)
+      assert [[^binary]] = result.rows
     end

618-672: Consider verifying exact ISO8601 format in temporal type assertions.

The temporal type tests use LIKE patterns ("202%", "____-__-__%") which only loosely verify that data was stored. To ensure the encoding produces correct ISO8601 strings, consider asserting the actual stored value matches the expected format.

💡 Example for DateTime test
     test "DateTime parameter encoding" do
       dt = DateTime.utc_now()

       result = SQL.query!(TestRepo, "INSERT INTO test_types (text_col) VALUES (?)", [dt])
       assert result.num_rows == 1

-      result =
-        SQL.query!(TestRepo, "SELECT COUNT(*) FROM test_types WHERE text_col LIKE ?", ["202%"])
-
-      assert [[count]] = result.rows
-      assert count >= 1
+      result = SQL.query!(TestRepo, "SELECT text_col FROM test_types ORDER BY id DESC LIMIT 1")
+      [[stored]] = result.rows
+      # Verify ISO8601 format was stored
+      assert stored == DateTime.to_iso8601(dt)
     end
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55990b7 and f393b70.

📒 Files selected for processing (2)
  • lib/ecto_libsql/query.ex
  • test/type_encoding_implementation_test.exs
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/ecto_libsql/query.ex
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Use British/Australian English for all code, comments, and documentation (except SQL keywords and compatibility requirements)

Files:

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

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming: state for connection scope, trx_state for transaction scope, cursor for cursor scope, stmt_id for prepared statement ID scope
When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments
When an error operation returns state in tests that is NOT needed for subsequent operations, discard it with underscore
For terminal test operations, use underscore variable names and assert error tuples with the pattern assert {:error, %EctoLibSql.Error{}, _conn}

Files:

  • test/type_encoding_implementation_test.exs
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Add comprehensive test coverage including happy path, error cases, edge cases, transaction rollback scenarios, type conversions, and concurrent operations

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For terminal test operations, use underscore variable names and assert error tuples with the pattern `assert {:error, %EctoLibSql.Error{}, _conn}`

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion

Applied to files:

  • test/type_encoding_implementation_test.exs
🧬 Code graph analysis (1)
test/type_encoding_implementation_test.exs (2)
lib/ecto/adapters/libsql/connection.ex (3)
  • insert (658-679)
  • from (862-865)
  • all (601-632)
lib/ecto_libsql/query.ex (1)
  • to_string (104-106)
⏰ 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: Analyze (rust)
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / macos-latest
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / ubuntu-latest
🔇 Additional comments (6)
test/type_encoding_implementation_test.exs (6)

1-52: LGTM - Well-structured test module setup.

The test module correctly uses async: false for shared database access, defines scoped TestRepo and User modules, and properly manages table creation and cleanup in setup_all. The on_exit callback ensures database files are cleaned up after all tests complete.


150-216: LGTM - UUID encoding tests are well-structured.

Good use of the pin operator (^uuid) for precise value matching in assertions. The tests comprehensively cover raw SQL and Ecto.Query integration paths.


218-270: LGTM - :null atom encoding tests cover the key scenarios.

These tests validate the critical :nullnilNULL encoding path that addresses the Oban compatibility issues mentioned in the PR objectives.


272-340: LGTM - Combined type encoding tests provide good integration coverage.

Testing multiple encoded types together in single queries and batch operations validates that the encoding implementation handles real-world usage patterns correctly.


408-467: LGTM - String encoding edge cases are well covered.

Excellent coverage of edge cases including empty strings, special characters (quotes, escapes), Unicode (CJK, Arabic, emoji), and whitespace variations. These are important for ensuring the adapter handles real-world string data correctly.


569-599: LGTM - Decimal parameter encoding tests align with PR objectives.

These tests verify the Decimal encoding implementation that was added to fix the "Unsupported argument type" errors when using Oban with ecto_libsql. Testing both positive and negative Decimal values ensures proper string conversion.

… type coercion

New test suites added to type_encoding_implementation_test.exs:

1. Float/REAL field encoding (8 tests)
   - Positive and negative floats
   - Very small and very large floats
   - Float zero
   - Float comparisons in WHERE clauses
   - Floats in aggregate functions (SUM, AVG, COUNT)

2. NULL/nil edge cases (9 tests)
   - NULL in SUM aggregate (ignores NULLs)
   - NULL in AVG aggregate (ignores NULLs)
   - COUNT with NULL values (COUNT(*) vs COUNT(column))
   - COALESCE with NULL values
   - NULL in compound WHERE clauses
   - NULL in CASE expressions
   - NULL in ORDER BY (sorts first in SQLite)
   - NULL with DISTINCT

3. Type coercion edge cases (8 tests)
   - String that looks like number in text column
   - Empty string vs NULL distinction
   - Zero vs NULL in numeric columns
   - Type affinity (integer in text column)
   - Float precision in arithmetic
   - Division by zero handling (returns NULL)
   - String vs numeric comparison behavior

Previous coverage:
   - UUID/binary_id fields (already comprehensive)
   - Date-only and Time-only fields (already tested)
   - Boolean, Decimal, DateTime, String, Binary types (already tested)

Total new tests: 25
Total tests in file: 57
All tests pass.
ocean added 2 commits January 13, 2026 17:53
Closed issues:
- el-v3v (Reduce redundant parameter binding tests): Analyzed overlap between unit and integration tests; accepted minimal redundancy as acceptable technical debt
- el-fpi (Fix binary data round-trip for single null byte): Confirmed bug exists via NIF layer; documented for future implementation

Test suite: 706 tests pass, 0 failures
- Lines 91-111: Replace weak count >= 1 assertions with exact count == 1
  Weak assertions can mask data isolation issues or unintended side effects
  from other tests. These tests have predictable counts from setup.

- Lines 495-515: Increase large binary test from 125 bytes to 1MB
  125 bytes doesn't meaningfully test large data handling. Updated to use
  1MB and consistent pin matching (^binary) for exact content verification.

- Lines 618-672: Replace LIKE patterns with exact ISO8601 format assertions
  Tests now verify stored values match expected format exactly instead of
  using loose patterns like '202%' or '____-__-__%'. This ensures encoding
  produces correct ISO8601 strings for DateTime, NaiveDateTime, Date, Time.
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 (6)
test/type_encoding_implementation_test.exs (6)

143-148: Consider tightening the assertion for better test precision.

Since line 134 deletes all users and lines 137-138 insert exactly 2 users (one active, one inactive), the assertion could be more precise:

-      assert length(active_users) >= 1
-      assert Enum.all?(active_users, & &1.active)
+      assert length(active_users) == 1
+      assert hd(active_users).name == "Dave"

The current >= 1 assertion would pass even if the encoding were broken and returned both users.


237-250: Test name is misleading - doesn't test :null encoding in query parameters.

This test inserts nil directly (line 241) and uses static IS NULL SQL. It doesn't actually test :null atom encoding in query parameters as the name suggests. Consider either:

  1. Renaming to clarify what it actually tests:
-    test "querying with :null atom for IS NULL" do
+    test "nil inserted value can be queried with IS NULL" do
  1. Or modifying to actually test :null in a parameter context (though IS NULL doesn't use parameters).

317-321: Loose assertion could mask encoding failures.

After inserting exactly 3 rows (lines 305-315), asserting count >= 3 would still pass if previous test data leaked. Since line 300 deletes all users, consider:

-      assert count >= 3
+      assert count == 3

560-569: Zero value test could be more precise.

The test inserts zero values but only verifies row count, not the actual stored values:

     test "zero values" do
       SQL.query!(TestRepo, "INSERT INTO test_types (int_col) VALUES (?)", [0])
       SQL.query!(TestRepo, "INSERT INTO test_types (real_col) VALUES (?)", [0.0])

       result =
-        SQL.query!(TestRepo, "SELECT int_col, real_col FROM test_types ORDER BY id DESC LIMIT 2")
-
-      rows = result.rows
-      assert length(rows) == 2
+        SQL.query!(TestRepo, "SELECT int_col FROM test_types WHERE int_col = ?", [0])
+      assert [[0]] = result.rows
+
+      result =
+        SQL.query!(TestRepo, "SELECT real_col FROM test_types WHERE real_col = ?", [0.0])
+      assert [[0.0]] = result.rows
     end

966-981: Assertion provides minimal verification.

The test comment acknowledges floating-point precision issues, but assert is_list(result.rows) provides almost no verification of behaviour. Consider asserting the row count or checking if any rows were returned:

-      # Due to floating point precision, this might return 0 or 1 rows
-      # depending on exact arithmetic
-      assert is_list(result.rows)
+      # Due to floating point precision, this might return 0 or 1 rows
+      assert length(result.rows) in [0, 1]

991-1002: Test assertion doesn't verify string comparison behaviour.

The test demonstrates an important SQLite behaviour (lexicographic vs numeric comparison), but assert is_integer(count) doesn't verify the actual comparison semantics. Consider documenting the expected count:

       result =
         SQL.query!(TestRepo, "SELECT COUNT(*) FROM test_types WHERE text_col < ?", ["50"])

       assert [[count]] = result.rows
-      # Result depends on string vs numeric comparison
-      assert is_integer(count)
+      # Lexicographic: "100" < "50" (true), "20" < "50" (true) → 2 matches
+      assert count == 2
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f393b70 and 2c99e60.

📒 Files selected for processing (2)
  • .beads/last-touched
  • test/type_encoding_implementation_test.exs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Use British/Australian English for all code, comments, and documentation (except SQL keywords and compatibility requirements)

Files:

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

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming: state for connection scope, trx_state for transaction scope, cursor for cursor scope, stmt_id for prepared statement ID scope
When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments
When an error operation returns state in tests that is NOT needed for subsequent operations, discard it with underscore
For terminal test operations, use underscore variable names and assert error tuples with the pattern assert {:error, %EctoLibSql.Error{}, _conn}

Files:

  • test/type_encoding_implementation_test.exs
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Add comprehensive test coverage including happy path, error cases, edge cases, transaction rollback scenarios, type conversions, and concurrent operations

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For terminal test operations, use underscore variable names and assert error tuples with the pattern `assert {:error, %EctoLibSql.Error{}, _conn}`

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to priv/repo/migrations/*.exs : For SQLite migrations requiring column type changes, use table recreation pattern: create new table with desired schema, copy data with transformation, drop old table, rename new table, recreate indexes (SQLite doesn't support ALTER COLUMN; SQLite < 3.35.0 doesn't support DROP COLUMN)

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion

Applied to files:

  • test/type_encoding_implementation_test.exs
🧬 Code graph analysis (1)
test/type_encoding_implementation_test.exs (2)
lib/ecto/adapters/libsql/connection.ex (3)
  • insert (658-679)
  • from (862-865)
  • all (601-632)
lib/ecto_libsql/query.ex (1)
  • to_string (104-106)
⏰ 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). (4)
  • GitHub Check: Rust Fuzz Testing
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / ubuntu-latest
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / macos-latest
  • GitHub Check: Analyze (rust)
🔇 Additional comments (9)
.beads/last-touched (1)

1-1: No concerns with this metadata file update.

This appears to be an internal tracking file (updated from el-6r5 to el-1p2). No code logic to review.

test/type_encoding_implementation_test.exs (8)

1-52: Well-structured test module with comprehensive coverage.

The test setup is appropriate with async: false for database isolation and proper cleanup via EctoLibSql.TestHelpers.cleanup_db_files/1. The setup_all correctly initialises the repository and creates the users table for the main test scenarios.


152-218: LGTM!

The UUID encoding tests are well-structured with proper pin matching (^uuid) to verify exact value preservation through the encoding/decoding cycle.


410-469: LGTM!

Excellent coverage of string edge cases including empty strings, special characters (quotes, backslashes), Unicode (CJK, Arabic, emojis), and whitespace variants (newlines, tabs, CRLF).


497-507: LGTM!

Good use of 1MB binary test to verify large data handling. Pin matching (^binary) ensures exact byte-for-byte integrity verification rather than just size comparison.


604-671: LGTM!

Excellent temporal type encoding tests that directly address the PR objective of fixing Oban compatibility. The exact ISO8601 format verification (instead of LIKE patterns) provides strong assurance that DateTime, NaiveDateTime, Date, and Time types are correctly encoded.


756-774: LGTM!

Well-designed aggregate function tests with appropriate floating-point tolerance comparisons. The test correctly verifies SUM, AVG, and COUNT behaviour with float values.


777-901: LGTM!

Comprehensive NULL handling tests covering aggregates, COALESCE, CASE expressions, ORDER BY, and DISTINCT. The documentation of SQLite-specific NULL sorting behaviour (line 887) is helpful.


1-1004: Comprehensive test coverage for type encoding implementation.

This test file provides thorough coverage for the parameter encoding feature required for Oban compatibility. The tests appropriately cover:

  • Boolean encoding (true/false → 1/0)
  • Temporal types (DateTime, NaiveDateTime, Date, Time → ISO8601)
  • Decimal encoding
  • :null atom handling
  • Edge cases for strings, binaries, numerics, and NULL handling

The test structure with per-describe setup/teardown ensures proper isolation between test groups.

ocean added 2 commits January 13, 2026 18:51
- Tighten assertion on active_users query to verify exact count and user identity
- Rename misleading test name to clarify it tests nil insertion, not :null encoding
- Change loose >= assertions to exact == assertions after DELETE operations
- Improve zero value test to verify actual stored values via WHERE clause
- Replace generic is_list assertion with specific length check for float precision test
- Document and verify expected behavior for string comparison lexicographic order
- Fix float zero pattern matching warning by checking +0.0 vs -0.0 representation

All tests pass with no warnings.
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

🤖 Fix all issues with AI agents
In @test/type_encoding_implementation_test.exs:
- Around line 560-574: In the "zero values" test, the blank line between the
second SQL.query! call and the pattern match causes mix format to fail; remove
the empty line so the assignment and immediate pattern match are adjacent (i.e.,
keep the SQL.query!(TestRepo, "SELECT real_col FROM test_types WHERE real_col =
?", [0.0]) line immediately followed by `[[stored_real]] = result.rows`),
preserving the existing variable names (`result`, `stored_real`) and test
structure.
🧹 Nitpick comments (3)
test/type_encoding_implementation_test.exs (3)

252-271: Consider tightening assertions to exact counts.

Given the DELETE FROM users at line 253 followed by two known inserts, the counts should be deterministic. Using >= 1 is weaker than necessary.

Suggested fix
       # Count non-NULL values
       result = SQL.query!(TestRepo, "SELECT COUNT(*) FROM users WHERE uuid IS NOT NULL")
       assert [[count]] = result.rows
-      assert count >= 1
+      assert count == 1

       # Count NULL values
       result = SQL.query!(TestRepo, "SELECT COUNT(*) FROM users WHERE uuid IS NULL")
       assert [[count]] = result.rows
-      assert count >= 1
+      assert count == 1

335-341: Consider exact assertion.

After clearing the table and inserting two users, querying with active == true and uuid == uuid should return exactly 1 user.

Suggested fix
       users =
         from(u in User, where: u.active == ^true and u.uuid == ^uuid)
         |> TestRepo.all()

-      assert length(users) >= 1
+      assert length(users) == 1
       assert Enum.all?(users, fn u -> u.active == true and u.uuid == uuid end)

344-408: Assertions could be tightened throughout this describe block.

Similar to earlier sections, the >= 1 and >= 2 assertions (lines 354, 359, 364, 385, 401, 406) could be exact since the test data is deterministic after DELETE FROM users.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c99e60 and b4d6dff.

📒 Files selected for processing (1)
  • test/type_encoding_implementation_test.exs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Use British/Australian English for all code, comments, and documentation (except SQL keywords and compatibility requirements)

Files:

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

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming: state for connection scope, trx_state for transaction scope, cursor for cursor scope, stmt_id for prepared statement ID scope
When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments
When an error operation returns state in tests that is NOT needed for subsequent operations, discard it with underscore
For terminal test operations, use underscore variable names and assert error tuples with the pattern assert {:error, %EctoLibSql.Error{}, _conn}

Files:

  • test/type_encoding_implementation_test.exs
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use JSON functions from `EctoLibSql.JSON` module for working with JSON/JSONB data instead of raw SQL strings
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For terminal test operations, use underscore variable names and assert error tuples with the pattern `assert {:error, %EctoLibSql.Error{}, _conn}`

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Add comprehensive test coverage including happy path, error cases, edge cases, transaction rollback scenarios, type conversions, and concurrent operations

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to priv/repo/migrations/*.exs : For SQLite migrations requiring column type changes, use table recreation pattern: create new table with desired schema, copy data with transformation, drop old table, rename new table, recreate indexes (SQLite doesn't support ALTER COLUMN; SQLite < 3.35.0 doesn't support DROP COLUMN)

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion

Applied to files:

  • test/type_encoding_implementation_test.exs
🪛 GitHub Actions: CI
test/type_encoding_implementation_test.exs

[error] 564-571: Mix format check failed. The following file is not formatted: test/type_encoding_implementation_test.exs. Run 'mix format' (or 'mix format --check-formatted' after formatting) to fix.

⏰ 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). (1)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (8)
test/type_encoding_implementation_test.exs (8)

1-52: LGTM!

Module structure is well-organised with a nested TestRepo and User schema. The setup_all properly creates the test table and schedules cleanup via the test helper.


54-150: LGTM!

Boolean encoding tests are comprehensive, covering both raw SQL and Ecto.Query usage with exact assertions.


152-218: LGTM!

UUID encoding tests properly verify string pass-through with pin matching for exact value verification.


410-518: LGTM!

Comprehensive coverage of string and binary edge cases including empty strings, special characters, unicode, and large binary data with proper pin matching for integrity verification.


609-676: LGTM!

Temporal type encoding tests properly verify exact ISO8601 format output for DateTime, NaiveDateTime, Date, and Time types.


678-780: LGTM!

Float encoding tests appropriately use tolerance-based comparisons for floating point values and include good coverage of aggregate functions.


782-906: LGTM!

Excellent coverage of NULL/nil edge cases including aggregate behaviour, COALESCE, CASE expressions, and SQLite-specific NULL ordering semantics.


908-1009: LGTM!

Thorough coverage of type coercion edge cases including SQLite's type affinity behaviour, division by zero handling, and float precision considerations.

Comment on lines 560 to 574
test "zero values" do
SQL.query!(TestRepo, "INSERT INTO test_types (int_col) VALUES (?)", [0])
SQL.query!(TestRepo, "INSERT INTO test_types (real_col) VALUES (?)", [0.0])

result =
SQL.query!(TestRepo, "SELECT int_col FROM test_types WHERE int_col = ?", [0])
assert [[0]] = result.rows

result =
SQL.query!(TestRepo, "SELECT real_col FROM test_types WHERE real_col = ?", [0.0])

[[stored_real]] = result.rows
# Float comparison: allow for +0.0 vs -0.0 representation
assert stored_real == +0.0 or stored_real == -0.0
end
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

Fix formatting issue flagged by CI pipeline.

The blank line at line 570 between the query and the pattern match causes the mix format check to fail.

Suggested fix
       result =
         SQL.query!(TestRepo, "SELECT real_col FROM test_types WHERE real_col = ?", [0.0])
-      
       [[stored_real]] = result.rows
       # Float comparison: allow for +0.0 vs -0.0 representation
       assert stored_real == +0.0 or stored_real == -0.0
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test "zero values" do
SQL.query!(TestRepo, "INSERT INTO test_types (int_col) VALUES (?)", [0])
SQL.query!(TestRepo, "INSERT INTO test_types (real_col) VALUES (?)", [0.0])
result =
SQL.query!(TestRepo, "SELECT int_col FROM test_types WHERE int_col = ?", [0])
assert [[0]] = result.rows
result =
SQL.query!(TestRepo, "SELECT real_col FROM test_types WHERE real_col = ?", [0.0])
[[stored_real]] = result.rows
# Float comparison: allow for +0.0 vs -0.0 representation
assert stored_real == +0.0 or stored_real == -0.0
end
test "zero values" do
SQL.query!(TestRepo, "INSERT INTO test_types (int_col) VALUES (?)", [0])
SQL.query!(TestRepo, "INSERT INTO test_types (real_col) VALUES (?)", [0.0])
result =
SQL.query!(TestRepo, "SELECT int_col FROM test_types WHERE int_col = ?", [0])
assert [[0]] = result.rows
result =
SQL.query!(TestRepo, "SELECT real_col FROM test_types WHERE real_col = ?", [0.0])
[[stored_real]] = result.rows
# Float comparison: allow for +0.0 vs -0.0 representation
assert stored_real == +0.0 or stored_real == -0.0
end
🧰 Tools
🪛 GitHub Actions: CI

[error] 564-571: Mix format check failed. The following file is not formatted: test/type_encoding_implementation_test.exs. Run 'mix format' (or 'mix format --check-formatted' after formatting) to fix.

🤖 Prompt for AI Agents
In @test/type_encoding_implementation_test.exs around lines 560 - 574, In the
"zero values" test, the blank line between the second SQL.query! call and the
pattern match causes mix format to fail; remove the empty line so the assignment
and immediate pattern match are adjacent (i.e., keep the SQL.query!(TestRepo,
"SELECT real_col FROM test_types WHERE real_col = ?", [0.0]) line immediately
followed by `[[stored_real]] = result.rows`), preserving the existing variable
names (`result`, `stored_real`) and test structure.

… deterministic counts

- Replace >= assertions with exact == counts (lines 252-271)
- Change 'at least 1' to exactly 1 in combined type encoding test (line 339)
- Use exact counts throughout edge cases and error conditions describe block
  - Line 354: exactly 1 active user (was >= 1)
  - Line 359: exactly 1 inactive user (was >= 1)
  - Line 364: exactly 1 with NOT (was >= 1)
  - Line 385: exactly 2 matching UUID (was >= 2)
  - Line 401: exactly 1 NULL value (was >= 1)
  - Line 406: exactly 1 non-NULL value (was >= 1)

Since tests perform DELETE FROM users at start and know exact INSERT count,
assertions can be deterministic rather than loose comparisons.
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

🤖 Fix all issues with AI agents
In @test/type_encoding_implementation_test.exs:
- Around line 750-760: The test "float in WHERE clause comparison" currently
asserts a non-deterministic lower bound (assert count >= 2); change this to an
exact equality assertion (assert count == 2) since the inserted values 1.5 and
2.7 are the only rows > 1.0; update the assertion in that test (the line
referencing count) accordingly to assert exact count == 2.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4d6dff and 7d47fd8.

📒 Files selected for processing (1)
  • test/type_encoding_implementation_test.exs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Use British/Australian English for all code, comments, and documentation (except SQL keywords and compatibility requirements)

Files:

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

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming: state for connection scope, trx_state for transaction scope, cursor for cursor scope, stmt_id for prepared statement ID scope
When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments
When an error operation returns state in tests that is NOT needed for subsequent operations, discard it with underscore
For terminal test operations, use underscore variable names and assert error tuples with the pattern assert {:error, %EctoLibSql.Error{}, _conn}

Files:

  • test/type_encoding_implementation_test.exs
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use JSON functions from `EctoLibSql.JSON` module for working with JSON/JSONB data instead of raw SQL strings
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For terminal test operations, use underscore variable names and assert error tuples with the pattern `assert {:error, %EctoLibSql.Error{}, _conn}`

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Add comprehensive test coverage including happy path, error cases, edge cases, transaction rollback scenarios, type conversions, and concurrent operations

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Run formatters before committing: `mix format && cd native/ecto_libsql && cargo fmt`

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to priv/repo/migrations/*.exs : For SQLite migrations requiring column type changes, use table recreation pattern: create new table with desired schema, copy data with transformation, drop old table, rename new table, recreate indexes (SQLite doesn't support ALTER COLUMN; SQLite < 3.35.0 doesn't support DROP COLUMN)

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For state threading in tests, use consistent variable naming: `state` for connection scope, `trx_state` for transaction scope, `cursor` for cursor scope, `stmt_id` for prepared statement ID scope

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion

Applied to files:

  • test/type_encoding_implementation_test.exs
🧬 Code graph analysis (1)
test/type_encoding_implementation_test.exs (2)
lib/ecto/adapters/libsql/connection.ex (3)
  • insert (658-679)
  • from (862-865)
  • all (601-632)
lib/ecto_libsql/query.ex (1)
  • to_string (104-106)
⏰ 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: Elixir 1.18.0 / OTP 27.0 / macos-latest
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / ubuntu-latest
  • GitHub Check: Analyze (rust)
🔇 Additional comments (12)
test/type_encoding_implementation_test.exs (12)

1-52: LGTM - Module structure and setup are well-organised.

The test module correctly uses async: false for shared database state, defines inline test schemas, and properly registers cleanup via on_exit. The setup pattern is appropriate for integration-style tests.


54-150: LGTM - Boolean encoding tests are thorough.

Good coverage of boolean encoding including raw SQL queries, WHERE clause matching, Ecto schema inserts, and Ecto.Query integration. Assertions correctly use exact equality checks.


152-218: LGTM - UUID encoding tests are well-structured.

Tests correctly verify UUID string storage, retrieval, and querying. Good use of pin matching (^uuid) for exact value verification.


220-272: LGTM - :null atom encoding tests verify the expected behaviour.

Tests correctly verify that the :null atom is converted to nil (SQL NULL) and can be queried with IS NULL operators.


274-342: LGTM - Combined type encoding tests provide good coverage.

Tests correctly verify that multiple encoded types (boolean, UUID, :null) work together in single queries, batch operations, and Ecto queries.


344-408: LGTM - Edge cases tests are well-designed.

Good coverage of boolean comparisons including !=, UUID aggregation queries, and NULL/NOT NULL operator combinations.


410-469: LGTM - String encoding edge cases are comprehensive.

Excellent coverage including empty strings, quotes/escapes, Unicode characters (CJK, Arabic, emoji), and various whitespace characters.


471-518: LGTM - Binary encoding edge cases test data integrity well.

Good coverage including null bytes, large binary data (1MB), and random byte sequences. Pin matching correctly verifies exact data round-trip integrity.


520-608: LGTM - Numeric encoding edge cases cover important boundaries.

Excellent coverage of int64 boundaries (max/min values), zero handling for both integers and floats, and Decimal-to-string encoding verification.


610-677: LGTM - Temporal type encoding tests verify ISO8601 conversion correctly.

Tests align well with the PR objectives, verifying that DateTime, NaiveDateTime, Date, and Time parameters are encoded to ISO8601 format. Good use of exact equality assertions rather than pattern matching.


783-907: LGTM - NULL/nil edge cases provide comprehensive coverage.

Excellent tests for SQL NULL semantics including aggregate behaviour, COALESCE, compound WHERE clauses, CASE expressions, ORDER BY, and DISTINCT. All assertions are deterministic and exact.


909-1009: LGTM - Type coercion edge cases correctly test SQLite-specific behaviour.

Good coverage of SQLite's type affinity, including appropriate flexibility in assertions (e.g., line 969 allows for either integer or string storage). The floating-point precision test (line 986) correctly acknowledges non-deterministic behaviour with a documented comment.

ocean added 2 commits January 13, 2026 21:27
- Replace pipe chains with direct function calls (lines 145, 211, 337)
- Convert Enum.map pipe to direct function call (line 309)
- Use underscored number instead of scientific notation (line 725)

All 3 refactoring opportunities and 1 code readability issue resolved.
57 tests pass with no credo violations.
In 'float in WHERE clause comparison' test (line 754):
- Insert values: 1.5, 2.7, 0.8
- Query: real_col > 1.0
- Result: exactly 2 rows match (1.5 and 2.7)
- Change assertion from count >= 2 to count == 2 for determinism

57 tests pass, zero credo violations.
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 (3)
test/type_encoding_implementation_test.exs (3)

405-422: Consider a more defensive table creation pattern.

The current pattern uses CREATE TABLE IF NOT EXISTS, which works correctly when on_exit runs. However, if a test crashes or is interrupted, the stale table may persist with an incompatible schema for subsequent describe blocks that define test_types with different columns.

A more resilient approach would ensure a fresh table regardless of prior state:

♻️ Suggested improvement
 setup do
+  SQL.query!(TestRepo, "DROP TABLE IF EXISTS test_types")
   SQL.query!(TestRepo, """
-  CREATE TABLE IF NOT EXISTS test_types (
+  CREATE TABLE test_types (
     id INTEGER PRIMARY KEY AUTOINCREMENT,
     text_col TEXT,
     blob_col BLOB,
     int_col INTEGER,
     real_col REAL
   )
   """)

   on_exit(fn ->
     SQL.query!(TestRepo, "DROP TABLE IF EXISTS test_types")
   end)

   :ok
 end

141-141: Consider hoisting import Ecto.Query to module level.

The import is repeated inside multiple tests (lines 141, 209, 330). Moving it to the module level would reduce duplication and improve readability.

♻️ Suggested refactor
 defmodule EctoLibSql.TypeEncodingImplementationTest do
   use ExUnit.Case, async: false

   # Tests for the type encoding implementation:
   # - Boolean encoding (true/false → 1/0)
   # - UUID encoding (binary → string if needed)
   # - :null atom encoding (:null → nil)

   alias Ecto.Adapters.SQL
+  import Ecto.Query

Then remove the import Ecto.Query lines from individual tests.


567-569: Redundant zero comparison.

In Elixir, +0.0 == -0.0 evaluates to true, so the or clause is unnecessary. A simple assert stored_real == 0.0 would suffice.

♻️ Simplified assertion
-      # Float comparison: allow for +0.0 vs -0.0 representation
-      assert stored_real == +0.0 or stored_real == -0.0
+      assert stored_real == 0.0
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d47fd8 and bf0bb24.

📒 Files selected for processing (1)
  • test/type_encoding_implementation_test.exs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Use British/Australian English for all code, comments, and documentation (except SQL keywords and compatibility requirements)

Files:

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

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming: state for connection scope, trx_state for transaction scope, cursor for cursor scope, stmt_id for prepared statement ID scope
When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments
When an error operation returns state in tests that is NOT needed for subsequent operations, discard it with underscore
For terminal test operations, use underscore variable names and assert error tuples with the pattern assert {:error, %EctoLibSql.Error{}, _conn}

Files:

  • test/type_encoding_implementation_test.exs
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use JSON functions from `EctoLibSql.JSON` module for working with JSON/JSONB data instead of raw SQL strings
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For terminal test operations, use underscore variable names and assert error tuples with the pattern `assert {:error, %EctoLibSql.Error{}, _conn}`

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Run formatters before committing: `mix format && cd native/ecto_libsql && cargo fmt`

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to priv/repo/migrations/*.exs : For SQLite migrations requiring column type changes, use table recreation pattern: create new table with desired schema, copy data with transformation, drop old table, rename new table, recreate indexes (SQLite doesn't support ALTER COLUMN; SQLite < 3.35.0 doesn't support DROP COLUMN)

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For state threading in tests, use consistent variable naming: `state` for connection scope, `trx_state` for transaction scope, `cursor` for cursor scope, `stmt_id` for prepared statement ID scope

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Add comprehensive test coverage including happy path, error cases, edge cases, transaction rollback scenarios, type conversions, and concurrent operations

Applied to files:

  • test/type_encoding_implementation_test.exs
⏰ 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: Elixir 1.18.0 / OTP 27.0 / ubuntu-latest
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / macos-latest
  • GitHub Check: Analyze (rust)
🔇 Additional comments (9)
test/type_encoding_implementation_test.exs (9)

1-52: LGTM - Well-structured test module setup.

The module setup correctly uses async: false for database tests, defines an appropriate test schema, and implements proper cleanup via on_exit. The table structure aligns with the User schema fields.


54-148: Comprehensive boolean encoding test coverage.

Tests correctly verify that true encodes to 1 and false to 0, covering raw SQL, Ecto schema integration, and Ecto.Query usage. Good isolation with explicit DELETE FROM users at the start of each test.


150-270: LGTM - UUID and :null encoding tests are thorough.

UUID tests verify correct string storage and retrieval, whilst :null atom tests confirm proper conversion to nil and correct IS NULL query behaviour.


605-672: Excellent temporal type encoding coverage.

Tests correctly verify that DateTime, NaiveDateTime, Date, and Time are encoded to their ISO8601 string representations. The exact string comparison (e.g., assert stored == expected_iso8601) properly validates the encoding behaviour described in the PR objectives.


572-602: LGTM - Decimal encoding tests verify string conversion.

Tests correctly validate that Decimal values are converted to their string representation, covering both positive and negative cases as required by the PR objectives.


482-512: LGTM - Thorough binary encoding tests.

Good coverage of edge cases including null bytes, large binaries (1MB), and random byte content. The use of pin matching (^binary) correctly verifies data integrity rather than just size.


778-902: Comprehensive NULL handling test coverage.

Excellent set of tests covering SQLite NULL semantics including aggregate functions, COALESCE, compound WHERE clauses, CASE expressions, ORDER BY behaviour, and DISTINCT. These tests will help prevent regressions in NULL value handling.


904-1004: LGTM - Type coercion edge cases well documented.

These tests effectively document SQLite-specific behaviours including type affinity, division by zero returning NULL, and string vs numeric comparison semantics. The flexible assertions (e.g., line 964, 981) appropriately handle SQLite's dynamic typing.


674-776: LGTM - Solid floating point encoding tests.

Good coverage of float edge cases with appropriate tolerance comparisons (< 0.00001). The aggregate function tests (SUM, AVG) verify correct handling in arithmetic contexts.

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 (3)
test/type_encoding_implementation_test.exs (3)

54-148: Comprehensive boolean encoding coverage.

The tests thoroughly cover boolean encoding scenarios including:

  • true1 and false0 conversion
  • WHERE clause comparisons with boolean parameters
  • Ecto schema integration with boolean fields
  • Ecto.Query with boolean parameters

Minor suggestion: the import Ecto.Query at line 141 could be moved to the module level to avoid repetition (also appears at lines 209, 330).


405-422: Consider using unique table names or explicit DROP before CREATE.

Seven describe blocks create test_types with different schemas using CREATE TABLE IF NOT EXISTS. If a previous test run failed before on_exit cleanup, the table may exist with an incompatible schema, causing subsequent test failures.

Consider either:

  1. Using unique table names per describe block (e.g., test_types_string, test_types_binary)
  2. Adding DROP TABLE IF EXISTS test_types before the CREATE in each setup
Suggested fix for setup blocks
  setup do
+   SQL.query!(TestRepo, "DROP TABLE IF EXISTS test_types")
    SQL.query!(TestRepo, """
-   CREATE TABLE IF NOT EXISTS test_types (
+   CREATE TABLE test_types (
      ...
    )
    """)

Also applies to: 466-480, 516-531, 605-619, 675-688, 779-794, 905-920


967-982: Floating point precision test assertion is quite loose.

The assertion assert length(result.rows) in [0, 1] accepts both outcomes, which means this test will always pass regardless of the actual behaviour. While the comment explains the floating-point precision uncertainty, consider either:

  1. Making the test deterministic by using a threshold that guarantees a specific outcome
  2. Documenting what the expected behaviour actually is for this adapter
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf0bb24 and 0ffd576.

📒 Files selected for processing (1)
  • test/type_encoding_implementation_test.exs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ex,exs,rs,md}

📄 CodeRabbit inference engine (CLAUDE.md)

Use British/Australian English for all code, comments, and documentation (except SQL keywords and compatibility requirements)

Files:

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

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming: state for connection scope, trx_state for transaction scope, cursor for cursor scope, stmt_id for prepared statement ID scope
When an error operation returns updated state in tests that IS needed for subsequent operations, rebind the state variable and add clarifying comments
When an error operation returns state in tests that is NOT needed for subsequent operations, discard it with underscore
For terminal test operations, use underscore variable names and assert error tuples with the pattern assert {:error, %EctoLibSql.Error{}, _conn}

Files:

  • test/type_encoding_implementation_test.exs
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Use JSON functions from `EctoLibSql.JSON` module for working with JSON/JSONB data instead of raw SQL strings
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql.ex : Update type loaders and dumpers in `lib/ecto/adapters/libsql.ex` when fixing type conversion issues

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Verify schema types match database columns and check custom types have loaders/dumpers to fix type conversion errors

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Add comprehensive test coverage including happy path, error cases, edge cases, transaction rollback scenarios, type conversions, and concurrent operations

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/**/*.ex : Use `cast/3` in changesets for automatic type conversion in Elixir

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For terminal test operations, use underscore variable names and assert error tuples with the pattern `assert {:error, %EctoLibSql.Error{}, _conn}`

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to lib/ecto/adapters/libsql/connection.ex : Update SQL generation in `lib/ecto/adapters/libsql/connection.ex` when adding SQLite function support

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to priv/repo/migrations/*.exs : For SQLite migrations requiring column type changes, use table recreation pattern: create new table with desired schema, copy data with transformation, drop old table, rename new table, recreate indexes (SQLite doesn't support ALTER COLUMN; SQLite < 3.35.0 doesn't support DROP COLUMN)

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Run formatters before committing: `mix format && cd native/ecto_libsql && cargo fmt`

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:10.435Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T07:35:10.435Z
Learning: Applies to test/**/*.{exs,ex} : For state threading in tests, use consistent variable naming: `state` for connection scope, `trx_state` for transaction scope, `cursor` for cursor scope, `stmt_id` for prepared statement ID scope

Applied to files:

  • test/type_encoding_implementation_test.exs
📚 Learning: 2026-01-12T07:35:34.542Z
Learnt from: CR
Repo: ocean/ecto_libsql PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T07:35:34.542Z
Learning: Applies to priv/repo/migrations/*.exs : Use `STRICT` table option in migrations for type safety and to prevent accidental type coercion

Applied to files:

  • test/type_encoding_implementation_test.exs
⏰ 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). (2)
  • GitHub Check: Elixir 1.18.0 / OTP 27.0 / macos-latest
  • GitHub Check: Analyze (rust)
🔇 Additional comments (8)
test/type_encoding_implementation_test.exs (8)

1-52: LGTM: Well-structured test module setup.

The module setup correctly uses async: false for database tests, defines a clean TestRepo and User schema, and properly handles cleanup via on_exit. The z_ prefix on the database filename ensures it sorts last, avoiding conflicts with other test databases.


150-270: UUID and :null encoding tests look good.

Good coverage of UUID string handling and :null atom to nil conversion for NULL values. The tests correctly verify round-trip encoding and IS NULL queries.


297-318: Unused variable is appropriately marked.

The _results variable at line 309 correctly uses the underscore prefix to indicate intentional discard, following the coding guidelines for terminal test operations.


492-502: Good large binary test with proper assertion.

Testing with 1MB of random data is appropriate for validating large data handling. Using pin matching (^binary) ensures exact data integrity verification rather than just checking size.


572-602: Decimal encoding tests align with PR objectives.

These tests directly address the PR objective of encoding Decimal values to string format before passing to the Rust NIF. Good coverage of both positive and negative decimal values.


621-671: Temporal type tests validate ISO8601 encoding.

These tests verify the core PR fix - converting DateTime, NaiveDateTime, Date, and Time to ISO8601 strings. The exact string comparison (rather than LIKE patterns) ensures proper format validation.


984-990: Good edge case: division by zero handling.

Correctly validates SQLite's behaviour of returning NULL for division by zero rather than raising an error.


1-1005: Overall: Excellent test coverage for type encoding implementation.

This test suite comprehensively covers the PR objectives:

  • ✅ DateTime, NaiveDateTime, Date, Time encoding to ISO8601
  • ✅ Decimal encoding to string
  • ✅ Boolean encoding (true/false → 1/0)
  • ✅ :null atom handling
  • ✅ Primitive pass-through (nil, integers, floats, strings, binaries)
  • ✅ Mixed parameter handling
  • ✅ Edge cases (NULL handling, type coercion, large values)

The test structure is well-organised with clear describe blocks and appropriate cleanup.

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.

2 participants