Revision history for DBIx::Class::Async

0.62 2026-02-25
     [NEW FEATURES]
     - Added as_subselect_rs() method for wrapping queries as subselects.
       Correctly preserves column lists from the original ResultSet.
       When you select a subset of columns, the subselect will only include
       those columns, not all columns from the table. This enables complex
       query patterns with derived tables, limited subqueries, and
       multi-stage aggregations.

     - Added support for empty SELECT lists (select => []). Generates
       database-appropriate SQL: "SELECT FROM table" for PostgreSQL,
       "SELECT 1 FROM table" for other databases. This addresses
       compatibility with PostgreSQL's column-less SELECT syntax and
       resolves the limitation inherited from DBIx::Class core.

     - Added DBIx::Class::Async::Exception, a structured exception class
       hierarchy consistent with the DBIx::Class::Exception interface.
       Exceptions stringify to their message, support boolean overload,
       and provide throw/rethrow.

     - Added DBIx::Class::Async::Exception::Factory to translate raw
       DBIx::Class error strings into typed exception objects automatically,
       including improved diagnostics (relationship name passed as undef
       column value). Loading Factory is sufficient for all internal
       use -- it loads the base class and all subclasses as part of its own
       initialisation.

     - Each exception subclass lives in its own file, individually loadable
       via use/require and properly indexed on MetaCPAN:
       - DBIx::Class::Async::Exception::RelationshipAsColumn
       - DBIx::Class::Async::Exception::NotInStorage
       - DBIx::Class::Async::Exception::MissingColumn
       - DBIx::Class::Async::Exception::NoSuchRelationship
       - DBIx::Class::Async::Exception::AmbiguousColumn

     [ENHANCEMENTS]
     - Enhanced as_query() to detect and handle empty column selection,
       generating optimal SQL for each database backend.

     - _call_worker now derives result_class from the payload's source_name
       at the top of the method, making it available to both the pre-flight
       validation and all three post-worker error paths without any change
       to the call signature. Pre-flight validation in _call_worker catches
       (undef relationship key in create/update hashref) before the request
       reaches the worker pool, returning a typed Future->fail immediately.

     [TESTS]
     - Added comprehensive tests for empty select list SQL generation,
       condition handling, and execution in t/152-sql-consistency.t.

     - Added t/exception.t covering throw/rethrow/overload behaviour for the
       base class and all subclasses, Factory pattern matching, and passthrough
       of unrecognised errors. Tests use mock schema/source objects and
       require no live database connection.

     [DOCUMENTATION]
     - Documented empty SELECT list support with usage examples and
       database-specific behavior in search() method POD.

0.61 2026-02-24
     [NEW FEATURES]
     - Added update_query() method to DBIx::Class::Async::ResultSet for
       previewing UPDATE SQL without execution. Useful for debugging,
       audit logging, and testing. (GH#XXX)

     - Added delete_query() method to DBIx::Class::Async::ResultSet for
       previewing DELETE SQL without execution. Enables safe validation
       of destructive operations before execution.

     - Added insert_query() method to DBIx::Class::Async::Row for
       previewing INSERT SQL without execution. Allows inspection of
       insert operations for testing and validation.

0.60 2026-02-24
     [ENHANCEMENTS]
     - Added debugobj() and debugfh() methods to DBIx::Class::Async::Storage::DBI
       for full API compatibility with DBIx::Class::Storage::DBI. These
       methods enable SQL debugging and logging with custom debug objects
       or filehandles.

     - Enhanced worker processes to respect debug flag from parent process.
       When storage->debug(1) is called, SQL statements are now logged to
       STDERR in worker processes, enabling comprehensive query debugging
       in async mode.

     - Improved SQL generation consistency in DBIx::Class::Async::ResultSet.
       Column ordering and attribute merging are now fully deterministic
       across multiple invocations of the same query, improving query cache
       effectiveness and debugging reliability.

     - Added attribute deduplication in ResultSet->search() chaining.
       Accumulating attributes (join, prefetch, columns, select, as,
       order_by, group_by, having) are now automatically deduplicated using
       stable serialization, preventing duplicate JOINs and maintaining
       consistent SQL structure.

     [TESTS]
     - Added t/152-sql-consistency.t to verify deterministic SQL generation
       across multiple query invocations, including tests for column order
       stability, attribute merging, and deduplication behaviour.

     - Added t/spelling.t to perform British spell check for AUTHOR_TESTING.

     [DOCUMENTATION]
     - Added comprehensive DEBUGGING section to DBIx::Class::Async::Storage::DBI
       documenting debug(), debugobj(), and debugfh() methods with usage
       examples.

     - Enhanced debug() method documentation to clarify integration with
       debugobj and worker process behavior.

     - Added detailed POD for SQL generation consistency guarantees and their
       benefits for query caching, performance analysis, and testing.

     [INTERNAL]
     - Refactored _merge_attrs() in ResultSet.pm with clearer logic and
       improved deduplication using Data::Dumper for nested structure
       comparison.

     - Extracted _merge_cond(), _is_empty_cond(), and _dedup_key() helper
       methods for better code organization and reusability.

     - Modified _call_worker() in Async.pm to pass debug flag to worker
       processes, enabling consistent debug behavior across process
       boundaries.

0.59 2026-02-21
     [Bug Fixes]
     - Fixed issue silent drop of relationship 'where' conditions.
       Relationships defined with a 'where' containing raw SQL scalar refs
       (e.g. datetime functions) were silently ignored when traversing via
       a row accessor or prefetch, returning all related rows instead of
       the filtered subset.
       Fixed in _ensure_accessors(), _fetch_relationship_async(), and
       related_resultset() in DBIx::Class::Async::Row.
       Relationships with raw SQL in their 'where' are now excluded from
       the '_related' cache, ensuring dynamic expressions are evaluated
       fresh on every call.
     [TESTS]
     - t/151-has-many-datetime-filter.t: to cover the bug fix.
     - t/150-multi-column-relationship.t: new test covering multi-column
       relationships spanning two tables, demonstrating both the DBIC
       coderef relationship approach (join/prefetch) and the async-safe
       helper method pattern for cases where join conditions depend on
       columns from related tables rather than self.

0.58 2026-02-20
     [BUG FIX]
     - ResultSet::create() now detects scalar-ref values targeting primary
       key columns and croaks immediately with a descriptive error message.
       Previously, scalar refs used to embed inline SQL expressions
       (e.g. \'UUID()') were silently stringified during IPC serialisation
       to the worker process, causing DBIC to fall back to last_insert_id()
       on a non-autoincrement char column and return a wrong value ('1' on
       SQLite, undef on MySQL). Callers should generate PK values in Perl
       before calling create(), e.g. Data::UUID->new->create_str.
     [TEST SUITE]
     - t/149-scalar-ref-char-pk.t: new test covering the scalar-ref char PK
       guard and confirming that Perl-side UUID generation works correctly
       as the fix.
     - t/lib/TestSchema/Result/Event.pm: new test fixture.
     - t/003-basic.t, t/004-simple-get.t: updated source count from 3 to 4
       to reflect the addition of the Event fixture to TestSchema.

0.57 2026-02-10
     - [FEATURE] Changed caching to be disabled by default (TTL set to 0).
     - [FEATURE] Added automatic detection of non-deterministic SQL functions
       (NOW, RAND, etc.) to automatically bypass cache for safety.
     - [FIX] Improved cache invalidation on update/delete operations to use
       specific primary key keys, preventing stale data scenarios.
     - [FIX] count() queries are no longer cached by default due to high
       risk of stale data, ensuring accurate row counts.

0.56 2026-02-08
     [TEST SUITE]
     - Fixed t/030-row-copy.t to deal in system with -Duselongdouble as
       reported in the issue #4 by @eserte.
     - Fixed t/145-mojo-integration.t to skip test unless Mojo::IOLoop and
       IO::Async::Loop::Mojois are found as reported in the issue #5
       by @eserte.

0.55 2026-02-06
     [NEW FEATURES]
     - Added run_parallel() method to DBIx::Class::Async::Schema. This method
       accepts a list of code references, executes them concurrently using
       the asynchronous schema connection, and returns a Future that
       resolves when all tasks are complete.
     - Added await_all() method to DBIx::Class::Async::Schema. This method
       takes one or more Future objects and synchronously blocks until all
       of them have completed, returning the list of results.
     [DOCUMENTATION]
     - Added comprehensive POD for run_parallel() and await_all() in Schema.pm,
       including usage examples for maximizing query performance.
     [TEST SUITE]
     - Added t/146-await-all.t to verify synchronous waiting and error
       propagation for await_all().
     - Added t/147-run-parallel.t to verify concurrent execution, aggregation
       of results, and error propagation for run_parallel().

0.54 2026-02-04
     [TEST SUITE]
     - Fixed t/145-mojo-integration.t to prevent compile-time failures on
       environments where Mojo::IOLoop is not installed.
     [DOCUMENTATION]
     - Formalised Event Loop Agnosticism: Explicitly documented the
       ability to inject external IO::Async::Loop instances.

0.53 2026-02-04
     [TEST SUITE]
     - Added t/144-loop-engine.t: Validates "Smart Default" auto-initialisation
       and verified "Injection Pattern" for custom IO::Async::Loop instances.
     - Added t/145-mojo-integration.t: Established formal support for
       Mojo::IOLoop environments, proving non-blocking co-existence
       between DBIC workers and Mojo timers.

     [DOCUMENTATION]
     - Updated DBI.pm/Storage.pm: Clearly defined the "Master-Worker"
       architecture and the separation of the Parent process from the
       DBI Handle (Ghost DBH pattern).
     - Enhanced CAVEATS: Documented why traditional txn_begin/commit
       blocks are replaced by the atomic instruction-set logic of txn_do.

0.52 2026-02-04
     - Proposed patch for issue #4 (-Duselongdouble), thanks @eserte.
     - Proposed patch for issue #9 (seg fault), thanks @eserte.
     - Proposed patch for issue #7 (missing prereq). thanks @szabgab.
     - Merged pull request #8 (add more versions of Perl to CI), thanks @szabgab.

0.51 2026-02-03
     - Bumped version as PAUSE was unhappy with previous tar ball.

0.50 2026-02-03
     [MAJOR ARCHITECTURAL OVERHAUL]
     - Complete rewrite of the Storage and Persistence layer to use a
       decoupled "Bridge & Worker" architecture.
     - Implementation of DBIx::Class::Async::Row lifecycle management:
        * Introduced "Dirty" column tracking to minimise SQL UPDATE payloads.
        * Added shadow-key optimisation for high-speed attribute access.
        * Robust AUTOLOAD mechanism for transparent ResultSet/Row interaction.
     - Enhanced Race Condition Recovery:
        * find_or_create() now handles unique constraint collisions
          automatically via a catch-and-retry strategy.
     - Improved Memory & Process Management:
        * Weakened schema references in Storage to prevent worker leaks.
        * Refined worker pool lifecycle (connect/disconnect) for cleaner
          shutdowns in event-loop environments.
     - Streaming Support:
        * Introduced DBIx::Class::Async::Storage::DBI::Cursor for
          non-blocking, memory-efficient iteration over large result sets.
     - Persistence Integrity:
        * Added strict Primary Key validation in find(), update(), and delete()
          to prevent ambiguous database operations.
     - Documentation:
        * Full POD refresh for Row, ResultSet, and Storage classes reflecting
          the new async design patterns.

0.49 2026-01-22
     - [IMPROVEMENT] Fixed ResultSet->slice to correctly return a ResultSet
       in scalar context.
     - [IMPROVEMENT] Fixed ResultSet->count to respect slices (LIMIT/OFFSET)
       by using subqueries in the async worker.
     - [IMPROVEMENT] Ensure result_class persists across chained search() calls.
     - [IMPROVEMENT] Fixed constructor (new) to correctly store and inherit
        result_class, rows, and pager attributes.
     - [IMPROVEMENT] Fixed argument passing in Async.pm to ensure attributes
       ($attrs) reach the background worker for count operations.
     - [TEST] Fixed t/43-result-class.t to verify result_class persistence.
     - [TEST] Fixed t/26-slice.t to test comprehensive slicing and chaining
       behaviour against a real SQLite database.
     - [TEST] Added t/57-count-performance.t to benchmark and verify the
       overhead of asynchronous subquery counting.

0.48 2026-01-22
     - [ENHANCE] Hardened _merge_result_data to support multiple database
       return patterns (HASH, ARRAY, and SCALAR).
     - [FIX] Added support for positional Primary Key mapping from ARRAY
       refs, improving compatibility with specialised DBI drivers.
     - [FIX] Improved Composite Primary Key safety during row creation,
       ensuring multi-column keys are correctly populated from database
       returns (e.g., PostgreSQL RETURNING clauses).
     - [TEST] Added comprehensive test suite for result data merging
       logic (t/56-merge-result-data.t).

0.47 2026-01-22
     - [REFACTOR] Overhauled Row state management to use authoritative
       'in_storage' flags instead of guessing based on Primary Key presence.
     - [FIX] Resolved "Cannot update row: not in storage" errors in
       complex workflows by propagating storage state through recursive
       relationship inflation.
     - [REFACTOR] Centralised row inflation logic into Async.pm bridge to
       ensure consistent object creation across all ResultSet fetch paths.
     - [FIX] Updated find_or_new to correctly distinguish between persistent
       and transient objects.
     - [IMPROVE] Hardened Row and ResultSet against Mock objects in test
       suites by adding defensive metadata checks (can('columns')).
     - [OPTIMISE] Improved search performance by only generating cache
       keys when caching is explicitly enabled.
     - [FIX] Ensure single-column primary keys are correctly merged during
       create() operations across all bridge drivers.

0.46 2026-01-22
     - [DOCS] Major documentation overhaul across the entire distribution.
     - [DOCS] Modernised SYNOPSIS for all core packages to utilise Future-based
       chaining (->then/->catch) instead of legacy blocking patterns:
        * DBIx::Class::Async
        * DBIx::Class::Async::Schema
        * DBIx::Class::Async::ResultSet
        * DBIx::Class::Async::Row
        * DBIx::Class::Async::Storage
        * DBIx::Class::Async::Storage::DBI
        * DBIx::Class::Async::Storage::DBI::Cursor
        * DBIx::Class::Async::Pager
        * DBIx::Class::Async::ResultComponent
     - [DOCS] Added practical examples for high-concurrency operations, including
       race-condition safe find_or_create and update_or_create.
     - [DOCS] Documented the "Smart Discovery" logic for unique constraints.
     - [DOCS] Improved technical clarity regarding synchronous metadata vs.
       asynchronous data retrieval in Pager and Row objects.
     - [DOCS] Demonstrated standard async patterns for recursive cursor iteration.

0.45 2026-01-22
     - [REFACTOR] Extracted unique constraint discovery into internal helper
       _extract_unique_lookup to unify logic across ResultSet operations.
     - [FEATURE] Refactored find_or_new to use Smart Discovery for lookups,
       improving search accuracy.
     - [FIX] Enhanced find_or_new to correctly strip "me." prefixes from
       ResultSet conditions when instantiating new result objects.
     - [FIX] Cleaned up find_or_create logic by utilising the new lookup
       helper and streamlining the race-condition recovery path.
     - [DOCS] Added POD documentation for internal _extract_unique_lookup method.
     - [FIX] Refactored update_or_create to utilise _extract_unique_lookup and
      implement atomic race-condition recovery.
    - [FIX] Corrected update_or_new behavior to properly return a volatile
      new_result object instead of persisting via create() on find failure.
    - [IMPROVEMENT] Standardised prefix stripping (me/self/foreign) in
      update_or_new to prevent invalid column crashes on filtered ResultSets.
    - [REFACTOR] Streamlined identity discovery across all upsert-style
      methods to ensure consistent unique key prioritisation.

0.44 2026-01-22
     - [FEATURE] Refactor find_or_create to be race-condition safe in
       asynchronous environments.
     - [IMPROVEMENT] Implement "Smart Discovery" for unique constraints;
       automatically identifies lookup columns if 'key' is not provided.
     - [FIX] Enhance Async.pm error propagation to correctly stringify
       DBIx::Class::Exception objects for the parent process.
     - [FIX] Ensure find_or_create handles the "Gap" between initial find
       and create by performing an atomic recovery find on conflict.
     - [FIX] Add missing $attrs propagation to find() in Async.pm to
       support complex recovery searches.

0.43  2026-01-22
      - Minor test cleanup.

0.42  2026-01-22
      - [MAJOR] Added DBIx::Class::Async::ResultComponent to provide
        non-blocking row-level update() and delete() methods.
      - [OPTIMISATION] Re-engineered ResultSet update() and delete() to use
        high-performance bulk SQL ("WHERE PK IN (...)") instead of
        individual N-queries.
      - [FEATURE] Added support for bulk update_bulk() and delete_all()
        respecting LIMIT and OFFSET attributes via ID-mapping.
      - [FIX] Silenced "Query returned more than one row" deprecation
        warnings by utilising search()->first() with explicit row limits
        in worker operations.
      - [FIX] Hardened the Bridge update() method to support hybrid return
        types: returns Row objects for single updates and row-counts
        for bulk updates.
      - [STABILITY] Improved IO::Async cleanup during Global Destruction
        to prevent "Notifier does not exist" warnings.
      - [INTERNAL] Added _check_response() and _merge_result_data()
        helpers to standardise error handling and row inflation.
      - [TESTS] Added 8 new test files (t/48 through t/55) covering
        bulk operations, row-level components, and internal safety guards.

0.41  2026-01-19
      - Added support for inflate column.

0.40  2026-01-19
      - Added test to cover the use of CHI with DBIx::Class::Async.

0.39  2026-01-18
      - Added sub is_ordered() to DBIx::Class::Async::ResultSet.

0.38  2026-01-18
      - Added new package DBIx::Class::Async::ResultSet::Pager.
      - Added the following subs to DBIx::Class::Async::ResultSet.
        - count_total
        - is_paged
        - page
        - pager
        - search_with_pager

0.37  2026-01-18
      - Documented the removal of support for txn_scope_guard() in DBIx::Class::Async::Schema.

0.36  2026-01-18
      - Added sub txn_batch() to DBIx::Class::Async::Schema.
      - Updated DBIx::Class::Async::Schema::deploy() to return Future.

0.35  2026-01-18
      - Updated pod for txn_batch() and added unit test.

0.34  2026-01-18
      - Added sub search_with_prefetch() to DBIx::Class::Async.
      - Added sub result_class() to DBIx::Class::Async::ResultSet.

0.33  2026-01-17
      - Added the following methods to DBIx::Class::Async::ResultSet
        - get_cache
        - set_cache
        - clear_cache

0.32  2026-01-17
      - Added the following methods to DBIx::Class::Async::ResultSet
        - count_literal
        - count_rs
        - search_literal

0.31  2026-01-16
      - Added deploy() to DBIx::Class::Async and DBIx::Class::Async::Schema.

0.30  2026-01-16
      - Added the following methods to DBIx::Class::Async::Schema
        - schema_version
        - unregister_source

0.29  2026-01-16
      - Added the following methods to DBIx::Class::Async::Row
        - is_column_dirty
        - update_or_insert
        - insert_or_update (alias for update_or_insert)

0.28  2026-01-13
      - Added sub copy() to DBIx::Class::Async::Row.
      - Added sub register_[class|source] to DBIx::Class::Async::Schema.

0.27  2026-01-12
      - Tidied up pod in general.

0.26  2026-01-12
      - Re-organise Cursor package in sync with DBIx::Class.
        Before: DBIx::Class::Async::Cursor
        After: DBIx::Class::Async::Storage::DBI::Cursor
      - Added new package DBIx::Class::Async::Storage::DBI.

0.25  2026-01-12
      - Added sub DBIx::Class::Async::Row::id().

0.24  2026-01-11
      - Added the following methods to DBIx::Class::Async::Row
        - is_column_changed
        - make_columm_dirty
        - get_dirty_columns
        - set_column
        - set_columns

0.23  2026-01-11
      - Improved DBIx::Class::Async::Schema::clone().
      - Added dedicated unit test to cover the clone().

0.22  2026-01-11
      - Added sub class() and populate() to DBIx::Class::Async::Schema.

0.21  2026-01-09
      - Updated Makefile.PL to pull version automatically.
      - Tidied up pod document.

0.20  2026-01-08
      - Updated Makefile.PL w.r.t test requisite thanks Gabor Szabo.
      - Added CI workflow thanks Gabor Szabo.
      - Tidied up pod document.

0.19  2026-01-08
      - Added sub search_related[_rs] to DBIx::Class::Async::ResultSet.

0.18  2026-01-08
      - Added sub delete_all() to DBIx::Class::Async::ResultSet.

0.17  2026-01-08
      - Added sub update_or_[new|create]() to DBIx::Class::Async::ResultSet.

0.16  2026-01-08
      - Added sub find_or_[new|create]() to DBIx::Class::Async::ResultSet.

0.15  2026-01-08
      - Added sub populate() and populate_bulk() to DBIx::Class::Async::ResultSet.

0.14  2026-01-08
      - Added sub slice() to DBIx::Class::Async::ResultSet.

0.13  2026-01-07
      - Added sub related_resultset() to DBIx::Class::Async::ResultSet.

0.12  2026-01-06
      - Updated pod about N+1 issue.

0.11  2026-01-06
      - Search with prefix now supported by DBIx::Class::Async::Schema.

0.10  2026-01-06
      - POD cleanup in general.

0.09  2026-01-05
      - Added support for Cursor.

0.08  2026-01-05
      - Added sub create_related() to DBIx::Class::Async::Row.

0.07  2026-01-05
      - Fixed sub prefetch() in DBIx::Class::Async::ResultSet.

0.06  2026-01-05
      - Fixed sub next() in DBIx::Class::Async::ResultSet.

0.05  2026-01-04
      - Removed redundant documented attributes.

0.04  2026-01-04
      - Updated pod document.

0.03  2026-01-04
      - Tidied up unit tests.

0.02  2026-01-04
      - Added initial draft to support following async operations:
        - DBIx::Class::Async::Row
        - DBIx::Class::Async::ResultSet
        - DBIx::Class::Async::Schema
        - DBIx::Class::Async::Storage
     - Also added template for the following:
        - DBIx::Class::Async::TxnGuard

0.01  2026-01-01
      - Module Created.
