From d480684b57e0d5cb814e275c9dc9d1c86dbfdd2e Mon Sep 17 00:00:00 2001 From: Rob Rudin Date: Wed, 11 Oct 2023 09:05:08 -0400 Subject: [PATCH] Added impl and test for non-document binary() Also moved the primitive_value_converters below the main public function. --- docs/eval.md | 15 +++++------ marklogic/internal/eval.py | 51 ++++++++++++++++---------------------- tests/test_eval.py | 6 +++++ 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/docs/eval.md b/docs/eval.md index 7f3a99d..7242113 100644 --- a/docs/eval.md +++ b/docs/eval.md @@ -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 | | --- | --- | @@ -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 diff --git a/marklogic/internal/eval.py b/marklogic/internal/eval.py index 9af1b3e..9757a2b 100644 --- a/marklogic/internal/eval.py +++ b/marklogic/internal/eval.py @@ -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: """ @@ -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 diff --git a/tests/test_eval.py b/tests/test_eval.py index 5e3a687..a6d44fc 100644 --- a/tests/test_eval.py +++ b/tests/test_eval.py @@ -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 + + def test_no_script(client): with raises( ValueError, match="Must define either 'javascript' or 'xquery' argument."