Beispiel #1
0
 def __init__(self, model, **kwargs):
     self.client = JSONAPIClient()
     self.model = model
     self._fields = kwargs.get("fields", {})
     self._include = kwargs.get("include", [])
     self._filters = kwargs.get("filters", {})
     self._sort = kwargs.get("sort", [])
     self._cache = None
Beispiel #2
0
def test_jsonapi_client_get_with_include_empty(mock_requests):
    expected_params = {
        "fields[related_records]": "name,other_related",
    }
    url = f"http://example.com/related-records/?{urlencode(expected_params)}"
    mock_requests.get(url, json={})
    client = JSONAPIClient()
    client.get("related_records", include=[])
    assert mock_requests.called
    assert mock_requests.last_request.url == url
Beispiel #3
0
def test_jsonapi_client_get_record_default(mock_requests):
    expected_params = {
        "fields[related_records]": "name,other_related",
        "include": "other_related",
    }
    url = f"http://example.com/related-records/42/?{urlencode(expected_params)}"
    mock_requests.get(url, json={})
    client = JSONAPIClient()
    client.get("related_records", resource_id=42)
    assert mock_requests.called
    assert mock_requests.last_request.url == url
Beispiel #4
0
def test_jsonapi_client_get_with_fields_override_resource_default(
        mock_requests):
    expected_params = {
        "fields[related_records]": "name",
        "include": "other_related",
    }
    url = f"http://example.com/related-records/?{urlencode(expected_params)}"
    mock_requests.get(url, json="{}")
    client = JSONAPIClient()
    client.get("related_records", fields={"related_records": ["name"]})
    assert mock_requests.called
    assert mock_requests.last_request.url == url
Beispiel #5
0
def test_jsonapi_client_get_with_page_number(mock_requests):
    expected_params = {
        "fields[related_records]": "name,other_related",
        "include": "other_related",
        "page[number]": 12,
    }
    url = f"http://example.com/related-records/?{urlencode(expected_params)}"
    mock_requests.get(url, json="{}")
    client = JSONAPIClient()
    client.get("related_records", page_number=12)
    assert mock_requests.called
    assert mock_requests.last_request.url == url
Beispiel #6
0
def test_jsonapi_client_get_with_sort(mock_requests):
    expected_params = {
        "fields[related_records]": "name,other_related",
        "include": "other_related",
        "sort": "-name,other_related",
    }
    url = f"http://example.com/related-records/?{urlencode(expected_params)}"
    mock_requests.get(url, json="{}")
    client = JSONAPIClient()
    client.get("related_records", sort=["-name", "other_related"])
    assert mock_requests.called
    assert mock_requests.last_request.url == url
Beispiel #7
0
def test_jsonapi_client_get_handles_http_errors(mock_requests):
    expected_params = {
        "include": "other_related",
        "fields[related_records]": "name,other_related",
    }
    mock_requests.register_uri(
        "GET",
        f"http://example.com/related-records/?{urlencode(expected_params)}",
        status_code=400,
        json={"error": "some error"},
    )
    client = JSONAPIClient()
    with pytest.raises(JSONAPIClientError):
        client.get("related_records")
    assert mock_requests.called
Beispiel #8
0
def test_jsonapi_client_get_with_fields_for_related(mock_requests):
    expected_params = {
        "fields[other_related]": "something",
        "fields[related_records]": "name,other_related",
        "include": "other_related",
    }
    url = f"http://example.com/related-records/?{urlencode(expected_params)}"
    mock_requests.get(url, json={})
    client = JSONAPIClient()
    client.get("related_records",
               fields={
                   "other_related": ["something"],
                   "not_used": []
               })
    assert mock_requests.called
    assert mock_requests.last_request.url == url
Beispiel #9
0
def test_jsonapi_client_session_headers(mock_version):
    del settings.DJANGO_JSON_API_ADDITIONAL_HEADERS
    client = JSONAPIClient()
    assert client.session.headers["Accept"] == "application/vnd.api+json"
    assert client.session.headers["Content-Type"] == "application/vnd.api+json"
    assert client.session.headers["User-Agent"] == "JSONAPIClient/0.1.2"

    setattr(
        settings,
        "DJANGO_JSON_API_ADDITIONAL_HEADERS",
        {
            "User-Agent": f"SW_{settings.SERVICE}/JsonAPI",
            "X-SW-service": settings.SERVICE,
        },
    )

    client = JSONAPIClient()
    assert client.session.headers["Accept"] == "application/vnd.api+json"
    assert client.session.headers["Content-Type"] == "application/vnd.api+json"
    assert client.session.headers["User-Agent"] == "SW_test/JsonAPI"
    assert client.session.headers["X-SW-service"] == "test"
