Skip to content

Releases: ocean/ecto_libsql

0.7.0

Choose a tag to compare

@ocean ocean released this 09 Dec 02:12

πŸš€ EctoLibSql v0.7.0 - Performance & Feature Release

Major performance improvements, new connection management features, and comprehensive SQLite configuration support.

πŸ› Bug Fixes

  • ON CONFLICT Support (Issue #25) - Full upsert support with composite unique indexes

    • :on_conflict: :nothing with conflict targets
    • :on_conflict: :replace_all for upserts
    • Custom field replacement with {fields, _, targets}
  • Binary ID Type System (Issue #23) - Complete resolution

    • Fixed autogenerate(:binary_id) to generate string UUIDs
    • Fixed INSERT without RETURNING clause (was causing CaseClauseError)
    • Fixed BLOB encoding in Rust NIF (now returns Elixir binaries)
  • Remote Test Stability - Fixed vector operations test failures from stale data

⚑ Performance Improvements

Prepared Statement Caching - Statements are now cached and reused with automatic binding cleanup, delivering ~10-15x faster query execution for repeated queries. Benchmark: 100 cached executions in ~33ms (~330Β΅s per query).

✨ New Features

Connection Management

  • busy_timeout/2 - Configure database lock timeout (default: 5000ms)
  • reset/1 - Reset connection state without closing
  • interrupt/1 - Cancel long-running queries

PRAGMA Configuration

New EctoLibSql.Pragma module with comprehensive SQLite configuration:

  • Foreign keys control (enable_foreign_keys/1, disable_foreign_keys/1)
  • Journal mode (set_journal_mode/2 - WAL, DELETE, MEMORY, etc.)
  • Cache size (set_cache_size/2)
  • Synchronous level (set_synchronous/2 - OFF, NORMAL, FULL, EXTRA)
  • Table introspection (table_info/2, table_list/1)
  • User version tracking (user_version/1, set_user_version/2)

Transaction Features

  • Savepoints - Nested transaction support with partial rollback
    • create_savepoint/2 - Create named savepoint
    • release_savepoint_by_name/2 - Commit savepoint changes
    • rollback_to_savepoint_by_name/2 - Rollback to savepoint
  • Transaction Ownership Validation - Prevents cross-connection transaction manipulation

Batch Operations

  • execute_batch_sql/2 - Execute multiple SQL statements (non-transactional)
  • execute_transactional_batch_sql/2 - Atomic batch execution

Prepared Statement Introspection

  • stmt_parameter_count/2 - Get number of parameters
  • stmt_column_count/2 - Get number of result columns
  • stmt_column_name/3 - Get column name by index

Advanced Replica Sync

  • get_frame_number_for_replica/1 - Monitor replication frame
  • sync_until_frame/2 - Wait for specific frame (30s timeout)
  • flush_and_get_frame/1 - Push pending writes
  • max_write_replication_index/1 - Read-your-writes consistency tracking

πŸ”’ Security Fixes

  • SQL Injection Prevention - Added strict alphanumeric validation for savepoint names
  • Prepared Statement Validation - Enhanced parameter binding checks

πŸ“š Documentation

  • Updated AGENTS.md with all new features
  • Updated README.md with concise examples

πŸ”„ Backward Compatibility

All changes are backward compatible. Prepared statement API unchanged - caching happens transparently with improved performance.

Full Changelog: https://github.com/ocean/ecto_libsql/blob/main/CHANGELOG.md
Full list of changes: 0.6.0...0.7.0

0.6.0 - Migrations, remote replicas, better libSQL support

Choose a tag to compare

@ocean ocean released this 30 Nov 05:33

What's Changed

  • fix: Fix panic in prepared statement exec, add streaming support by @ocean in #19
  • fix: Fix Ecto migrations bug for issue #20 and add some more tests by @ocean in #21
  • feature: Add some extended libSQL support for ALTER TABLE etc by @ocean in #22
  • Remote Sync Performance & Reliability
    • Removed redundant manual .sync() calls after write operations for embedded replicas
    • LibSQL automatically handles sync to remote primary database - manual syncs were causing double-sync overhead
    • Added 30-second timeout to connection establishment to prevent indefinite hangs
    • All Turso remote tests now pass reliably (previously 4 tests timed out)
    • Test suite execution time improved significantly (~107s vs timing out at 60s+)

According to Turso documentation: "Writes are sent to the remote primary database by default, then the local database updates automatically once the remote write succeeds." Manual sync is only needed when explicitly pulling down changes from remote (e.g., after reconnecting to an existing replica).

  • Ecto Migrations Compatibility (Issue #20)

    • Fixed DDL function grouping that was causing compilation errors
    • Added comprehensive migration test suite (759 lines) covering all SQLite ALTER TABLE operations
    • Improved handling of SQLite's limited ALTER TABLE support
    • Added tests for column operations, constraint management, and index creation
  • Prepared Statement Execution

    • Fixed panic in prepared statement execution that could crash the BEAM VM
    • Added proper error handling for prepared statement operations
    • Improved error messages for prepared statement failures
  • Extended LibSQL DDL Support

    • Added support for additional ALTER TABLE operations compatible with LibSQL
    • Improved DDL operation grouping and execution order
    • Better handling of SQLite dialect quirks

Added

  • Cursor Streaming Support

    • Implemented cursor-based streaming for large result sets
    • Added handle_declare/4, handle_fetch/4, and handle_deallocate/4 DBConnection callbacks
    • Memory-efficient processing of large queries
    • Rust NIF functions: declare_cursor/3, fetch_cursor/2, cursor registry management
  • Comprehensive Test Coverage

    • Added 138 new DDL generation tests in test/ecto_connection_test.exs
    • Added 759 lines of migration tests in test/ecto_migration_test.exs
    • Improved error handling test coverage
    • All 162 tests passing (0 failures)

Changed

  • Sync Behaviour for Embedded Replicas

    • Automatic sync after writes has been removed (LibSQL handles this natively)
    • Manual sync() via EctoLibSql.Native.sync/1 still available for explicit control
    • Improved sync timeout handling with configurable DEFAULT_SYNC_TIMEOUT_SECS (30s)
    • Added connection timeout to prevent hangs during initial replica sync
  • Documentation Updates

    • Updated all documentation to reflect sync behaviour changes
    • Added clarification about when manual sync is needed vs automatic
    • Improved Turso/LibSQL compatibility documentation references

Technical Details

Sync Performance Before:

  • Manual .sync() called after every write operation
  • Double sync overhead (LibSQL auto-sync + manual sync)
  • 120-second timeout causing long test hangs
  • 4 tests timing out after 60+ seconds each

Sync Performance After:

  • LibSQL's native auto-sync used correctly
  • No redundant manual sync calls
  • 30-second connection timeout for fast failure
  • All tests passing in ~107 seconds

Migration Notes

This is a non-breaking change for normal usage. However, if you were relying on automatic sync behaviour after writes in embedded replica mode, you may now need to explicitly call EctoLibSql.Native.sync/1 when you need to ensure remote data is pulled down (e.g., after reconnecting to an existing local database).

Recommended Actions:

  1. Review code that uses embedded replicas with sync: true
  2. Add explicit sync() calls after reconnecting to existing local databases if you need to pull down remote changes
  3. Remove any redundant manual sync() calls after write operations

Full Changelog: 0.5.0...0.6.0

0.5.0 - Massively improve Rust error handling

Choose a tag to compare

@ocean ocean released this 26 Nov 23:58

Changed

  • Rust NIF Error Handling
    • Eliminated all 146 unwrap() calls from production Rust code
    • Added safe_lock() and safe_lock_arc() helper functions for safe mutex locking
    • All NIF errors now return {:error, message} tuples to Elixir instead of panicking
    • Mutex poisoning errors are handled gracefully with descriptive context
    • Invalid connection/transaction/statement/cursor IDs return proper errors

Fixed

  • VM Stability - NIF errors no longer crash the entire BEAM VM
    • Invalid operations (bad connection IDs, missing resources) now return error tuples
    • Processes survive NIF errors, allowing supervision trees to work properly
    • Error messages include descriptive context for easier debugging

Added

  • Comprehensive Error Handling Tests
    • Added test/error_demo_test.exs with 7 tests demonstrating graceful error handling
    • Added test/error_handling_test.exs with 14 comprehensive error coverage tests
    • All tests verify that NIF errors return proper error tuples instead of crashing the BEAM VM

Technical Details

Before 0.5.0:

  • 146 unwrap() calls in Rust production code
  • Mutex/registry errors β†’ panic β†’ entire BEAM VM crash
  • Invalid IDs β†’ panic β†’ VM crash
  • Supervision trees ineffective for NIF errors

After 0.5.0:

  • 0 unwrap() calls in Rust production code (100% eliminated)
  • All errors return {:error, "descriptive message"} tuples
  • Processes can handle errors and recover
  • Supervision trees work as expected

Migration Guide

This is a non-breaking change for normal Ecto usage. Your existing code will continue to work exactly as before, but is now significantly more stable.

What Changed:

  • NIF functions that previously panicked now return {:error, reason} tuples
  • Your existing error handling code will now catch errors that previously crashed the VM

Recommended Actions:

  1. Review error handling in code that uses EctoLibSql.Native functions directly
  2. Ensure supervision strategies are in place for database operations
  3. Consider adding retry logic for transient errors (connection timeouts, etc.)

Notes

This release represents a major stability improvement for production deployments. The refactoring ensures that ecto_libsql handles errors the "Elixir way" - returning error tuples that can be supervised, rather than panicking at the Rust level and crashing the VM.

0.4.0 - First ecto_libsql release

Choose a tag to compare

@ocean ocean released this 21 Nov 21:55

What's Changed

  • feat: Major feature additions - batch ops, prepared statements, transaction behaviours, and metadata by @ocean in #1
  • feat: Add comprehensive GitHub Actions CI workflow for PR testing by @ocean in #2
  • fix: Expand Elixir version support to 1.17+ (current-1 policy) by @ocean in #4
  • Add libsql cursor support, vector search, encryption and more tests by @ocean in #3
  • Add full Ecto adapter and tests by @ocean in #5
  • Rename library from libsqlex to ecto_libsql to reflect major update in functionality by @ocean in #7
  • fix: Fix remote tests, add some notes by @ocean in #8
  • Update dependabot.yml to support multiple ecosystems by @ocean in #9
  • build(deps): Bump actions/checkout from 4 to 6 by @dependabot[bot] in #10
  • build(deps): Bump db_connection from 2.7.0 to 2.8.1 by @dependabot[bot] in #11
  • build(deps): Bump rustler from 0.36.1 to 0.37.1 by @dependabot[bot] in #12
  • build(deps): Update rustler requirement from 0.36.1 to 0.37.0 in /native/ecto_libsql by @dependabot[bot] in #13
  • build(deps-dev): Bump ex_doc from 0.38.2 to 0.39.1 by @dependabot[bot] in #14
  • docs: Adjust for Hex publishing by @ocean in #15

New Contributors

Full Changelog: https://github.com/ocean/ecto_libsql/commits/0.4.0