# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['service_repository',
 'service_repository.filters',
 'service_repository.interfaces',
 'service_repository.repositories']

package_data = \
{'': ['*']}

install_requires = \
['six>=1.16.0,<2.0.0']

setup_kwargs = {
    'name': 'service-repository',
    'version': '0.1.2',
    'description': 'Simple service layer with repository to SQLAlchemy or MongoDB',
    'long_description': '# Service layer and repository for SQLAlchemy or MongoDB (asynchronous)\n\nSimple service layer with repository to SQLAlchemy with SQLModel or MongoDB with Motor.\n\nInherit the usual service methods:\n`pagination`, `create`, `get`, `update`, `delete`, `count`\n\n## Installation\n\n<div class="termy">\n\n```console\n$ pip install service-repository\n\n---> 100%\n```\n\n</div>\n\n## With SQLAlchemy\n\nCreate the model, as in the example [song/models.py](tests/song/models.py)\n\nCreate and extend of `BaseRepositorySqlalchemy` in you repository, as in the example [song/repositories.py](tests/song/repositories.py)\n\nCreate and extend you service, as in the example [song/services.py](tests/song/services.py)\n\nThe following is an example with the connection session, but pass the session as needed.\n\n```python\nimport pytest\nfrom sqlalchemy.ext.asyncio import AsyncSession, create_async_engine\nfrom sqlalchemy.orm import sessionmaker\nfrom sqlmodel import SQLModel\n\n\n# Get you connection session of SQLAlchemy, example next, but make as you\n@pytest.fixture()\nasync def sqlalchemy():\n    SQLALCHEMY_DATABASE_URI = "sqlite+aiosqlite:///./tests/testing.db"\n    engine = create_async_engine(\n        SQLALCHEMY_DATABASE_URI, future=True, echo=True\n    )\n    async_session = sessionmaker(\n        bind=engine, expire_on_commit=False, class_=AsyncSession\n    )\n    async with engine.begin() as conn:\n        await conn.run_sync(SQLModel.metadata.create_all)\n        yield async_session\n        await conn.run_sync(SQLModel.metadata.drop_all)\n```\n\nThe following is an example with register created.\n\n```python\nimport pytest\nfrom tests.song.services import SongService\nfrom tests.song.models import SongCreate\n\n\n@pytest.fixture\nasync def song_one(sqlalchemy):\n    song_create = {\n        "title": "Song title 1",\n        "is_active": True,\n    }\n    \n    async with sqlalchemy() as session:\n        song = await SongService(db=session).create(\n            schema_in=SongCreate(**song_create)\n        )\n    return song\n```\n\n#### Pagination with dynamic filter and sorting in the service.\n\n```python\nimport pytest\nfrom tests.song.services import SongService\n\n\n@pytest.mark.asyncio\nasync def test_song_service_with_or_and_asc_filter_paginate_song(sqlalchemy):\n    criteria = [\n        {"field": "foo", "op": "ilike", "value": "%bar%"},\n    ]\n    # Or with criteria in format or\n    criteria = [\n        {\n            "or": [\n                {"field": "title", "op": "==", "value": "Song title 2"},\n                {"field": "title", "op": "==", "value": "Song title 3"},\n            ]\n        }\n    ]\n    sort = [\n        {"field": "title", "direction": "asc"},\n    ]\n    async with sqlalchemy() as session:\n        pagination = await SongService(db=session).paginate(\n            page=1, per_page=5, criteria=criteria, sort=sort\n        )\n```\n\nOperator options for filtering are:\n\n`is_null, is_not_null, eq, ne, gt, lt, ge, le, like, ilike, not_ilike, in, not_in, any, not_any`\n\n#### Use the create extended method on service\n\n```python\nimport pytest\nfrom tests.song.services import SongService\nfrom tests.song.models import SongCreate\n\n\n@pytest.mark.asyncio\nasync def test_song_service_create_song(sqlalchemy):\n    song_data_one = {\n        "title": "Song title 1",\n        "is_active": True,\n    }\n    async with sqlalchemy() as session:\n        song = await SongService(db=session).create(\n            schema_in=SongCreate(**song_data_one)\n        )\n```\n\n#### Update method on service\n\n```python\nimport pytest\nfrom tests.song.services import SongService\nfrom tests.song.models import SongUpdate\n\n\n@pytest.mark.asyncio\nasync def test_song_service_update_song(sqlalchemy, song_one):\n    song_data = {\n        "title": "Song title 2",\n        "is_active": False,\n    }\n    async with sqlalchemy() as session:\n        song = await SongService(db=session).update(\n            instance=song_one, schema_in=SongUpdate(**song_data)\n        )\n```\n\n#### Get method on service to get one register\n\n```python\nimport pytest\nfrom tests.song.services import SongService\n\n\n@pytest.mark.asyncio\nasync def test_song_service_get_song(sqlalchemy, song_one):\n    async with sqlalchemy() as session:\n        song = await SongService(db=session).get(id=song_one.id)\n```\n\n#### Delete method on service\n\n```python\nimport pytest\nfrom tests.song.services import SongService\n\n\n@pytest.mark.asyncio\nasync def test_song_service_delete_song(sqlalchemy, song_one):\n    async with sqlalchemy() as session:\n        await SongService(db=session).delete(id=song_one.id)\n```\n\n#### Count method on service\n\n```python\nimport pytest\nfrom tests.song.services import SongService\n\n\n@pytest.mark.asyncio\nasync def test_song_service_count_song(sqlalchemy):\n    async with sqlalchemy() as session:\n        total = await SongService(db=session).count()\n```\n\n## With MongoDB\n\nCreate the model, as in the example [product/models.py](tests/product/models.py)\n\nCreate and extend of `BaseRepositoryMotor` in you repository, as in the example [product/repositories.py](tests/product/repositories.py)\n\nCreate and extend you service, as in the example [product/services.py](tests/product/services.py)\n\nThe following is an example with the connection session, but pass the session as needed.\n\n```python\nimport pytest\nfrom motor.motor_asyncio import AsyncIOMotorClient\n\n\n# Get you connection session of Motor, example next, but make as you\n@pytest.fixture()\nasync def motor():\n    client = AsyncIOMotorClient(\n        "localhost",\n        maxPoolSize=10,\n        minPoolSize=10,\n        tz_aware=True,\n    )\n    await client.drop_database("testing")\n    session = client.get_database("testing")\n    yield session\n```\n\nThe following is an example with register created.\n\n```python\nimport pytest\nfrom tests.product.models import ProductCreate\nfrom tests.product.services import ProductService\n\n\n@pytest.fixture\nasync def product_one(motor, product_data_one):\n    product_data = {\n        "title": "Product title 1",\n        "is_active": True,\n    }\n    product = await ProductService(db=motor).create(\n        schema_in=ProductCreate(**product_data)\n    )\n    return product\n```\n\n#### Pagination with dynamic filter and sorting in the service.\n\n```python\nimport pytest\nfrom tests.product.services import ProductService\n\n\n@pytest.mark.asyncio\nasync def test_product_service_with_or_and_asc_filter_paginate_product(\n    app, motor, product_data_one\n):\n    criteria = {"title": "Product title 1"}\n    sort = [("title", -1)]\n\n    pagination = await ProductService(db=motor).paginate(\n        page=1, per_page=5, criteria=criteria, sort=sort\n    )\n```\n\n#### Use the create extended method on service\n\n```python\nimport pytest\nfrom tests.product.models import ProductCreate\nfrom tests.product.services import ProductService\n\n\n@pytest.mark.asyncio\nasync def test_product_service_create_product(motor):\n    product_data = {\n        "title": "Product title 1",\n        "is_active": True,\n    }\n    product = await ProductService(db=motor).create(\n        schema_in=ProductCreate(**product_data)\n    )\n```\n\n#### Update method on service\n\n```python\nimport pytest\nfrom tests.product.models import ProductUpdate\nfrom tests.product.services import ProductService\n\n\n@pytest.mark.asyncio\nasync def test_product_service_update_product(motor, product_one):\n    product_data = {\n        "title": "Product title 2",\n        "is_active": False,\n    }\n    product = await ProductService(db=motor).update(\n        instance=product_one, schema_in=ProductUpdate(**product_data)\n    )\n```\n\n#### Get method on service to get one register\n\n```python\nimport pytest\nfrom tests.product.services import ProductService\n\n\n@pytest.mark.asyncio\nasync def test_product_service_get_product(motor, product_one):\n    product = await ProductService(db=motor).get(_id=product_one.id)\n```\n\n#### Delete method on service\n\n```python\nimport pytest\nfrom tests.product.services import ProductService\n\n\n@pytest.mark.asyncio\nasync def test_product_service_delete_product(motor, product_one):\n    await ProductService(db=motor).delete(_id=product_one.id)\n```\n\n#### Count method on service\n\n```python\nimport pytest\nfrom tests.product.services import ProductService\n\n\n@pytest.mark.asyncio\nasync def test_product_service_count_product(motor):\n    total = await ProductService(db=motor).count()\n```\n\n### Inherited base service layer with FastApi\n\nYou can create an inherited base service layer and add its methods, \nas in the example in FastApi with convenience methods for 404:\n\n```python\nfrom fastapi import HTTPException, status\nfrom pydantic import BaseModel\nfrom service_repository.services import BaseService as Base\n\n\nclass BaseService(Base):\n    """Class representing the base service."""\n    def __init__(self, db) -> None:\n        self.db = db\n\n    async def get_or_404(self, **kwargs):\n        """Get one instance by filter or 404 if not exists."""\n        instance = await self.get(**kwargs)\n        if not instance:\n            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)\n        return instance\n\n    async def update_or_404(self, schema_in: BaseModel, **kwargs):\n        """Update instance or 404 if not exists."""\n        instance = await self.get_or_404(**kwargs)\n        instance = await self.update(instance=instance, schema_in=schema_in)\n        return instance\n\n    async def delete_or_404(self, **kwargs):\n        """Delete one instance by filter or 404 if not exists."""\n        await self.get_or_404(**kwargs)\n        await self.delete(**kwargs)\n```\n\n### Inherited base service layer with Flask\n\nYou can create an inherited base service layer and add its methods, \nas in the example in Flask with convenience methods for 404:\n\n```python\nfrom flask import abort\nfrom pydantic import BaseModel\nfrom service_repository.services import BaseService as Base\n\n\nclass BaseService(Base):\n    """Class representing the base service."""\n    def __init__(self, db) -> None:\n        self.db = db\n\n    async def get_or_404(self, **kwargs):\n        """Get one instance by filter or 404 if not exists."""\n        instance = await self.get(**kwargs)\n        if not instance:\n            raise abort(404)\n        return instance\n\n    async def update_or_404(self, schema_in: BaseModel, **kwargs):\n        """Update instance or 404 if not exists."""\n        instance = await self.get_or_404(**kwargs)\n        instance = await self.update(instance=instance, schema_in=schema_in)\n        return instance\n\n    async def delete_or_404(self, **kwargs):\n        """Delete one instance by filter or 404 if not exists."""\n        await self.get_or_404(**kwargs)\n        await self.delete(**kwargs)\n```\n\n## Security\n\nIf you discover any security related issues, please email fndmiranda@gmail.com instead of using the issue tracker.\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.',
    'author': 'Fernando Miranda',
    'author_email': 'fndmiranda@gmail.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/fndmiranda/service-repository',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.8,<4.0',
}


setup(**setup_kwargs)
