Initial release: async repository layer over SQLModel

This commit is contained in:
2026-08-13 22:25:59 +03:00
commit 3d85c2b5dd
26 changed files with 2252 additions and 0 deletions

219
tests/test_repositories.py Normal file
View File

@@ -0,0 +1,219 @@
import pytest
from pydantic_filters import BaseSort, OffsetPagination
from sqlalchemy.orm import joinedload
from metaorm import AlreadyExistsError, DatabaseSettings, HaveNoSessionError
from tests.models import (
AuthorRepository,
AuthorTable,
BookRepository,
BookTable,
ProductFilter,
ProductRepository,
ProductTable,
User,
UserRepository,
)
class TestBaseRepository:
async def test_session_raises_error_without_transaction(
self,
user_repository: UserRepository,
) -> None:
with pytest.raises(HaveNoSessionError):
_ = user_repository.session
async def test_create_item(self, user_repository: UserRepository) -> None:
user = User(name="Alice", email="alice@example.com")
created = await user_repository.create_item(user)
assert created.id is not None
assert created.name == "Alice"
assert created.email == "alice@example.com"
async def test_get_items(self, user_repository: UserRepository) -> None:
user1 = User(name="Alice", email="alice@example.com")
user2 = User(name="Bob", email="bob@example.com")
await user_repository.create_item(user1)
await user_repository.create_item(user2)
items = [item async for item in user_repository.get_items()]
assert len(items) == 2
assert {item.name for item in items} == {"Alice", "Bob"}
async def test_get_items_count(self, user_repository: UserRepository) -> None:
await user_repository.create_item(
User(name="Alice", email="alice@example.com"),
)
await user_repository.create_item(
User(name="Bob", email="bob@example.com"),
)
count = await user_repository.get_items_count()
assert count == 2
async def test_update_items(self, user_repository: UserRepository) -> None:
await user_repository.create_item(
User(name="Alice", email="alice@example.com"),
)
await user_repository.create_item(
User(name="Bob", email="bob@example.com"),
)
updated = [item async for item in user_repository.update_items(name="Updated")]
assert len(updated) == 2
assert all(item.name == "Updated" for item in updated)
async def test_delete_items(self, user_repository: UserRepository) -> None:
await user_repository.create_item(
User(name="Alice", email="alice@example.com"),
)
await user_repository.create_item(
User(name="Bob", email="bob@example.com"),
)
await user_repository.delete_items()
count = await user_repository.get_items_count()
assert count == 0
async def test_create_item_raises_already_exists_on_duplicate(
self,
user_repository: UserRepository,
) -> None:
user = User(name="Alice", email="alice@example.com")
await user_repository.create_item(user)
with pytest.raises(AlreadyExistsError):
await user_repository.create_item(user)
async def test_transaction_reuses_existing_session(
self,
user_repository: UserRepository,
) -> None:
async with user_repository.transaction():
_ = user_repository.session
async def test_get_items_with_pagination(
self,
user_repository: UserRepository,
) -> None:
for index in range(5):
await user_repository.create_item(
User(name=f"User{index}", email=f"user{index}@example.com"),
)
pagination = OffsetPagination(offset=1, limit=2)
items = [
item async for item in user_repository.get_items(pagination=pagination)
]
assert len(items) == 2
async def test_get_items_with_sort(
self,
user_repository: UserRepository,
) -> None:
await user_repository.create_item(
User(name="Charlie", email="c@example.com"),
)
await user_repository.create_item(
User(name="Alice", email="a@example.com"),
)
await user_repository.create_item(
User(name="Bob", email="b@example.com"),
)
sort = BaseSort(sort_by="name", sort_by_order="asc")
items = [item async for item in user_repository.get_items(sort=sort)]
assert [item.name for item in items] == ["Alice", "Bob", "Charlie"]
async def test_init_with_settings_creates_container(
self,
product_repository_settings: ProductRepository,
) -> None:
product = ProductTable(name="Widget", price=9.99)
created = await product_repository_settings.create_item(product)
assert created.id is not None
assert created.name == "Widget"
async def test_get_filter_type(self) -> None:
repository = ProductRepository(settings=DatabaseSettings())
filter_type = repository.get_filter_type()
assert filter_type is ProductFilter
async def test_get_items_with_filter(
self,
product_repository_settings: ProductRepository,
) -> None:
await product_repository_settings.create_item(
ProductTable(name="Alpha", price=10.0),
)
await product_repository_settings.create_item(
ProductTable(name="Beta", price=20.0),
)
items = [
item
async for item in product_repository_settings.get_items(
filter_=ProductFilter(name="Alpha"),
)
]
assert len(items) == 1
assert items[0].name == "Alpha"
async def test_get_items_with_options(
self,
author_repository: AuthorRepository,
book_repository: BookRepository,
) -> None:
author = await author_repository.create_item(AuthorTable(name="Tolkien"))
await book_repository.create_item(
BookTable(title="The Hobbit", author_id=author.id),
)
books = [
item
async for item in book_repository.get_items(
options=[joinedload(BookTable.author)],
)
]
assert len(books) == 1
assert books[0].title == "The Hobbit"
assert books[0].author.name == "Tolkien"
async def test_update_items_with_options(
self,
author_repository: AuthorRepository,
book_repository: BookRepository,
) -> None:
from sqlalchemy.orm import raiseload
author = await author_repository.create_item(AuthorTable(name="Tolkien"))
await book_repository.create_item(
BookTable(title="The Hobbit", author_id=author.id),
)
updated = [
item
async for item in book_repository.update_items(
title="Updated",
options=[raiseload(BookTable.author)],
)
]
assert len(updated) == 1
assert updated[0].title == "Updated"