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

[((16, 16, 16, 51), 'sqlalchemy.create_engine', 'create_engine', ({(16, 30, 16, 50): '"""sqlite:///:memory:"""'}, {}), "('sqlite:///:memory:')", False, 'from sqlalchemy import create_engine\n'), ((23, 17, 23, 50), 'to_do_list.tasks.infrastructure.persistence.relational.RelationalTaskRepository', 'RelationalTaskRepository', ({(23, 42, 23, 49): 'session'}, {}), '(session)', False, 'from to_do_list.tasks.infrastructure.persistence.relational import RelationalTaskRepository, DBInstaller\n'), ((32, 17, 32, 50), 'to_do_list.tasks.infrastructure.persistence.relational.RelationalTaskRepository', 'RelationalTaskRepository', ({(32, 42, 32, 49): 'session'}, {}), '(session)', False, 'from to_do_list.tasks.infrastructure.persistence.relational import RelationalTaskRepository, DBInstaller\n'), ((41, 17, 41, 50), 'to_do_list.tasks.infrastructure.persistence.relational.RelationalTaskRepository', 'RelationalTaskRepository', ({(41, 42, 41, 49): 'session'}, {}), '(session)', False, 'from to_do_list.tasks.infrastructure.persistence.relational import RelationalTaskRepository, DBInstaller\n'), ((60, 17, 60, 50), 'to_do_list.tasks.infrastructure.persistence.relational.RelationalTaskRepository', 'RelationalTaskRepository', ({(60, 42, 60, 49): 'session'}, {}), '(session)', False, 'from to_do_list.tasks.infrastructure.persistence.relational import RelationalTaskRepository, DBInstaller\n'), ((21, 14, 21, 42), 'sqlalchemy.orm.sessionmaker', 'sessionmaker', (), '', False, 'from sqlalchemy.orm import sessionmaker\n'), ((30, 14, 30, 42), 'sqlalchemy.orm.sessionmaker', 'sessionmaker', (), '', False, 'from sqlalchemy.orm import sessionmaker\n'), ((39, 14, 39, 42), 'sqlalchemy.orm.sessionmaker', 'sessionmaker', (), '', False, 'from sqlalchemy.orm import sessionmaker\n'), ((58, 14, 58, 42), 'sqlalchemy.orm.sessionmaker', 'sessionmaker', (), '', False, 'from sqlalchemy.orm import sessionmaker\n'), ((17, 4, 17, 26), 'to_do_list.tasks.infrastructure.persistence.relational.DBInstaller', 'DBInstaller', ({(17, 16, 17, 25): 'db_engine'}, {}), '(db_engine)', False, 'from to_do_list.tasks.infrastructure.persistence.relational import RelationalTaskRepository, DBInstaller\n'), ((47, 8, 47, 18), 'complexheart.domain.criteria.Criteria', 'Criteria', ({}, {}), '()', False, 'from complexheart.domain.criteria import Criteria\n')]