Skip to content

[WIP] fix: mongo query predicate edge case#388

Open
JeffreyJPZ wants to merge 11 commits into
br-g:mainfrom
JeffreyJPZ:merge-query-predicates
Open

[WIP] fix: mongo query predicate edge case#388
JeffreyJPZ wants to merge 11 commits into
br-g:mainfrom
JeffreyJPZ:merge-query-predicates

Conversation

@JeffreyJPZ

Copy link
Copy Markdown
Contributor

Changes

  • Fixed an edge case that I missed in my original query predicate pairing algorithm, e.g. if i had a lower bound position > 5 and upper bound position <= 5, this does not result in a "bounded" interval.
  • Merged "overlapping" intervals to make life slightly easier for the MongoDB query planner and to make range queries easier to reason about
  • Changed query string ops from literals to enums for consistency
  • Added a MongoOp enum and MongoPredicate dataclass to get rid of repeated literals
  • Added CI job for unit tests, a guide for testing locally, and a test for the query predicate pairing algorithm, which can hopefully kickstart Add functional tests #264

I would ideally like to add a few more unit tests before this gets done.
Feedback would be appreciated, I could also break this up into multiple PRs if necessary.

Copilot AI review requested due to automatic review settings April 15, 2026 10:24
@JeffreyJPZ JeffreyJPZ marked this pull request as draft April 15, 2026 10:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the MongoDB query-filter construction to handle an edge case in bounded-interval pairing and to merge overlapping intervals, while also introducing basic unit-test infrastructure and a first regression test for predicate pairing.

Changes:

  • Introduces MongoOp and MongoPredicate and updates query predicate construction to use them.
  • Updates the bounded-inequality pairing algorithm to avoid invalid “bounded” intervals (e.g. > 5 with <= 5) and to merge overlapping intervals.
  • Adds pytest configuration, a unit test for the pairing logic, CI to run unit tests, and local testing instructions.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/openf1/util/test_predicate_pairing.py Adds unit tests for bounded-inequality pairing and overlap merging behavior.
src/openf1/util/misc.py Extends hash_obj to handle dataclass inputs (currently implemented incorrectly).
src/openf1/util/db.py Adds MongoOp/MongoPredicate, updates query predicate generation, pairing/merging logic, and session lookups.
src/openf1/services/query_api/query_params.py Switches comparison-to-Mongo operators toward enums and updates filter conversion (currently mismapped).
pyproject.toml Adds pytest discovery configuration.
CONTRIBUTING.md Documents how to run tests locally.
.github/workflows/tests.yml Adds a CI job to run unit tests with pytest.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/openf1/util/misc.py Outdated
Comment thread src/openf1/util/db.py Outdated
Comment thread src/openf1/services/query_api/query_params.py Outdated
Comment thread src/openf1/util/db.py Outdated
Comment on lines +115 to +130
Args:
predicates: A list of inequality predicates without duplicates (i.e. no two predicates can have the same op and value).
Predicates have a MongoDB operator such as "$eq", "$gt", "$gte", "$lt", or "$lte", and a numeric value (e.g. int, float, datetime).

Returns:
A list of predicate pairs where the first predicate of the pair represents a lower bound ("$gt", "$gte"),
the second predicate of the pair represents an upper bound ("$lt", "$lte"),
and the value difference among all pairs is minimized (i.e. the value difference in each pair is as small as possible).
and the second predicate of the pair represents an upper bound ("$lt", "$lte").

