-
Notifications
You must be signed in to change notification settings - Fork 1
fix: add DateTime/Decimal parameter encoding for Oban compatibility #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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
WalkthroughAdds param encoding for Elixir types (temporal types, Decimal, booleans, :null, plain maps→JSON), implements Changes
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this 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.UUIDstructs- 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
📒 Files selected for processing (2)
lib/ecto_libsql/query.extest/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.extest/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
Usecast/3in 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:statefor connection scope,trx_statefor transaction scope,cursorfor cursor scope,stmt_idfor 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 patternassert {: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.extest/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.extest/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.extest/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.extest/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: nilandrows: nilare 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.
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
There was a problem hiding this 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
FunctionClauseErrorwhen 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
DateTimeto ISO8601 string (line 931) before passing as parameter. This verifies the string works, but doesn't test thatDateTimestructs are automatically handled differently from plain maps by the encoding logic.A more comprehensive test would pass the raw
DateTimestruct 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
setupblock (lines 103-108). While not harmful, this is redundant.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
lib/ecto/adapters/libsql/connection.exlib/ecto_libsql/native.extest/ecto_integration_test.exstest/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.extest/ecto_integration_test.exstest/ecto_migration_test.exslib/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
Usecast/3in changesets for automatic type conversion in Elixir
Files:
lib/ecto_libsql/native.exlib/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:statefor connection scope,trx_statefor transaction scope,cursorfor cursor scope,stmt_idfor 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 patternassert {:error, %EctoLibSql.Error{}, _conn}
Files:
test/ecto_integration_test.exstest/ecto_migration_test.exs
lib/ecto/adapters/libsql/connection.ex
📄 CodeRabbit inference engine (CLAUDE.md)
Update SQL generation in
lib/ecto/adapters/libsql/connection.exwhen 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.exlib/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.extest/ecto_migration_test.exslib/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.exstest/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.exslib/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.exslib/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.exslib/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.exslib/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!/1raisesJason.EncodeErrorif 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 usingJason.encode/1with 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_argsandexecute_with_transactioncorrectly 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").
- 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
There was a problem hiding this 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_encodedvariable 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
⛔ Files ignored due to path filters (1)
.beads/.sync.lockis excluded by!**/*.lock
📒 Files selected for processing (8)
.beads/last-touched.beads/sync_base.jsonl.claude/settings.local.jsonAGENTS.mdTYPE_ENCODING_SUMMARY.mdlib/ecto_libsql/query.extest/type_encoding_implementation_test.exstest/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.exstest/type_encoding_implementation_test.exsTYPE_ENCODING_SUMMARY.mdlib/ecto_libsql/query.ex
test/**/*.{exs,ex}
📄 CodeRabbit inference engine (CLAUDE.md)
test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming:statefor connection scope,trx_statefor transaction scope,cursorfor cursor scope,stmt_idfor 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 patternassert {:error, %EctoLibSql.Error{}, _conn}
Files:
test/type_encoding_investigation_test.exstest/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
Usecast/3in 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.exstest/type_encoding_implementation_test.exsTYPE_ENCODING_SUMMARY.mdlib/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.exstest/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.exstest/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.exstest/type_encoding_implementation_test.exsTYPE_ENCODING_SUMMARY.mdlib/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.exstest/type_encoding_implementation_test.exsTYPE_ENCODING_SUMMARY.mdlib/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.exstest/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/3implementation correctly handles list parameters by mapping each element throughencode_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/1implementations 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)
:nullatom support provides a useful alternative tonil- 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/3is 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_exitcallback
54-148: LGTM!Comprehensive boolean encoding tests covering:
- Direct SQL with
true/falseparameters- 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
:nullatom encoding, verifying it produces SQL NULL values that work correctly withIS NULLandIS NOT NULLoperators.
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 formatchecks. Please runmix formatto 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 errorsLearnt 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 ElixirLearnt 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 issuesLearnt 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 stringsLearnt 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 supporttest/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
TYPE_ENCODING_SUMMARY.md
Outdated
| ``` | ||
| 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 | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| ``` | |
| 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.
- 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
There was a problem hiding this 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!/1will raiseJason.EncodeErrorif 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 endtest/type_encoding_implementation_test.exs (1)
409-418: Unused schema module.
StringTestTypes(and similarlyBinaryTestTypes,NumericTestTypes,TemporalTestTypesin 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
📒 Files selected for processing (7)
.beads/.gitignore.gitignorelib/ecto/adapters/libsql/connection.exlib/ecto_libsql/query.extest/ecto_integration_test.exstest/ecto_libsql_query_encoding_test.exstest/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.extest/ecto_integration_test.exslib/ecto_libsql/query.extest/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.exwhen 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
Usecast/3in changesets for automatic type conversion in Elixir
Files:
lib/ecto/adapters/libsql/connection.exlib/ecto_libsql/query.ex
test/**/*.{exs,ex}
📄 CodeRabbit inference engine (CLAUDE.md)
test/**/*.{exs,ex}: For state threading in tests, use consistent variable naming:statefor connection scope,trx_statefor transaction scope,cursorfor cursor scope,stmt_idfor 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 patternassert {:error, %EctoLibSql.Error{}, _conn}
Files:
test/ecto_integration_test.exstest/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.exlib/ecto_libsql/query.extest/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.exlib/ecto_libsql/query.extest/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.extest/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.extest/ecto_integration_test.exslib/ecto_libsql/query.extest/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.extest/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.exstest/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 Loggerto the module level (near other aliases) for consistency, asrequireis 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
:nullhandling 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:
- Plain maps are JSON-encoded before NIF invocation
- Nested map structures are preserved through encoding
- 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
:nullatom is converted tonil(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.
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.
There was a problem hiding this 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 >= 1when 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
📒 Files selected for processing (2)
lib/ecto_libsql/query.extest/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:statefor connection scope,trx_statefor transaction scope,cursorfor cursor scope,stmt_idfor 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 patternassert {: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: falsefor shared database access, defines scoped TestRepo and User modules, and properly manages table creation and cleanup insetup_all. Theon_exitcallback 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
:null→nil→NULLencoding 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.
28e8f21 to
0438907
Compare
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.
There was a problem hiding this 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
>= 1assertion would pass even if the encoding were broken and returned both users.
237-250: Test name is misleading - doesn't test:nullencoding in query parameters.This test inserts
nildirectly (line 241) and uses staticIS NULLSQL. It doesn't actually test:nullatom encoding in query parameters as the name suggests. Consider either:
- 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
- Or modifying to actually test
:nullin a parameter context (thoughIS NULLdoesn't use parameters).
317-321: Loose assertion could mask encoding failures.After inserting exactly 3 rows (lines 305-315), asserting
count >= 3would 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
📒 Files selected for processing (2)
.beads/last-touchedtest/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:statefor connection scope,trx_statefor transaction scope,cursorfor cursor scope,stmt_idfor 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 patternassert {: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-6r5toel-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: falsefor database isolation and proper cleanup viaEctoLibSql.TestHelpers.cleanup_db_files/1. Thesetup_allcorrectly initialises the repository and creates theuserstable 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.
- 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.
There was a problem hiding this 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 usersat line 253 followed by two known inserts, the counts should be deterministic. Using>= 1is 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 == uuidshould 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
>= 1and>= 2assertions (lines 354, 359, 364, 385, 401, 406) could be exact since the test data is deterministic afterDELETE FROM users.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 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:statefor connection scope,trx_statefor transaction scope,cursorfor cursor scope,stmt_idfor 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 patternassert {: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.
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
There was a problem hiding this 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
📒 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:statefor connection scope,trx_statefor transaction scope,cursorfor cursor scope,stmt_idfor 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 patternassert {: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: falsefor shared database state, defines inline test schemas, and properly registers cleanup viaon_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 -:nullatom encoding tests verify the expected behaviour.Tests correctly verify that the
:nullatom is converted tonil(SQL NULL) and can be queried withIS NULLoperators.
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, andTimeparameters 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.
- 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.
There was a problem hiding this 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 whenon_exitruns. However, if a test crashes or is interrupted, the stale table may persist with an incompatible schema for subsequent describe blocks that definetest_typeswith 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 hoistingimport Ecto.Queryto 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.QueryThen remove the
import Ecto.Querylines from individual tests.
567-569: Redundant zero comparison.In Elixir,
+0.0 == -0.0evaluates totrue, so theorclause is unnecessary. A simpleassert stored_real == 0.0would 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
📒 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:statefor connection scope,trx_statefor transaction scope,cursorfor cursor scope,stmt_idfor 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 patternassert {: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: falsefor database tests, defines an appropriate test schema, and implements proper cleanup viaon_exit. The table structure aligns with the User schema fields.
54-148: Comprehensive boolean encoding test coverage.Tests correctly verify that
trueencodes to1andfalseto0, covering raw SQL, Ecto schema integration, and Ecto.Query usage. Good isolation with explicitDELETE FROM usersat the start of each test.
150-270: LGTM - UUID and :null encoding tests are thorough.UUID tests verify correct string storage and retrieval, whilst
:nullatom tests confirm proper conversion toniland correctIS NULLquery behaviour.
605-672: Excellent temporal type encoding coverage.Tests correctly verify that
DateTime,NaiveDateTime,Date, andTimeare 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
Decimalvalues 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.
There was a problem hiding this 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:
true→1andfalse→0conversion- WHERE clause comparisons with boolean parameters
- Ecto schema integration with boolean fields
- Ecto.Query with boolean parameters
Minor suggestion: the
import Ecto.Queryat 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_typeswith different schemas usingCREATE TABLE IF NOT EXISTS. If a previous test run failed beforeon_exitcleanup, the table may exist with an incompatible schema, causing subsequent test failures.Consider either:
- Using unique table names per describe block (e.g.,
test_types_string,test_types_binary)- Adding
DROP TABLE IF EXISTS test_typesbefore the CREATE in each setupSuggested 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:
- Making the test deterministic by using a threshold that guarantees a specific outcome
- Documenting what the expected behaviour actually is for this adapter
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 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:statefor connection scope,trx_statefor transaction scope,cursorfor cursor scope,stmt_idfor 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 patternassert {: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: falsefor database tests, defines a clean TestRepo and User schema, and properly handles cleanup viaon_exit. Thez_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
:nullatom tonilconversion for NULL values. The tests correctly verify round-trip encoding and IS NULL queries.
297-318: Unused variable is appropriately marked.The
_resultsvariable 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
Decimalvalues 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, andTimeto 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.
Addresses issues from PR #57 where Oban failed due to unsupported parameter types.
Problem:
Solution:
Changes:
Testing:
Fixes #57
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.