BDMS 774 Filtering and Sorting Wells & Contacts#665
Merged
Conversation
…n join Document Thing virtual filter fields in query_helper. Add contacts filter matching any linked Contact.name with contains, ncontains, eq, ne, startswith, endswith.
- Accept repeated filter query params via order_sort_filter merge of filters list - Contact virtual filter field things: EXISTS join ThingContactAssociation and Thing.name for contains/null operators (inverse of Thing contacts filter) - Thing virtual sorts for properties and proxies that cannot use ORDER BY on ORM attributes: monitoring_status, well_status, datalogger_suitability_status, site_name (NMBGMR thing_id_link), contacts and aquifers (min lower name), open_status (CASE on Open Status history), measuring_point_height (latest MP row) - Contact virtual sort for things: min lower Thing.name across associations - Document dispatch order in _apply_json_filter_clause and module header - Add sqlalchemy case and nulls_last imports
- Switch get_db_contacts to keyword-only filters argument matching order_sort_filter(filters=...) - Document virtual things filter and get_db_contacts link to list endpoint - Split add_contact signature across lines for line length
- Replace single filter string with Annotated list from Query(alias=filter) so Refine can send multiple JSON filter objects (AND semantics) - Point get_contacts docstring at virtual things filter and get_db_contacts - Add typing Annotated import for filter_params
- things contains, no match, and nnull filter cases - Multiple filter parameters AND together (things plus name) - Sort by things (min site name) returns 200 and includes linked contact - Module-scoped auth override matching other API tests
- monitoring_status and well_status descending or ascending - site_name, contacts, open_status, measuring_point_height, aquifers sort smoke tests (expect 200, SQL-backed ORDER BY) - Covers Thing virtual sort keys used by the wells DataGrid
- Features bullet notes repeated filter params and virtual association fields - Points readers to docs/refine-json-filters-and-virtual-fields.md for rationale
- New subsection under architecture for DataGrid filter and sort wiring - Cross-link to refine-json-filters-and-virtual-fields.md for maintainers
- Explains repeated filter query params, virtual filter fields, EXISTS pattern, and inverse Thing contacts versus Contact things associations - Documents sorting for non-column Thing and Contact fields including scalar summaries (min names, StatusHistory subqueries, site_name via thing_id_link) - Tables map API behavior to query_helper helpers; notes tests to read Note: docs/ is gitignored by default; this file is tracked via force-add so the guide stays in version control alongside query_helper.
jirhiker
approved these changes
Apr 28, 2026
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 is changing
List pages mix two kinds of columns:
WHERE/ORDER BY.This work applies to both Contacts (
GET /contactand related) and Wells (GET /thing/...water well style lists). In both places, when the grid needs (2), the API mimics a real column: stable names in the query string, then server side SQL that matches the intent.Filters
Virtual filter fields map UI
fieldnames to SQL that answers “does any related row match?” without duplicating parent rows (mostlyEXISTS). Examples: contacts on wells, things on contacts.Repeated
filter=parameters (Refine or DataGrid style) are decoded one by one and combined with AND. Sending one filter is still a list of length one. Sending none adds no filter predicates from that mechanism.Sorts
Virtual sort keys map UI
sortnames to one expression per row used inORDER BY(for example minimum linked name for an association, latest text from a history table). Implemented in_apply_thing_virtual_sortand_apply_contact_virtual_sortinservices/query_helper.py. Details and tables live indocs/refine-json-filters-and-virtual-fields.md.Why it mattered: Sorting on those names used to treat non-column attributes like database columns and could 500. Those paths are now defined in SQL.
Stricter validation
Filter JSON must include
field,operator, andvalue. Missing keys return 422.Is this a good idea?
Alternate approaches
What changed (short)
filter=params: AND together.docs/refine-json-filters-and-virtual-fields.md.Docs
docs/refine-json-filters-and-virtual-fields.md(filters, sorts, operators, semantics).