Examples:
[] --> []
[{"$gt": 5}] --> []
[{"$gt": 10}, {"$lt": 5}] --> []
[{"$gt": 5}, {"$lt": 10}] --> [({"$gt": 5}, {"$lt": 10})]
[{"$gt": 5}, {"$lt": 10}, {"$lt": 12}] --> [({"$gt": 5}, {"$lt": 10})]
[{"$gt": 5}, {"$lt": 10}, {"$gt": 8}, {"$lt": 12}] --> [({"$gt": 5}, {"$lt": 10}), ({"$gt": 8}, {"$lt": 12})]
[{"$eq": 5}] --> []
[{"$gt": 5}] --> [] (unbounded interval)
[{"$gt": 10}, {"$lt": 5}] --> [] (unbounded intervals)
[{"$gt": 5}, {"$lt": 10}] --> [({"$gt": 5}, {"$lt": 10})] (bounded interval)
[{"$gt": 5}, {"$lt": 10}, {"$lt": 12}] --> [({"$gt": 5}, {"$lt": 10})] (bounded interval with unbounded interval)
[{"$gt": 5}, {"$lt": 10}, {"$gt": 8}, {"$lt": 12}] --> [({"$gt": 5}, {"$lt": 12})] (bounded intervals merged due to overlap)

Copilot AI Apr 15, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring examples for _get_bounded_inequality_predicate_pairs still show the old { "$gt": 5 } dict-style predicates, but the function now accepts MongoPredicate objects. Updating these examples (and the Args description) would prevent confusion for future readers.

Copilot uses AI. Check for mistakes.
JeffreyJPZ and others added 2 commits April 15, 2026 03:32
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@br-g

br-g commented Apr 23, 2026

Copy link
Copy Markdown
Owner

Thanks a lot @JeffreyJPZ, great work!
I will have a look soon 👀

@br-g

br-g commented May 6, 2026

Copy link
Copy Markdown
Owner

Hi @JeffreyJPZ,
Apologies for the delay since my last comment!I see this PR is still marked as a "Draft". Just checking in to see if you are still actively working on it? I know you mentioned you wanted to add a few more unit tests and were looking for feedback. I also noticed that there are now some merge conflicts in src/openf1/util/db.py that will need to be resolved. Let me know if you plan to continue with this and when you think it might be ready for a full review.

@JeffreyJPZ

Copy link
Copy Markdown
Contributor Author

Hi @br-g, sorry about that! I'll try and resolve the merge conflicts, fix some of the documentation and maybe add a couple tests for _generate_query_predicate. I can't make any promises but I'll try and have that done by the end of next week?

@br-g

br-g commented May 7, 2026

Copy link
Copy Markdown
Owner

Hi @br-g, sorry about that! I'll try and resolve the merge conflicts, fix some of the documentation and maybe add a couple tests for _generate_query_predicate. I can't make any promises but I'll try and have that done by the end of next week?

No problem, take the time you need! I just wanted to check on the status

@JeffreyJPZ JeffreyJPZ marked this pull request as ready for review May 15, 2026 20:49
@JeffreyJPZ

Copy link
Copy Markdown
Contributor Author

@br-g it should be ready now for a first pass!

@br-g

br-g commented May 26, 2026

Copy link
Copy Markdown
Owner

Hi @JeffreyJPZ,

Sorry for the delay getting back to you, and thanks for your patience! This is really impressive work. The more I dig into this code, the more I appreciate how much complexity you've untangled.

I did find a few issues while testing locally:

  1. Strict-inequality empty interval not respected. [{"$gt": 5}, {"$lt": 5}] returns matching documents instead of an empty result. The docstring suggests this should be treated as an unbounded/empty case.

  2. Adjacency merge is unsafe for float-valued fields. For example:

    session_key=11291&gap_to_leader>=10&gap_to_leader<=11&gap_to_leader>=12&gap_to_leader<=44
    

    returns a document with gap_to_leader=11.276. Because both interval endpoints are integers and ops are inclusive, the two intervals get merged into [10, 44], but gap_to_leader accepts floats, so values in (11, 12) shouldn't match. The pairing function doesn't know the field's type, so it can't safely assume integer adjacency means contiguity.

  3. null handling crashes the API. session_key=11291&position>10&position=null causes a crash. I haven't dug into the root cause yet. It might be a separate concern from the pairing logic.

Would you have time to look into these? No rush! Let me know what works.

@JeffreyJPZ

Copy link
Copy Markdown
Contributor Author

Hi @br-g,

Thanks for the in-depth review, this merging logic is pretty tricky 😅 - I'll have a look at it later this week or next week.

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.

3 participants