Add QueryBuilder with fluent API and composable filter expressions#118
Add QueryBuilder with fluent API and composable filter expressions#118abelmilash-msft merged 29 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Implements the QueryBuilder feature from the SDK redesign design doc:
- Fluent query builder (client.query.builder("table")) with 20 chainable methods
- Composable filter expression tree (models/filters.py) with &, |, ~ operators
- filter_in, filter_between, and where() for expression tree composition
- Automatic column name lowercasing and OData value formatting
- datetime/date/uuid.UUID auto-formatting in filter values
309 tests passing (126 new for QueryBuilder + filters).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- README: Promote QueryBuilder as primary query method with fluent, expression tree, and filter_in/between examples; demote raw OData to fallback - Walkthrough: Add Section 7 with 5 QueryBuilder demos (basic fluent, filter_in, filter_between, where() expression tree, combined + paging) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
execute() now yields individual records instead of pages, abstracting away OData paging. Pass by_page=True for explicit page-level iteration. This follows the abstraction-level heuristic: QueryBuilder is the "abstract away OData" API, so paging should be transparent. The raw records.get() API retains paged iteration for backward compatibility. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Run black on 5 files that failed formatting check - Fix _FunctionFilter.__init__ value param: str -> Any (matches _format_value which handles int, float, datetime, etc.) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@abelmilash-msft -- 5 commits were added on top of your work (4e37cee..b08639d). Here's a summary for your review: New features added (closing OData Web API parity gaps identified in issue #147 and OData docs audit):
All 601 tests pass. No existing commits were removed or modified. Python 3.10-3.14 compatible. |
9f65211 to
c400243
Compare
e95e4de to
5c2a17c
Compare
…filter_raw warning
b8a4db6
Summary
Implements the QueryBuilder feature from the SDK redesign design doc (ADO PR 1504429):
client.query.builder("table")with 20 chainable methods includingselect,filter_eq/ne/gt/ge/lt/le,filter_contains/startswith/endswith,filter_in,filter_between,filter_null/not_null,filter_raw,where,order_by,top,page_size,expand, andexecutemodels/filters.py) with Python operator overloads (&,|,~) for AND, OR, NOT compositionstr,int,float,bool,None,datetime,date,uuid.UUIDUsage examples
Design decisions
_filter_partslist — preserves call order when mixingfilter_*()andwhere()execute()callsbuild()internally — single source of truth for filter compilationget()on QueryOperations — onlybuilder()added; paginated queries remain onrecords.get()filter_between—(col ge low and col le high)for correct precedenceFiles changed
src/.../models/filters.pysrc/.../models/query_builder.pysrc/.../operations/query.pybuilder()to QueryOperationssrc/.../models/__init__.pytests/.../models/test_filters.pytests/.../models/test_query_builder.pytests/.../test_query_operations.pyMerge conflict note
operations/query.pymay conflict with PR #115 (typed return models) — resolution is straightforward since we only add abuilder()method.Test plan
pytest tests/unit/models/test_filters.py— 57 passedpytest tests/unit/models/test_query_builder.py— 69 passedpytest tests/unit/test_query_operations.py— 9 passedpytest tests/— 309 passed, 0 failed🤖 Generated with Claude Code