from typing import Optional

from complexheart.domain.criteria import Criteria
from sqlalchemy import create_engine
from sqlalchemy.engine import Engine
from sqlalchemy.orm import sessionmaker

from to_do_list.tasks.domain.models import Task
from to_do_list.tasks.infrastructure.persistence.relational import RelationalTaskRepository, DBInstaller

db_engine: Optional[Engine] = None


def setup_function():
    global db_engine
    db_engine = create_engine('sqlite:///:memory:')
    DBInstaller(db_engine).install()


def test_repository_should_save_new_task_successfully(task_factory):
    session = sessionmaker(bind=db_engine)()

    repository = RelationalTaskRepository(session)
    task = repository.save(task_factory({}))

    assert session.query(Task).get(task.id)


def test_repository_should_find_task_successfully(task_factory):
    session = sessionmaker(bind=db_engine)()

    repository = RelationalTaskRepository(session)
    task = repository.save(task_factory({}))

    assert repository.find(task.id)


def test_repository_should_match_task_by_criteria_successfully(task_factory):
    session = sessionmaker(bind=db_engine)()

    repository = RelationalTaskRepository(session)

    for i in range(11):
        repository.save(task_factory({'description': 'My task {i}'.format(i=i)}))

    tasks = repository.match(
        Criteria() \
            .filter('description', 'like', '%task 1%') \
            .order_by(['id'])
    )

    for task in tasks:
        assert isinstance(task, Task)
    assert len(tasks) == 2


def test_repository_should_get_all_tasks_successfully(task_factory):
    session = sessionmaker(bind=db_engine)()

    repository = RelationalTaskRepository(session)

    for i in range(10):
        repository.save(task_factory({'description': 'My task {i}'.format(i=i)}))

    tasks = repository.all()

    for task in tasks:
        assert isinstance(task, Task)
    assert len(tasks) == 10

[((444, 479), 'sqlalchemy.create_engine', 'create_engine', (['"""sqlite:///:memory:"""'], {}), "('sqlite:///:memory:')\n", (457, 479), False, 'from sqlalchemy import create_engine\n'), ((651, 684), 'to_do_list.tasks.infrastructure.persistence.relational.RelationalTaskRepository', 'RelationalTaskRepository', (['session'], {}), '(session)\n', (675, 684), False, 'from to_do_list.tasks.infrastructure.persistence.relational import RelationalTaskRepository, DBInstaller\n'), ((905, 938), 'to_do_list.tasks.infrastructure.persistence.relational.RelationalTaskRepository', 'RelationalTaskRepository', (['session'], {}), '(session)\n', (929, 938), False, 'from to_do_list.tasks.infrastructure.persistence.relational import RelationalTaskRepository, DBInstaller\n'), ((1164, 1197), 'to_do_list.tasks.infrastructure.persistence.relational.RelationalTaskRepository', 'RelationalTaskRepository', (['session'], {}), '(session)\n', (1188, 1197), False, 'from to_do_list.tasks.infrastructure.persistence.relational import RelationalTaskRepository, DBInstaller\n'), ((1673, 1706), 'to_do_list.tasks.infrastructure.persistence.relational.RelationalTaskRepository', 'RelationalTaskRepository', (['session'], {}), '(session)\n', (1697, 1706), False, 'from to_do_list.tasks.infrastructure.persistence.relational import RelationalTaskRepository, DBInstaller\n'), ((602, 630), 'sqlalchemy.orm.sessionmaker', 'sessionmaker', ([], {'bind': 'db_engine'}), '(bind=db_engine)\n', (614, 630), False, 'from sqlalchemy.orm import sessionmaker\n'), ((856, 884), 'sqlalchemy.orm.sessionmaker', 'sessionmaker', ([], {'bind': 'db_engine'}), '(bind=db_engine)\n', (868, 884), False, 'from sqlalchemy.orm import sessionmaker\n'), ((1115, 1143), 'sqlalchemy.orm.sessionmaker', 'sessionmaker', ([], {'bind': 'db_engine'}), '(bind=db_engine)\n', (1127, 1143), False, 'from sqlalchemy.orm import sessionmaker\n'), ((1624, 1652), 'sqlalchemy.orm.sessionmaker', 'sessionmaker', ([], {'bind': 'db_engine'}), '(bind=db_engine)\n', (1636, 1652), False, 'from sqlalchemy.orm import sessionmaker\n'), ((484, 506), 'to_do_list.tasks.infrastructure.persistence.relational.DBInstaller', 'DBInstaller', (['db_engine'], {}), '(db_engine)\n', (495, 506), False, 'from to_do_list.tasks.infrastructure.persistence.relational import RelationalTaskRepository, DBInstaller\n'), ((1344, 1354), 'complexheart.domain.criteria.Criteria', 'Criteria', ([], {}), '()\n', (1352, 1354), False, 'from complexheart.domain.criteria import Criteria\n')]