Exemplo n.º 1
0
def test_invalid_subresource_path_fail():
    """Ensure a bad subresource path fails."""
    query_params = {"album.tracks._sorts_.failhere": "track_id,-name"}
    parser = ModelQueryParamParser(query_params)
    with raises(ParseError) as excinfo:
        parser.parse_subfilters()
    assert excinfo.value.code == "invalid_subresource_path"
Exemplo n.º 2
0
def test_parse_simple_subquery_fail():
    """Test a simple subquery fails with invalid input."""
    query_params = {"tracks._subquery_": 5}
    parser = ModelQueryParamParser(query_params)
    with raises(FilterParseError) as excinfo:
        parser.parse_subfilters()
    assert excinfo.value.code == "invalid_complex_filters"
Exemplo n.º 3
0
def test_suboffset_parser_bad_value_fail():
    """Ensure basic suboffset parsing fails appropriately."""
    query_params = {"album.tracks._offset_": "test"}
    parser = ModelQueryParamParser(query_params)
    with raises(OffsetLimitParseError) as excinfo:
        parser.parse_subfilters()
    assert excinfo.value.code == "invalid_suboffset_value"
Exemplo n.º 4
0
def test_parse_simple_subquery():
    """Test a simple subquery is handled properly."""
    query_params = {"tracks._subquery_.playlists.playlist_id": 5}
    parser = ModelQueryParamParser(query_params)
    result = parser.parse_subfilters()
    filters = result["tracks"].filters
    assert filters["$and"][0]["playlists.playlist_id"]["$eq"] == 5
Exemplo n.º 5
0
def test_subfilter_parser():
    """Ensure basic subfilter parsing works."""
    query_params = {"album.tracks._subquery_": '{"track_id": 5}'}
    parser = ModelQueryParamParser(query_params)
    result = parser.parse_subfilters()
    expected_result = {"$and": [{"track_id": 5}]}
    assert expected_result == result["album.tracks"].filters
Exemplo n.º 6
0
def test_parse_complex_subquery():
    """Test a complex subquery is handled properly."""
    query_params = {
        "tracks._subquery_.playlists": json.dumps({"playlist_id": 5})
    }
    parser = ModelQueryParamParser(query_params)
    result = parser.parse_subfilters()
    filters = result["tracks"].filters
    assert filters["$and"][0]["playlists"]["playlist_id"] == 5
Exemplo n.º 7
0
def test_subsorts_parser():
    """Ensure basic subsorts parsing works."""
    query_params = {"album.tracks._sorts_": "track_id,-name"}
    parser = ModelQueryParamParser(query_params)
    result = parser.parse_subfilters()
    assert len(result["album.tracks"].sorts) == 2
    assert result["album.tracks"].sorts[0].attr == "track_id"
    assert result["album.tracks"].sorts[0].direction == "ASC"
    assert result["album.tracks"].sorts[1].attr == "name"
    assert result["album.tracks"].sorts[1].direction == "DESC"
Exemplo n.º 8
0
 def test_subresource_nested_query(db_session):
     """Ensure a simple subresource query works."""
     query_params = {
         "tracks._subquery_.track_id-gte": 5,
         "tracks.playlists._subquery_.playlist_id-lte": 5
     }
     parser = ModelQueryParamParser(query_params)
     album_resource = AlbumResource(session=db_session)
     result = album_resource.get_collection(
         subfilters=parser.parse_subfilters(), embeds=parser.parse_embeds())
     success = False
     for album in result:
         if album["album_id"] == 3:
             assert len(album["tracks"]) == 1
             assert album["tracks"][0]["track_id"] == 5
             success = True
     assert success
Exemplo n.º 9
0
def test_invalid_subresource_path_ignore():
    """Ensure silent failure on subresource path when not strict."""
    query_params = {"album.tracks._sorts_.failhere": "track_id,-name"}
    parser = ModelQueryParamParser(query_params)
    result = parser.parse_subfilters(strict=False)
    assert len(result) == 0
Exemplo n.º 10
0
def test_suboffset_parser():
    """Ensure basic suboffset parsing works."""
    query_params = {"album.tracks._offset_": 5}
    parser = ModelQueryParamParser(query_params)
    result = parser.parse_subfilters()
    assert result["album.tracks"].offset == 5
