Skip to content

fix(persistence): ES _lastUpdated ignores ne/sa/eb/ap prefixes and OR-lists #892

Description

@smunini

Follow-up from #876 (which fixed _lastUpdated on Postgres, #871). While checking whether the other backends needed the same fix, Elasticsearch turned out to be the one backend whose _lastUpdated clause does not go through a precision-aware date builder.

Where

build_last_updated_clause in crates/persistence/src/backends/elasticsearch/search/query_builder.rs.

It writes each SearchValue straight into a single range map on the last_updated field, keyed only by gte/gt/lt/lte. Indexed date parameters on the same backend go through parameter_handlers/date.rs, which computes a [start, end) period from the value's precision and handles every prefix. _lastUpdated bypasses that.

What is wrong

Nothing returns a 500 (unlike #871), and because ES rounds date-only range bounds itself, eq, gt, lt, ge, and le behave correctly at day/month/year precision. The gaps are:

  • ne, sa, eb, ap all fall into the _ => arm and are treated as eq. _lastUpdated=ne2026-09-01 returns exactly the resources updated on that day instead of everything else. sa/eb should mirror gt/lt on the whole period.
  • Comma-separated OR values collapse into one map. _lastUpdated=2026-09-01,2026-09-03 inserts gte/lte twice; the second value overwrites the first, so an OR silently becomes a single-value match.
  • Inconsistent with the other backends. SQLite (date_condition), MongoDB (build_date_filter_doc), and now Postgres (build_last_updated_condition) all produce the same period-range semantics for _lastUpdated. ES is the odd one out.

Suggested fix

Reuse the period logic from parameter_handlers/date.rs (its date_precision_range plus the per-prefix match) against the top-level last_updated field instead of the nested search_params.date.value, and emit one clause per value combined with bool.should / minimum_should_match: 1 so OR lists work. ne becomes must_not of the [start, end) range.

Tests

  • Unit tests on the query builder pinning the emitted JSON for ne, sa, eb, and a two-value OR list.
  • Extend the ES integration test in crates/persistence/tests/elasticsearch_tests.rs, which today only covers a single ge case (_lastUpdated search should find recently created resource), with a ne case that must exclude the just-created resource.

Not affected

https://claude.ai/code/session_01334x1QZSmUsznAtEVcnVy7

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions