Skip to content
This repository was archived by the owner on Apr 29, 2025. It is now read-only.
This repository was archived by the owner on Apr 29, 2025. It is now read-only.

Using Archive recipe and filtering #146

@matdrapeau

Description

@matdrapeau

In order to use soft-deletes, I tried to used the recipe (https://potion.readthedocs.io/en/latest/recipes.html#archivingresource) but filtering resources are not working anymore.

from flask_potion import ModelResource, fields
from flask_potion.contrib.alchemy import SQLAlchemyManager
from flask_potion.exceptions import ItemNotFound
from flask_potion.routes import Route
from flask_potion.instances import Instances
from enum import Enum

class BaseResource(ModelResource):
    class Meta:
        read_only_fields = ['create_date', 'update_date']
    class Schema:
        create_date = fields.DateTimeString()
        update_date = fields.DateTimeString()



class Location(Enum):
    ARCHIVE_ONLY = 1
    INSTANCES_ONLY = 2
    BOTH = 3


class ArchiveManager(SQLAlchemyManager):
    def _query(self, source=Location.INSTANCES_ONLY):
        query = super(ArchiveManager, self)._query()

        if source == Location.BOTH:
            return query
        elif source == Location.ARCHIVE_ONLY:
            return query.filter(getattr(self.model, 'is_archived') == True)
        else:
            return query.filter(getattr(self.model, 'is_archived') == False)

    def instances(self, where=None, sort=None, source=Location.INSTANCES_ONLY):
        query = self._query(source)
        if where:
            expressions = [self._expression_for_condition(condition) for condition in where]
            query = self._query_filter(query, self._and_expression(expressions))
        if sort:
            query = self._query_order_by(query, sort)
        return query

    def archive_instances(self, page, per_page, where=None, sort=None):
        return self.instances(where=where, sort=sort, source=Location.ARCHIVE_ONLY).paginate(page=page, per_page=per_page)

    def read(self, id, source=Location.INSTANCES_ONLY):
        query = self._query(source)
        if query is None:
            raise ItemNotFound(self.resource, id=id)
        return self._query_filter_by_id(query, id)


class ArchivingResource(BaseResource):
    class Meta:
        manager = ArchiveManager
        exclude_routes = ['destroy'] # we're using rel="archive" instead.

    class Schema(BaseResource.Schema):
        is_archived = fields.Boolean(io='r')

    @Route.GET('/<int:id>', rel="self", attribute="instance")
    def read(self, id) -> fields.Inline('self'):
        return self.manager.read(id, source=Location.BOTH)

    @read.PATCH(rel="update")
    def update(self, properties, id):
        item = self.manager.read(id, source=Location.INSTANCES_ONLY)
        updated_item = self.manager.update(item, properties)
        return updated_item

    update.response_schema = update.request_schema = fields.Inline('self', patchable=True)

    @update.DELETE(rel="archive")
    def destroy(self, id):
        item = self.manager.read(id, source=Location.INSTANCES_ONLY)
        self.manager.update(item, {"is_archived": True})
        return None, 204

    @Route.GET("/archive")
    def archive_instances(self, **kwargs):
        return self.manager.archive_instances(**kwargs)

    archive_instances.request_schema = archive_instances.response_schema = Instances()

    @Route.GET('/archive/<int:id>', rel="readArchived")
    def read_archive(self, id) -> fields.Inline('self'):
        return self.manager.read(id, source=Location.ARCHIVE_ONLY)

    @Route.POST('/archive/<int:id>/restore', rel="restoreFromArchive")
    def restore_from_archive(self, id) -> fields.Inline('self'):
        item = self.manager.read(id, source=Location.ARCHIVE_ONLY)
        return self.manager.update(item, {"is_archived": False})


class Base(object):
    id = Column(Integer, primary_key=True, autoincrement=True)
    create_date = Column(DateTime(timezone=True), server_default=func.now())
    update_date = Column(DateTime(timezone=True), onupdate=func.now())
    is_archived = Column(Boolean, default=False)

Base = declarative_base(cls=Base)

class User(Base):
    __tablename__ = 'users'
    name = Column(String(), nullable=True)

class UserResource(ArchivingResource):
    class Meta(ArchivingResource.Meta):
        model = User
        natural_key = ('organization_id', 'foreign_id')
        #write_only_fields = ['organization_id']
    class Schema(ArchivingResource.Schema):
        name = fields.String()

app.api.add_resource(UserResource)

Doing such filters are raising errors:
/users?where={"create_date": {"$gt": "2018-06-10T14:56:15-05:00"}}
/users/archive?where={"create_date": {"$gt": "2018-06-10T14:56:15-05:00"}}

I get: ValidationError {'$gt': '2018-06-10T14:56:15-05:00'} is not valid under any of the given schemas

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions