Skip to content

Commit

Permalink
Async db connection (#7)
Browse files Browse the repository at this point in the history
* Async melding create

* Async melding retrieve

* Async melding list

* Use abstract collection instead of list

* Install pytest-asyncio as dev dependency

* Convert tests to async
  • Loading branch information
4c0n authored Feb 14, 2024
1 parent 6097037 commit 6094ec0
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 33 deletions.
14 changes: 8 additions & 6 deletions meldingen_core/actions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from collections.abc import Collection

from meldingen_core.models import Melding
from meldingen_core.repositories import BaseMeldingRepository

Expand All @@ -10,8 +12,8 @@ class MeldingCreateAction:
def __init__(self, repository: BaseMeldingRepository):
self.repository = repository

def __call__(self, melding: Melding) -> None:
self.repository.add(melding)
async def __call__(self, melding: Melding) -> None:
await self.repository.add(melding)


class MeldingListAction:
Expand All @@ -22,8 +24,8 @@ class MeldingListAction:
def __init__(self, repository: BaseMeldingRepository):
self.repository = repository

def __call__(self, *, limit: int | None = None, offset: int | None = None) -> list[Melding]:
return self.repository.list(limit=limit, offset=offset)
async def __call__(self, *, limit: int | None = None, offset: int | None = None) -> Collection[Melding]:
return await self.repository.list(limit=limit, offset=offset)


class MeldingRetrieveAction:
Expand All @@ -34,5 +36,5 @@ class MeldingRetrieveAction:
def __init__(self, repository: BaseMeldingRepository):
self.repository = repository

def __call__(self, pk: int) -> Melding | None:
return self.repository.retrieve(pk=pk)
async def __call__(self, pk: int) -> Melding | None:
return await self.repository.retrieve(pk=pk)
7 changes: 4 additions & 3 deletions meldingen_core/repositories.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from abc import ABCMeta, abstractmethod
from collections.abc import Collection
from typing import Generic, TypeVar

from meldingen_core.models import Melding
Expand All @@ -9,15 +10,15 @@

class BaseRepository(Generic[T, T_co], metaclass=ABCMeta):
@abstractmethod
def add(self, obj: T) -> None:
async def add(self, obj: T) -> None:
...

@abstractmethod
def list(self, *, limit: int | None = None, offset: int | None = None) -> list[T_co]:
async def list(self, *, limit: int | None = None, offset: int | None = None) -> Collection[T_co]:
...

@abstractmethod
def retrieve(self, pk: int) -> T_co | None:
async def retrieve(self, pk: int) -> T_co | None:
...


Expand Down
20 changes: 19 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pytest = "^8.0.0"
mkdocstrings = {version = "^0.24.0", extras = ["python"]}
mkdocs-material = "^9.5.6"
mkdocs-literate-nav = "^0.6.1"
pytest-asyncio = "^0.23.5"

[build-system]
requires = ["poetry-core"]
Expand Down
56 changes: 33 additions & 23 deletions tests/test_meldingen/test_actions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
import pytest_asyncio

from meldingen_core.actions import MeldingCreateAction, MeldingListAction, MeldingRetrieveAction
from meldingen_core.models import Melding
Expand All @@ -15,10 +16,10 @@ class TestMeldingRepository(BaseMeldingRepository):
def __init__(self) -> None:
self.data = []

def add(self, melding: Melding) -> None:
async def add(self, melding: Melding) -> None:
self.data.append(melding)

def list(self, *, limit: int | None = None, offset: int | None = None) -> list[Melding]:
async def list(self, *, limit: int | None = None, offset: int | None = None) -> list[Melding]:
if limit and offset:
return self.data[offset : offset + limit]
elif limit and not offset:
Expand All @@ -28,7 +29,7 @@ def list(self, *, limit: int | None = None, offset: int | None = None) -> list[M
else:
return self.data

def retrieve(self, pk: int) -> Melding | None:
async def retrieve(self, pk: int) -> Melding | None:
for _melding in self.data:
if _melding.text == str(pk):
return _melding
Expand All @@ -38,14 +39,14 @@ def retrieve(self, pk: int) -> Melding | None:
return repository


@pytest.fixture
def populated_meldingen_repository(
@pytest_asyncio.fixture
async def populated_meldingen_repository(
unpopulated_meldingen_repository: BaseMeldingRepository,
) -> BaseMeldingRepository:
for _pk in range(10):
melding = Melding()
melding.text = f"{_pk}"
unpopulated_meldingen_repository.add(melding)
await unpopulated_meldingen_repository.add(melding)

return unpopulated_meldingen_repository

Expand Down Expand Up @@ -75,70 +76,79 @@ def meldingen_retrieve_action(


class TestMeldingCreateAction:
def test_add(self, meldingen_create_action: MeldingCreateAction) -> None:
assert len(meldingen_create_action.repository.list()) == 0
@pytest.mark.asyncio
async def test_add(self, meldingen_create_action: MeldingCreateAction) -> None:
assert len(await meldingen_create_action.repository.list()) == 0

melding = Melding()
melding.text = "1"

meldingen_create_action(melding)
await meldingen_create_action(melding)

assert len(meldingen_create_action.repository.list()) == 1
assert meldingen_create_action.repository.retrieve(pk=1) == melding
assert len(await meldingen_create_action.repository.list()) == 1
assert await meldingen_create_action.repository.retrieve(pk=1) == melding


class TestMeldingListAction:
def test_list_all(self, meldingen_list_action: MeldingListAction) -> None:
meldingen = meldingen_list_action()
@pytest.mark.asyncio
async def test_list_all(self, meldingen_list_action: MeldingListAction) -> None:
meldingen = await meldingen_list_action()

assert len(meldingen) == 10

@pytest.mark.parametrize(
"limit, expected_result",
[(1, 1), (5, 5), (10, 10), (20, 10)],
)
def test_list_limit(self, meldingen_list_action: MeldingListAction, limit: int, expected_result: int) -> None:
meldingen = meldingen_list_action(limit=limit)
@pytest.mark.asyncio
async def test_list_limit(self, meldingen_list_action: MeldingListAction, limit: int, expected_result: int) -> None:
meldingen = await meldingen_list_action(limit=limit)

assert len(meldingen) == expected_result

@pytest.mark.parametrize("offset, expected_result", [(1, 9), (5, 5), (10, 0), (20, 0)])
def test_list_offset(
@pytest.mark.asyncio
async def test_list_offset(
self,
meldingen_list_action: MeldingListAction,
offset: int,
expected_result: int,
) -> None:
meldingen = meldingen_list_action(offset=offset)
meldingen = await meldingen_list_action(offset=offset)

assert len(meldingen) == expected_result

@pytest.mark.parametrize(
"limit, offset, expected_result",
[(10, 0, 10), (5, 0, 5), (10, 10, 0), (20, 0, 10)],
)
def test_list_limit_offset(
@pytest.mark.asyncio
async def test_list_limit_offset(
self,
meldingen_list_action: MeldingListAction,
limit: int,
offset: int,
expected_result: int,
) -> None:
meldingen = meldingen_list_action(limit=limit, offset=offset)
meldingen = await meldingen_list_action(limit=limit, offset=offset)

assert len(meldingen) == expected_result


class TestMeldingRetrieveAction:
@pytest.mark.parametrize("pk", [1, 2, 3, 4, 5])
def test_retrieve_existing_meldingen(self, meldingen_retrieve_action: MeldingRetrieveAction, pk: int) -> None:
melding = meldingen_retrieve_action(pk=pk)
@pytest.mark.asyncio
async def test_retrieve_existing_meldingen(self, meldingen_retrieve_action: MeldingRetrieveAction, pk: int) -> None:
melding = await meldingen_retrieve_action(pk=pk)

assert melding is not None
assert melding.text == str(pk)

@pytest.mark.parametrize("pk", [101, 102, 103, 104, 105])
def test_retrieve_non_existing_meldingen(self, meldingen_retrieve_action: MeldingRetrieveAction, pk: int) -> None:
melding = meldingen_retrieve_action(pk=pk)
@pytest.mark.asyncio
async def test_retrieve_non_existing_meldingen(
self, meldingen_retrieve_action: MeldingRetrieveAction, pk: int
) -> None:
melding = await meldingen_retrieve_action(pk=pk)

assert melding is None

0 comments on commit 6094ec0

Please sign in to comment.