Skip to content

Commit 6c32c6b

Browse files
Abel Milashclaude
andcommitted
Align async fetchxml() docstring and comments with sync
Add missing "Use for SQL-JOIN scenarios..." sentence, expand :return: description, add link-entity JOIN example, align Eager/Lazy comment wording, and add the two inline implementation comments from sync. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent e4680f8 commit 6c32c6b

1 file changed

Lines changed: 18 additions & 3 deletions

File tree

src/PowerPlatform/Dataverse/aio/operations/async_query.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,13 @@ def fetchxml(self, xml: str) -> AsyncFetchXmlQuery:
159159
:meth:`~PowerPlatform.Dataverse.models.async_fetchxml_query.AsyncFetchXmlQuery.execute_pages`
160160
is called on the returned object.
161161
162+
Use for SQL-JOIN scenarios, aggregate queries, or other operations that
163+
the OData builder endpoint cannot express.
164+
162165
:param xml: Well-formed FetchXML query string. The root ``<entity name="...">``
163166
element determines the entity set endpoint.
164167
:type xml: :class:`str`
165-
:return: Inert async query object.
168+
:return: Inert async query object with ``.execute()`` and ``.execute_pages()`` methods.
166169
:rtype: :class:`~PowerPlatform.Dataverse.models.async_fetchxml_query.AsyncFetchXmlQuery`
167170
:raises ValidationError: If the FetchXML is not a string, is empty, or exceeds the URL
168171
length limit when encoded.
@@ -174,15 +177,19 @@ def fetchxml(self, xml: str) -> AsyncFetchXmlQuery:
174177
<fetch top="50">
175178
<entity name="account">
176179
<attribute name="name" />
180+
<link-entity name="contact" from="parentcustomerid"
181+
to="accountid" alias="c" link-type="inner">
182+
<attribute name="fullname" />
183+
</link-entity>
177184
</entity>
178185
</fetch>
179186
\"\"\")
180187
181-
# Eager — all pages collected:
188+
# Eager — collect all pages:
182189
result = await query.execute()
183190
df = result.to_dataframe()
184191
185-
# Lazy — one page at a time:
192+
# Lazy — process one page at a time:
186193
async for page in query.execute_pages():
187194
process(page.to_dataframe())
188195
"""
@@ -191,11 +198,19 @@ def fetchxml(self, xml: str) -> AsyncFetchXmlQuery:
191198
xml = xml.strip()
192199
if not xml:
193200
raise ValidationError("xml must not be empty")
201+
# Fast-fail before any HTTP is attempted; execute_pages() re-checks the full URL
202+
# (base + encoded XML) on each page.
194203
if len(_url_quote(xml, safe="")) > _MAX_URL_LENGTH:
195204
raise ValidationError(
196205
f"FetchXML exceeds the Dataverse URL length limit ({_MAX_URL_LENGTH:,} characters) when encoded. "
197206
"Use a $batch POST request to send FetchXML in the request body where the limit is 64 KB."
198207
)
208+
# Parse only to verify well-formedness and extract the entity name needed for the
209+
# request URL. Structural and semantic validation is intentionally left to the server
210+
# to avoid duplicating rules that may diverge from Dataverse's own enforcement.
211+
# ElementTree does not resolve external entities or expand recursive internal entity
212+
# references, so pathological inputs of that kind raise ParseError rather than
213+
# consuming resources.
199214
try:
200215
root_el = _ET.fromstring(xml)
201216
except _ET.ParseError as exc:

0 commit comments

Comments
 (0)