Exemplo n.º 11
0
def test_sublimit_parser_bad_value_ignore():
    """Ensure non strict basic sublimit parsing ignores errors."""
    query_params = {"album.tracks._limit_": "test", "album.tracks._offset_": 5}
    parser = ModelQueryParamParser(query_params)
    result = parser.parse_subfilters(strict=False)
    assert result["album.tracks"].offset == 5
Exemplo n.º 12
0
    def get(self, path, query_params=None, strict=True, head=False):
        """Generic API router for GET requests.

        :param str path: The resource path specified. This should not
            include the root ``/api`` or any versioning info.
        :param query_params: Dictionary of query parameters, likely
            provided as part of a request. Defaults to an empty dict.
        :type query_params: dict or None
        :param bool strict: If ``True``, bad query params will raise
            non fatal errors rather than ignoring them.
        :param bool head: ``True`` if this was a HEAD request.
        :return: If this is a single entity query, an individual
            resource or ``None``. If this is a collection query, a
            list of resources. If it's an instance field query, the
            raw field value.
        :raise ResourceNotFoundError: If no resource can be found at
            the provided path.
        :raise BadRequestError: Invalid filters, sorts, fields,
            embeds, offset, or limit as defined in the provided query
            params will result in a raised exception if strict is set
            to ``True``.

        """
        if self.resource is None:
            self._deduce_resource(path)
        path_objs = self._get_path_objects(path)
        resource = path_objs.get("resource", None)
        path_part = path_objs.get("path_part", None)
        query_session = path_objs.get("query_session", None)
        ident = path_objs.get("ident", None)
        parser = ModelQueryParamParser(query_params, context=self.context)
        fields = parser.parse_fields()
        embeds = parser.parse_embeds()
        try:
            subfilters = parser.parse_subfilters(strict=strict)
        except ParseError as exc:
            if strict:
                raise BadRequestError(code=exc.code,
                                      message=exc.message,
                                      **exc.kwargs)
            subfilters = None
        # last path_part determines what type of request this is
        if isinstance(path_part, Field) and not isinstance(
                path_part, NestedPermissibleABC):
            # Simple property, such as album_id
            # return only the value
            field_name = path_part.data_key or path_part.name
            result = resource.get(ident=ident,
                                  fields=[field_name],
                                  strict=strict,
                                  session=query_session,
                                  head=head)
            if result is not None and field_name in result:
                return result[field_name]
            raise self.make_error("resource_not_found",
                                  path=path)  # pragma: no cover
        if isinstance(path_part, Field) or isinstance(path_part,
                                                      BaseModelResource):
            # resource collection
            # any non subresource field would already have been handled
            try:
                filters = parser.parse_filters(
                    resource.model,
                    convert_key_names_func=resource.convert_key_name)
            except FilterParseError as e:
                if strict:
                    raise BadRequestError(code=e.code,
                                          message=e.message,
                                          **e.kwargs)
                filters = None
            if not (isinstance(path_part, Nested) and not path_part.many):
                try:
                    offset_limit_info = parser.parse_offset_limit(
                        resource.page_max_size)
                    offset = offset_limit_info.offset
                    limit = offset_limit_info.limit
                except OffsetLimitParseError as e:
                    if strict:
                        raise BadRequestError(code=e.code,
                                              message=e.message,
                                              **e.kwargs)
                    offset, limit = None, None
                sorts = parser.parse_sorts()
                results = resource.get_collection(filters=filters,
                                                  subfilters=subfilters,
                                                  fields=fields,
                                                  embeds=embeds,
                                                  sorts=sorts,
                                                  offset=offset,
                                                  limit=limit,
                                                  session=query_session,
                                                  strict=strict,
                                                  head=head)
                if query_params.get("page") is not None or not offset:
                    results.current_page = int(query_params.get("page") or 1)
                    results.page_size = limit or resource.page_max_size
                return results
            else:
                result = resource.get_collection(fields=fields,
                                                 embeds=embeds,
                                                 subfilters=subfilters,
                                                 session=query_session,
                                                 strict=strict,
                                                 head=head)
                if len(result) != 1:  # pragma: no cover
                    # failsafe, _get_path_objects will catch this first.
                    raise self.make_error("resource_not_found", path=path)
                return result[0]
        elif isinstance(path_part, tuple):
            # path part is a resource identifier
            # individual instance
            return resource.get(ident=path_part,
                                fields=fields,
                                embeds=embeds,
                                subfilters=subfilters,
                                strict=strict,
                                session=query_session,
                                head=head)
        raise self.make_error("resource_not_found",
                              path=path)  # pragma: no cover