Skip to content

fix: match array fields in where filters - #1771

Open
HafizMMoaz wants to merge 1 commit into
typicode:mainfrom
HafizMMoaz:fix/filter-array-fields
Open

fix: match array fields in where filters#1771
HafizMMoaz wants to merge 1 commit into
typicode:mainfrom
HafizMMoaz:fix/filter-array-fields

Conversation

@HafizMMoaz

Copy link
Copy Markdown

Fixes #1449

Problem

Filtering on a property nested inside an array field does not just fail to work, it silently drops the condition and returns every row.

Using the data from #1449:

{
  "businesses": [
    { "id": "1", "categories": [{ "id": 1, "name": "cat 1" }, { "id": 2, "name": "cat 2" }] }
  ]
}
$ curl 'localhost:3000/businesses?categories.id=10'
[{"id":"1","categories":[{"id":1,...},{"id":2,...}]}]   # expected []

No business has a category with id 10, but the row comes back anyway. Any value produces the same result, so the filter has no effect at all.

Cause

parseWhere correctly turns categories.id=10 into { categories: { id: { eq: 10 } } }. matchesWhere then reaches this branch:

if (isJSONObject(field)) {
  if (!matchesWhere(field, value)) return false
}

continue

isJSONObject excludes arrays, so an array field skips the check and hits continue, and a skipped condition reads as a satisfied one. This is the same fail-open shape as #1731, but on a different path: there the intermediate field is missing, here it is present but is an array.

Fix

An array field now matches when at least one of its items matches the predicate, and fails to match when none do. All conditions in the predicate must be satisfied by the same item, so ?categories.id=1&categories.name=cat 2 does not match a business that has those values spread across two different categories.

This works through _where as well, since both paths share matchesWhere.

Tests

  • matches-where.test.ts: 11 cases covering matching and non-matching items, comparison and string operators against array items, the same-item requirement, arrays of primitives, and arrays nested under or.
  • app.test.ts: an end-to-end check of the exact URL form from the issue, asserting a match and an empty result.

pnpm test, pnpm lint and pnpm typecheck all pass.

Out of scope

Arrays of primitives (?tags=red against "tags": ["red", "blue"]) still do not match. That needs a decision on what ne should mean for a collection, so it seemed better kept separate from this fix.

Filtering on a property nested inside an array field silently ignored the
condition and returned every row. matchesWhere only recursed into fields
that are plain objects, so an array field fell through to `continue`,
which reads as a match.

An array field now matches when at least one of its items matches the
predicate, and fails to match when none of them do. All conditions in the
predicate must be satisfied by the same item.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

It is not possible to filter based on collection property.

1 participant