# Path: aiohttp_json_api/errors.py
# class ResourceNotFound(HTTPNotFound):
#     """
#     JSON API resource not found error. HTTP 404 Not found.
# 
#     Raised, if a resource does not exist.
#     """
# 
#     def __init__(self, type, id, **kwargs):
#         """
#         Resource not found error initializer.
# 
#         :param type: Type of resource
#         :param id: Resource identifier
#         :param kwargs: Additional arguments to base error
#         """
#         kwargs.setdefault(
#             "detail",
#             f"The resource (type='{type}', id='{id}') does not exist."
#         )
#         super(ResourceNotFound, self).__init__(**kwargs)
# 
# Path: aiohttp_json_api/controller.py
# class DefaultController(ControllerABC):
#     @staticmethod
#     async def default_include(field, resources, **kwargs):
#         if field.mapped_key:
#             ctx = kwargs['context']
#             compound_documents = []
#             for resource in resources:
#                 compound_document = getattr(resource, field.mapped_key)
#                 if compound_document:
#                     compound_documents.extend(
#                         (compound_document,)
#                         if type(compound_document) in ctx.registry
#                         else compound_document
#                     )
#             return compound_documents
#         raise RuntimeError('No includer and mapped_key have been defined.')
# 
#     @staticmethod
#     async def default_query(field, resource, **kwargs):
#         if field.mapped_key:
#             return getattr(resource, field.mapped_key)
#         raise RuntimeError('No query method and mapped_key have been defined.')
# 
#     @staticmethod
#     async def default_add(field, resource, data, sp, **kwargs):
#         logger.warning('You should override the adder.')
# 
#         if not field.mapped_key:
#             raise RuntimeError('No adder and mapped_key have been defined.')
# 
#         relatives = getattr(resource, field.mapped_key)
#         relatives.extend(data)
# 
#     @staticmethod
#     async def default_remove(field, resource, data, sp, **kwargs):
#         logger.warning('You should override the remover.')
# 
#         if not field.mapped_key:
#             raise RuntimeError('No remover and mapped_key have been defined.')
# 
#         relatives = getattr(resource, field.mapped_key)
#         for relative in data:
#             try:
#                 relatives.remove(relative)
#             except ValueError:
#                 pass
# 
#     async def update_resource(self, resource, data, sp, **kwargs):
#         updated_resource = copy.deepcopy(resource)
#         for key, (field_data, sp) in data.items():
#             field = self.ctx.schema.get_field(key)
#             await self.ctx.schema.set_value(field, updated_resource,
#                                             field_data, sp, **kwargs)
# 
#         return resource, updated_resource
# 
#     async def update_relationship(self, field, resource, data, sp, **kwargs):
#         updated_resource = copy.deepcopy(resource)
#         await self.ctx.schema.set_value(field, updated_resource, data, sp,
#                                         **kwargs)
#         return resource, updated_resource
# 
#     async def add_relationship(self, field, resource, data, sp, **kwargs):
#         updated_resource = copy.deepcopy(resource)
#         adder, adder_kwargs = first(
#             get_processors(self, Tag.ADD, field, self.default_add)
#         )
#         await adder(field, updated_resource, data, sp,
#                     **adder_kwargs, **kwargs)
#         return resource, updated_resource
# 
#     async def remove_relationship(self, field, resource, data, sp, **kwargs):
#         updated_resource = copy.deepcopy(resource)
#         remover, remover_kwargs = first(
#             get_processors(self, Tag.REMOVE, field, self.default_remove)
#         )
#         await remover(field, updated_resource, data, sp,
#                       **remover_kwargs, **kwargs)
#         return resource, updated_resource
# 
#     async def query_relatives(self, field, resource, **kwargs):
#         query, query_kwargs = first(
#             get_processors(self, Tag.QUERY, field, self.default_query)
#         )
#         return await query(field, resource, **query_kwargs, **kwargs)
# 
#     async def fetch_compound_documents(self, field, resources, **kwargs):
#         include, include_kwargs = first(
#             get_processors(self, Tag.INCLUDE, field, self.default_include)
#         )
#         return await include(field, resources, context=self.ctx,
#                              **include_kwargs, **kwargs)
# 
# Path: examples/simple/models.py
# class People(BaseModel):
#     def __init__(self, id: int, first_name: str, last_name: str,
#                  twitter: str = None):
#         super().__init__(id)
#         self.first_name = first_name
#         self.last_name = last_name
#         self.twitter = twitter
# 
#     def __repr__(self):
#         return self._repr(('id', 'first_name', 'last_name', 'twitter'))
# 
#     @staticmethod
#     def populate(count=100) -> Generator['People', None, None]:
#         import mimesis
# 
#         person = mimesis.Person()
# 
#         return (
#             People(id=int(person.identifier('####')), first_name=person.name(),
#                    last_name=person.surname(), twitter=person.username())
#             for _ in range(count)
#         )


import logging
import random
from aiohttp_json_api.errors import ResourceNotFound
from aiohttp_json_api.controller import DefaultController
from examples.simple.models import People


logger = logging.getLogger()


class SimpleController(DefaultController):
    @property
    def storage(self):
        """Shortcut for application simple storage"""
        return self.ctx.app['storage']

    async def fetch_resource(self, resource_id, **kwargs):
        rid = self.ctx.registry.ensure_identifier(
            {'type': self.ctx.resource_type, 'id': resource_id}
        )
        result = self.storage[rid.type].get(rid.id)
        if result is None:

# Path: aiohttp_json_api/errors.py
# class ResourceNotFound(HTTPNotFound):
#     """
#     JSON API resource not found error. HTTP 404 Not found.
# 
#     Raised, if a resource does not exist.
#     """
# 
#     def __init__(self, type, id, **kwargs):
#         """
#         Resource not found error initializer.
# 
#         :param type: Type of resource
#         :param id: Resource identifier
#         :param kwargs: Additional arguments to base error
#         """
#         kwargs.setdefault(
#             "detail",
#             f"The resource (type='{type}', id='{id}') does not exist."
#         )
#         super(ResourceNotFound, self).__init__(**kwargs)
# 
# Path: aiohttp_json_api/controller.py
# class DefaultController(ControllerABC):
#     @staticmethod
#     async def default_include(field, resources, **kwargs):
#         if field.mapped_key:
#             ctx = kwargs['context']
#             compound_documents = []
#             for resource in resources:
#                 compound_document = getattr(resource, field.mapped_key)
#                 if compound_document:
#                     compound_documents.extend(
#                         (compound_document,)
#                         if type(compound_document) in ctx.registry
#                         else compound_document
#                     )
#             return compound_documents
#         raise RuntimeError('No includer and mapped_key have been defined.')
# 
#     @staticmethod
#     async def default_query(field, resource, **kwargs):
#         if field.mapped_key:
#             return getattr(resource, field.mapped_key)
#         raise RuntimeError('No query method and mapped_key have been defined.')
# 
#     @staticmethod
#     async def default_add(field, resource, data, sp, **kwargs):
#         logger.warning('You should override the adder.')
# 
#         if not field.mapped_key:
#             raise RuntimeError('No adder and mapped_key have been defined.')
# 
#         relatives = getattr(resource, field.mapped_key)
#         relatives.extend(data)
# 
#     @staticmethod
#     async def default_remove(field, resource, data, sp, **kwargs):
#         logger.warning('You should override the remover.')
# 
#         if not field.mapped_key:
#             raise RuntimeError('No remover and mapped_key have been defined.')
# 
#         relatives = getattr(resource, field.mapped_key)
#         for relative in data:
#             try:
#                 relatives.remove(relative)
#             except ValueError:
#                 pass
# 
#     async def update_resource(self, resource, data, sp, **kwargs):
#         updated_resource = copy.deepcopy(resource)
#         for key, (field_data, sp) in data.items():
#             field = self.ctx.schema.get_field(key)
#             await self.ctx.schema.set_value(field, updated_resource,
#                                             field_data, sp, **kwargs)
# 
#         return resource, updated_resource
# 
#     async def update_relationship(self, field, resource, data, sp, **kwargs):
#         updated_resource = copy.deepcopy(resource)
#         await self.ctx.schema.set_value(field, updated_resource, data, sp,
#                                         **kwargs)
#         return resource, updated_resource
# 
#     async def add_relationship(self, field, resource, data, sp, **kwargs):
#         updated_resource = copy.deepcopy(resource)
#         adder, adder_kwargs = first(
#             get_processors(self, Tag.ADD, field, self.default_add)
#         )
#         await adder(field, updated_resource, data, sp,
#                     **adder_kwargs, **kwargs)
#         return resource, updated_resource
# 
#     async def remove_relationship(self, field, resource, data, sp, **kwargs):
#         updated_resource = copy.deepcopy(resource)
#         remover, remover_kwargs = first(
#             get_processors(self, Tag.REMOVE, field, self.default_remove)
#         )
#         await remover(field, updated_resource, data, sp,
#                       **remover_kwargs, **kwargs)
#         return resource, updated_resource
# 
#     async def query_relatives(self, field, resource, **kwargs):
#         query, query_kwargs = first(
#             get_processors(self, Tag.QUERY, field, self.default_query)
#         )
#         return await query(field, resource, **query_kwargs, **kwargs)
# 
#     async def fetch_compound_documents(self, field, resources, **kwargs):
#         include, include_kwargs = first(
#             get_processors(self, Tag.INCLUDE, field, self.default_include)
#         )
#         return await include(field, resources, context=self.ctx,
#                              **include_kwargs, **kwargs)
# 
# Path: examples/simple/models.py
# class People(BaseModel):
#     def __init__(self, id: int, first_name: str, last_name: str,
#                  twitter: str = None):
#         super().__init__(id)
#         self.first_name = first_name
#         self.last_name = last_name
#         self.twitter = twitter
# 
#     def __repr__(self):
#         return self._repr(('id', 'first_name', 'last_name', 'twitter'))
# 
#     @staticmethod
#     def populate(count=100) -> Generator['People', None, None]:
#         import mimesis
# 
#         person = mimesis.Person()
# 
#         return (
#             People(id=int(person.identifier('####')), first_name=person.name(),
#                    last_name=person.surname(), twitter=person.username())
#             for _ in range(count)
#         )


# Path: examples/simple/controllers.py
import logging
import random
from aiohttp_json_api.errors import ResourceNotFound
from aiohttp_json_api.controller import DefaultController
from examples.simple.models import People



logger = logging.getLogger()


class SimpleController(DefaultController):
    @property
    def storage(self):
        """Shortcut for application simple storage"""
        return self.ctx.app['storage']

    async def fetch_resource(self, resource_id, **kwargs):
        rid = self.ctx.registry.ensure_identifier(
            {'type': self.ctx.resource_type, 'id': resource_id}
        )
        result = self.storage[rid.type].get(rid.id)
        if result is None:

            raise ResourceNotFound(self.ctx.resource_type, resource_id)