Skip to content

Changelog

v2.0.0

Major release adding OpenSearch support and hardening the query builder. See the Upgrade Guide for migration steps.

Added

  • Nested attributes — casts, accessors, and mutators work on dot-notation paths ('hotel.location.lat' => 'float'); nested values are assigned/retrieved by their dotted key and serialized in place in toArray()/toJson().
  • Multi-index queries — read from a wildcard/comma index pattern ($index = 'logs-*') while writing to a concrete index ($writeIndex / getWriteIndex()). Documents write back to their origin _index, and from() / into() override the read/write index per call.
  • Attribute casting — Eloquent-style $casts covering the full Laravel catalog (primitives, dates, decimal, enums + enum collections, encrypted*, hashed, array-object/ collection casts, and custom CastsAttributes), plus accessors & mutators via Attribute::make and $appends.
  • Bulk insert & upsertModel::bulk([...]) and Model::upsert([...]) with automatic chunking, a configurable record cap (bulk.max / bulk.chunk_size), and a BulkResult DTO reporting per-item successes and failures.
  • OpenSearch driver selectable via SEARCH_DRIVER — the same fluent API works across Elasticsearch and OpenSearch.
  • OpenSearch authentication: basic-auth, API key, and AWS SigV4 (aws/aws-sdk-php is an optional dependency, installed only when SigV4 is used).
  • Multi-host clusters via a comma-separated SEARCH_HOST. Elasticsearch load-balances across all hosts; OpenSearch uses the first (single-endpoint by design — front a cluster with a load balancer or managed endpoint).
  • Active query validation: invalid bool clauses, match/terms_set shapes, and order/range operators now throw InvalidQuery when the query is built.

Changed

  • Environment variables renamed ELASTICSEARCH_*SEARCH_* (no fallback).
  • ConnectionInterface now exposes search(), count(), index(), update() instead of a driver-specific getClient().
  • BridgeBuilder::all() is now all(int $perPage = 15, array $columns = ['*']) and returns a bounded first page.
  • Bool clauses (must, should, must_not, filter) always render as arrays of clause objects, so chaining multiple clauses of the same type is valid.
  • multiMatch() and matchPhrase() nest as bool must clauses (no asRaw() needed).
  • count() sends only the query to the count API.
  • Aggregation results are stored per collection instance instead of a global Collection macro; multiple aggregations coexist and no longer leak across requests.

Removed

  • Deprecated from / to range operators — only gt/gte/lt/lte are valid.

Fixed

  • getAttribute() no longer errors when a hit has no _source.
  • PaginatedCollection::links() no longer fails on empty result sets (returns total: 0 with empty cursors).
  • Filters are no longer silently dropped outside a bool context — the query is promoted to a bool with the filters attached.
  • ::fake() no longer references a test-only class; the fake connection is driver-agnostic.
  • save() no longer mutates shared query-builder state during its existence check.

For older releases, switch to the v1.x docs using the version selector above.

Released under the MIT License.