Example #1
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
Example #2
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