Beispiel #10
0
 def _fetch_iterate(self) -> Iterator:
     client = JSONAPIClient()
     client.session.headers["X-No-Count"] = "true"
     page_size = getattr(self.model._meta, "page_size", 50)
     page_number = 1
     while True:
         page = client.get(
             self.resource_type,
             filters=self._filters,
             include=self._include or None,
             fields=self._fields,
             sort=self._sort,
             page_size=page_size,
             page_number=page_number,
         )
         included = page.get("included") or []
         data = page.get("data")
         page_number += 1
         self.model.from_resources(included)
         yield from self.model.from_resources(data)
         next_url = page.get("links", {}).get("next")
         if next_url is None:
             break
Beispiel #11
0
class JSONAPIManager:
    def __init__(self, model, **kwargs):
        self.client = JSONAPIClient()
        self.model = model
        self._fields = kwargs.get("fields", {})
        self._include = kwargs.get("include", [])
        self._filters = kwargs.get("filters", {})
        self._sort = kwargs.get("sort", [])
        self._cache = None

    def modify(self, **kwargs) -> "JSONAPIManager":
        _fields = {
            **self._fields,
            **kwargs.get("fields", {}),
        }
        _filters = {
            **self._filters,
            **kwargs.get("filters", {}),
        }
        _include = deepcopy(self._include)
        _include.extend(list(kwargs.get("include", [])))
        _sort = deepcopy(self._sort)
        _sort.extend(list(kwargs.get("sort", [])))
        return JSONAPIManager(
            model=self.model,
            fields=_fields,
            filters=_filters,
            include=_include,
            sort=_sort,
        )

    def sort(self, *args) -> "JSONAPIManager":
        return self.modify(sort=args)

    def filter(self, **kwargs) -> "JSONAPIManager":
        return self.modify(filters=kwargs)

    def include(self, *args) -> "JSONAPIManager":
        return self.modify(include=args)

    def fields(self, **kwargs) -> "JSONAPIManager":
        return self.modify(fields=kwargs)

    @property
    def resource_type(self) -> str:
        return self.model._meta.resource_type

    def _fetch_get(self, resource_id: Union[str, int] = None) -> dict:
        return self.client.get(
            self.resource_type,
            resource_id=resource_id,
            filters=self._filters,
            include=self._include or None,
            fields=self._fields,
            sort=self._sort,
        )

    def _fetch_iterate(self) -> Iterator:
        client = JSONAPIClient()
        client.session.headers["X-No-Count"] = "true"
        page_size = getattr(self.model._meta, "page_size", 50)
        page_number = 1
        while True:
            page = client.get(
                self.resource_type,
                filters=self._filters,
                include=self._include or None,
                fields=self._fields,
                sort=self._sort,
                page_size=page_size,
                page_number=page_number,
            )
            included = page.get("included") or []
            data = page.get("data")
            page_number += 1
            self.model.from_resources(included)
            yield from self.model.from_resources(data)
            next_url = page.get("links", {}).get("next")
            if next_url is None:
                break

    def _fetch_all(self) -> List["JSONAPIModel"]:  # noqa
        if self._cache is None:
            self._cache = list(self._fetch_iterate())
        return self._cache

    def count(self) -> int:
        data = self.client.get(
            self.resource_type,
            include=[],
            fields={self.resource_type: []},
            filters=self._filters,
            page_size=1,
        )
        return data.get("meta", {}).get("record_count")

    def iterator(self) -> Iterator["JSONAPIModel"]:  # noqa
        return self._fetch_iterate()

    def all(self) -> List["JSONAPIModel"]:  # noqa
        return self._fetch_all()

    def get(self, pk, ignore_cache=False) -> "JSONAPIModel":  # noqa
        record = self.model.from_cache(pk)
        if record is None or ignore_cache:
            document = self._fetch_get(resource_id=pk)
            data = document["data"]
            record = self.model.from_resource(data)
            self.model.from_resources(document.get("included") or [])
        return record

    def __getitem__(self, k) -> "JSONAPIModel":  # noqa
        self._fetch_all()
        return self._cache[k]

    def __iter__(self) -> Iterator["JSONAPIModel"]:  # noqa
        self._fetch_all()
        return iter(self._cache)

    def __bool__(self: "JSONAPIManager") -> bool:
        self._fetch_all()
        return bool(self._cache)
Beispiel #12
0
def test_jsonapi_get_unresolved_resource():
    client = JSONAPIClient()
    with pytest.raises(JSONAPIClientError,
                       match=r'Cannot resolve resource "unresolvable"'):
        client.get("unresolvable")