Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions docs/eval.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ assert results[1]["doc"] == 2
```

The following table describes how each MarkLogic type is associated with a Python data type. For any
MarkLogic type not listed in the table, the value is not converted and will be of type `bytes`.
MarkLogic type not listed in the table, such as `hexBinary` and `base64Binary`, the value is not converted and will be
of type `bytes`.

| MarkLogic type | Python type |
| --- | --- |
Expand All @@ -78,13 +79,13 @@ MarkLogic type not listed in the table, the value is not converted and will be o
| element() | str |
| array | list |
| array-node() | list |
| object-node() | dict or marklogic.documents.Document |
| document-node() | str or marklogic.documents.Document |
| binary() | marklogic.documents.Document |
| object-node() | dict or `marklogic.documents.Document` |
| document-node() | str or `marklogic.documents.Document` |
| binary() | bytes or `marklogic.documents.Document` |

For the `object-node()` and `document-node()` entries in the above table, a `marklogic.documents.Document` instance
will be returned if the MarkLogic value is associated with a URI via the multipart `X-URI` header. Otherwise, a `dict`
or `str` is returned respectively.
For the `object-node()`, `document-node()`, and `binary()` entries in the above table, a
`marklogic.documents.Document` instance will be returned if the value is associated with a URI via
the multipart `X-URI` header. Otherwise, a value of type `dict`, `str`, or `bytes` is returned respectively.

## Returning the original HTTP response

Expand Down
51 changes: 21 additions & 30 deletions marklogic/internal/eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,6 @@
Supports working with data returned by the v1/eval and v1/invoke endpoints.
"""

__primitive_value_converters = {
"integer": lambda part: int(part.text),
"decimal": lambda part: Decimal(part.text),
"boolean": lambda part: ("False" == part.text),
"string": lambda part: part.text,
"map": lambda part: json.loads(part.text),
"element()": lambda part: part.text,
"array": lambda part: json.loads(part.text),
"array-node()": lambda part: json.loads(part.text),
"object-node()": lambda part: __process_object_node_part(part),
"document-node()": lambda part: __process_document_node_part(part),
# It appears that binary() will only be returned for a binary node retrieved
# from the database, and thus an X-URI will always exist. Have not found a
# scenario that indicates otherwise.
"binary()": lambda part: Document(__get_decoded_uri_from_part(part), part.content),
}


def process_multipart_mixed_response(response: Response) -> list:
"""
Expand Down Expand Up @@ -55,20 +38,28 @@ def process_multipart_mixed_response(response: Response) -> list:
return transformed_parts


def __get_decoded_uri_from_part(part):
encoding = part.encoding
return part.headers["X-URI".encode(encoding)].decode(encoding)


def __process_object_node_part(part):
if b"X-URI" in part.headers:
return Document(__get_decoded_uri_from_part(part), json.loads(part.text))
else:
return json.loads(part.text)
__primitive_value_converters = {
"integer": lambda part: int(part.text),
"decimal": lambda part: Decimal(part.text),
"boolean": lambda part: "False" == part.text,
"string": lambda part: part.text,
"map": lambda part: json.loads(part.text),
"element()": lambda part: part.text,
"array": lambda part: json.loads(part.text),
"array-node()": lambda part: json.loads(part.text),
"object-node()": lambda part: __process_node(
part, lambda part: json.loads(part.text)
),
"document-node()": lambda part: __process_node(part, lambda part: part.text),
"binary()": lambda part: __process_node(part, lambda part: part.content),
}


def __process_document_node_part(part):
def __process_node(part, content_extractor):
content = content_extractor(part)
if b"X-URI" in part.headers:
return Document(__get_decoded_uri_from_part(part), part.text)
encoding = part.encoding
uri = part.headers["X-URI".encode(encoding)].decode(encoding)
return Document(uri, content)
else:
return part.text
return content
6 changes: 6 additions & 0 deletions tests/test_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ def test_hexBinary(client):
assert type(parts[0]) is bytes


def test_binary(client):
parts = client.eval(xquery='binary{xs:hexBinary("00")}')
assert len(parts) == 1
assert type(parts[0]) is bytes


Copy link
Contributor

Choose a reason for hiding this comment

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

nice

def test_no_script(client):
with raises(
ValueError, match="Must define either 'javascript' or 'xquery' argument."
Expand Down