Repository navigation
feat(search): filter on a field inside an object property - #4670
Merged
Merged
Conversation
`?dunning.currentStage=2` (and `['dunning.currentStage' => 2]` from PHP) answered an empty page: the request layer rebuilds the mangled key into `['dunning' => ['currentStage' => 2]]`, which applyObjectFilters read as a list of UUIDs, and a dotted key was an unknown property that added `1 = 0`. NestedPathFilter takes the filters on a path inside an object-typed property out of the filter map, in both spellings and at any depth, and writes their SQL against the JSON column (`#>>` on PostgreSQL, JSON_EXTRACT on MariaDB and MySQL): equality, a list, in, notIn, ne, isnull, like, and gt/gte/lt/lte, numeric when the operand is a number. The QueryBuilder path and the raw UNION path both use it. A segment that is not a plain name matches nothing; an encrypted object property is refused as its column filter is. A filter on the object property itself keeps its meaning. Assisted-by: ClaudeCode:claude-opus-5-5
Keeps both new MagicSearchHandler collaborators: development's MagicMetadataColumn and this branch's NestedPathFilter. Assisted-by: ClaudeCode:claude-opus-5-5
Contributor
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 173/173 | |||
| npm | ✅ | ✅ 648/648 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ✅ | ||||
| lockfile sync | ✅ | ||||
| PHPUnit | ✅ 26253/26253 · 25 skipped | ||||
| Newman | ✅ 714/714 | ||||
| Playwright | ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development. |
||||
| Hydra gates | ✅ |
Quality workflow — 2026-10-16 22:23 UTC
Download the full PDF report from the workflow artifacts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A filter can now name a field inside an object-typed property:
?dunning.currentStage=2,?dunning.currentStage[gte]=1,?dunning.paused=true, or['dunning.currentStage' => 2]from PHP.Before this, every such query answered an empty page. PHP mangles the dot,
SearchQueryHandlerrebuilds the key as['dunning' => ['currentStage' => 2]], andapplyObjectFiltersthen read that map as a list of UUIDs. A dotted key from PHP was an unknown property and added1 = 0.lib/Db/MagicMapper/NestedPathFilter.php:#>>on PostgreSQL,JSON_UNQUOTE(JSON_EXTRACT())on MariaDB and MySQL.in,notIn,ne,isnullandlike. The comparisonsgt,gte,ltandltecompare as numbers when the operand is numeric; on PostgreSQL the cast is guarded so non-numeric text cannot abort the query.MagicSearchHandleruses it on both the QueryBuilder path (applyObjectFilters) and the raw UNION path (buildObjectFilterConditionsSql).nested-property-filters, delta on zoeken-filteren.Why now: shillinq's receivables board counts the invoices in a reminder round on
ARInvoice.dunning.currentStage, and its chips filter ondunning.pausedanddunning.nextDunningDate.Tests
tests/Unit/Db/MagicSearchHandlerNestedPathFilterTest.phphas 9 tests. They cover:split()at any depth.5 of the 9 fail when the handler change is reverted (the other 4 test the new class directly or behaviour that has not changed). The neighbouring isnull and like suites still pass: 34 tests in total.
Live
I checked this on :8080 (PostgreSQL) as pieter, with the branch in the mount. ARInvoice has 3 rows and
dunningis empty on all of them.dunning.currentStage[isnull]=truedunning.currentStage[isnull]=falsedunning.currentStage[gte]=1I also ran the generated
#>>expressions, including the guarded numeric cast, against a JSON literal in the same PostgreSQL. All three returned true.Gates (exit codes)
composer check:strict, one run through heavy.sh. The WSL crash at 21:34 killed it during test:all, so test:all was rerun on its own (result below).conditions(). I fixed both: NestedPathFilter is now an instance collaborator, andconditions()is split into three helpers. phpmd on the two changed files then exits 0.OCP\DB\Schema\ITablein Migration/Version1Date20260831120000). None are in the changed files.[OK] No errors.Tests: 25972, Assertions: 67216, Errors: 4, Skipped: 27, Failures: 0. All 4 errors are inherited:AuditTrailMapperReadHistoryTestneedsOC\DB\QueryBuilder\CompositeExpression, which is not there when the suite runs on the host without Nextcloud server core.appinfo/info.xmlversion is not touched. The branch is based on b08b9fe (local development), so the mount keeps the installed version; it merges cleanly into development.AI assistance: written with Claude Code (claude-opus-5-5), reviewed by the lane coordinator.