diff --git a/CHANGELOG.md b/CHANGELOG.md index 55359f06..b7e1485d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog 1.0.0]. ## Unreleased +- Add a method to allow fetching press summaries for a given document + ## [Release 22.0.1] - Ensure that we log a warning and do not error when a judgment has an unrecognised jurisdiction diff --git a/script/build_xquery_type_dicts b/script/build_xquery_type_dicts index 19c57d04..00750dea 100755 --- a/script/build_xquery_type_dicts +++ b/script/build_xquery_type_dicts @@ -13,6 +13,7 @@ checks. They are used to enforce appropriately typed variables being passed in t \"\"\" from typing import Any, NewType, Optional, TypedDict +from caselawclient.models.documents import DocumentURIString MarkLogicDocumentURIString = NewType("MarkLogicDocumentURIString", str) MarkLogicDocumentVersionURIString = NewType("MarkLogicDocumentVersionURIString", MarkLogicDocumentURIString) @@ -53,6 +54,8 @@ def ml_type_to_python_type_declaration(variable_name: str, variable_type: str): variable_type = "MarkLogicDocumentVersionURIString" elif variable_name == "privilege_uri": variable_type = "MarkLogicPrivilegeURIString" + elif variable_name == "parent_uri": + variable_type = "DocumentURIString" elif variable_name == "uri" or variable_name.endswith("_uri"): variable_type = "MarkLogicDocumentURIString" else: diff --git a/smoketest/smoketest.py b/smoketest/smoketest.py index 52e4795b..a870f99c 100644 --- a/smoketest/smoketest.py +++ b/smoketest/smoketest.py @@ -49,3 +49,10 @@ def test_get_version_annotation(): def test_get_highest_enrichment_version(): value = api_client.get_highest_enrichment_version() assert int(value) + + +@pytest.mark.write +def test_get_press_summaries_for_document_uri(): + result = api_client.get_press_summaries_for_document_uri("/uksc/2023/35") + assert len(result) == 1 + assert result[0].uri == "uksc/2023/35/press-summary/1" diff --git a/src/caselawclient/Client.py b/src/caselawclient/Client.py index f77d206b..7abb9baa 100644 --- a/src/caselawclient/Client.py +++ b/src/caselawclient/Client.py @@ -205,6 +205,20 @@ def __init__( self.session.headers.update({"User-Agent": user_agent}) self.user_agent = user_agent + def get_press_summaries_for_document_uri( + self, uri: DocumentURIString + ) -> list[PressSummary]: + """ + Returns a list of PressSummary objects associated with a given Document URI + """ + vars: query_dicts.GetComponentsForDocumentDict = { + "parent_uri": DocumentURIString(uri if uri.startswith("/") else "/" + uri), + "component": "pressSummary", + } + response = self._send_to_eval(vars, "get_components_for_document.xqy") + uris = get_multipart_strings_from_marklogic_response(response) + return [PressSummary(uri.strip(".xml"), self) for uri in uris] + def get_document_by_uri( self, uri: DocumentURIString, query: Optional[str] = None ) -> Document: diff --git a/src/caselawclient/xquery/get_components_for_document.xqy b/src/caselawclient/xquery/get_components_for_document.xqy new file mode 100644 index 00000000..536388b3 --- /dev/null +++ b/src/caselawclient/xquery/get_components_for_document.xqy @@ -0,0 +1,20 @@ +xquery version "1.0-ml"; + +declare namespace akn = "http://docs.oasis-open.org/legaldocml/ns/akn/3.0"; +declare namespace uk = "https://caselaw.nationalarchives.gov.uk/akn"; + +declare variable $parent_uri as xs:string external; +declare variable $component as xs:string external; + +let $collectionQuery := cts:collection-query(("http://marklogic.com/collections/dls/latest-version")) +let $docTypeQuery := cts:element-attribute-value-query( + xs:QName("akn:doc"), + xs:QName("name"), + $component + ) +let $refQuery := cts:element-query( + xs:QName("uk:summaryOf"), + concat("https://caselaw.nationalarchives.gov.uk/id", $parent_uri) + ) + +return xdmp:node-uri(cts:search(//akn:akomaNtoso, cts:and-query(($refQuery, $collectionQuery, $docTypeQuery)))) diff --git a/src/caselawclient/xquery_type_dicts.py b/src/caselawclient/xquery_type_dicts.py index 13a7c6d8..7f32832b 100644 --- a/src/caselawclient/xquery_type_dicts.py +++ b/src/caselawclient/xquery_type_dicts.py @@ -7,6 +7,7 @@ """ from typing import Any, NewType, Optional, TypedDict +from caselawclient.models.documents import DocumentURIString MarkLogicDocumentURIString = NewType("MarkLogicDocumentURIString", str) MarkLogicDocumentVersionURIString = NewType("MarkLogicDocumentVersionURIString", MarkLogicDocumentURIString) @@ -55,6 +56,12 @@ class DocumentExistsDict(MarkLogicAPIDict): uri: MarkLogicDocumentURIString +# get_components_for_document.xqy +class GetComponentsForDocumentDict(MarkLogicAPIDict): + component: str + parent_uri: DocumentURIString + + # get_judgment.xqy class GetJudgmentDict(MarkLogicAPIDict): show_unpublished: Optional[bool] diff --git a/tests/client/test_get_press_summaries_for_document_uri.py b/tests/client/test_get_press_summaries_for_document_uri.py new file mode 100644 index 00000000..becd8aaf --- /dev/null +++ b/tests/client/test_get_press_summaries_for_document_uri.py @@ -0,0 +1,39 @@ +from unittest import TestCase +from unittest.mock import call, patch + +from caselawclient.Client import MarklogicApiClient + + +class TestGetPressSummariesForDocumentUri(TestCase): + def setUp(self): + self.client = MarklogicApiClient("", "", "", False) + + @patch("caselawclient.Client.PressSummary", autospec=True) + @patch("caselawclient.Client.MarklogicApiClient._send_to_eval") + @patch("caselawclient.Client.get_multipart_strings_from_marklogic_response") + def test_get_press_summaries_for_document_uri( + self, mock_get_marklogic_response, mock_eval, mock_press_summary + ): + mock_eval.return_value = "EVAL" + mock_get_marklogic_response.return_value = ["/foo/bar/baz/1", "/foo/bar/baz/2"] + + for uri in ["foo/bar", "/foo/bar"]: + with self.subTest(uri=uri): + self.client.get_press_summaries_for_document_uri(uri) + + mock_get_marklogic_response.assert_called_with("EVAL") + mock_eval.assert_called_with( + { + "parent_uri": "/foo/bar", + "component": "pressSummary", + }, + "get_components_for_document.xqy", + ) + + mock_press_summary.assert_has_calls( + [ + call("/foo/bar/baz/1", self.client), + call("/foo/bar/baz/2", self.client), + ], + any_order=True, + )