nlbone 0.3.2__py3-none-any.whl → 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nlbone/adapters/db/sqlalchemy/__init__.py +4 -1
- nlbone/adapters/db/sqlalchemy/engine.py +11 -0
- nlbone/adapters/db/sqlalchemy/repository.py +52 -0
- nlbone/adapters/db/sqlalchemy/uow.py +70 -0
- nlbone/adapters/messaging/__init__.py +1 -0
- nlbone/adapters/messaging/event_bus.py +20 -0
- nlbone/config/settings.py +22 -3
- nlbone/container.py +15 -0
- nlbone/core/application/events.py +16 -0
- nlbone/core/application/use_case.py +10 -0
- nlbone/core/domain/base.py +47 -0
- nlbone/core/ports/__init__.py +5 -1
- nlbone/core/ports/event_bus.py +7 -0
- nlbone/core/ports/repo.py +16 -0
- nlbone/core/ports/uow.py +16 -0
- nlbone/interfaces/api/dependencies/__init__.py +2 -1
- nlbone/interfaces/api/dependencies/uow.py +31 -0
- {nlbone-0.3.2.dist-info → nlbone-0.4.0.dist-info}/METADATA +1 -1
- {nlbone-0.3.2.dist-info → nlbone-0.4.0.dist-info}/RECORD +21 -14
- nlbone/core/application/use_cases/__init__.py +0 -0
- nlbone/core/application/use_cases/register_user.py +0 -0
- {nlbone-0.3.2.dist-info → nlbone-0.4.0.dist-info}/WHEEL +0 -0
- {nlbone-0.3.2.dist-info → nlbone-0.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1 +1,4 @@
|
|
|
1
|
-
from .query_builder import get_paginated_response, apply_pagination
|
|
1
|
+
from .query_builder import get_paginated_response, apply_pagination
|
|
2
|
+
from .engine import init_sync_engine, init_async_engine, sync_ping, sync_session, async_ping, async_session
|
|
3
|
+
from .repository import SqlAlchemyRepository, AsyncSqlAlchemyRepository
|
|
4
|
+
from .uow import SqlAlchemyUnitOfWork, AsyncSqlAlchemyUnitOfWork
|
|
@@ -117,3 +117,14 @@ def sync_ping() -> None:
|
|
|
117
117
|
with eng.connect() as conn:
|
|
118
118
|
conn.execute(text("SELECT 1"))
|
|
119
119
|
|
|
120
|
+
def get_async_session_factory() -> async_sessionmaker[AsyncSession]:
|
|
121
|
+
if _async_session_factory is None:
|
|
122
|
+
init_async_engine()
|
|
123
|
+
assert _async_session_factory is not None
|
|
124
|
+
return _async_session_factory
|
|
125
|
+
|
|
126
|
+
def get_sync_session_factory() -> sessionmaker[Session]:
|
|
127
|
+
if _sync_session_factory is None:
|
|
128
|
+
init_sync_engine()
|
|
129
|
+
assert _sync_session_factory is not None
|
|
130
|
+
return _sync_session_factory
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Generic, Iterable, Optional, Type, TypeVar, List
|
|
3
|
+
|
|
4
|
+
from sqlalchemy import select
|
|
5
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
6
|
+
from sqlalchemy.orm import Session
|
|
7
|
+
from nlbone.core.ports.repo import Repository, AsyncRepository
|
|
8
|
+
|
|
9
|
+
T = TypeVar("T")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SqlAlchemyRepository(Repository[T], Generic[T]):
|
|
13
|
+
def __init__(self, session: Session, model: Type[T]) -> None:
|
|
14
|
+
self.session = session
|
|
15
|
+
self.model = model
|
|
16
|
+
|
|
17
|
+
def get(self, id) -> Optional[T]:
|
|
18
|
+
return self.session.get(self.model, id)
|
|
19
|
+
|
|
20
|
+
def add(self, obj: T) -> None:
|
|
21
|
+
self.session.add(obj)
|
|
22
|
+
|
|
23
|
+
def remove(self, obj: T) -> None:
|
|
24
|
+
self.session.delete(obj)
|
|
25
|
+
|
|
26
|
+
def list(self, *, limit: int | None = None, offset: int = 0) -> Iterable[T]:
|
|
27
|
+
q = self.session.query(self.model).offset(offset)
|
|
28
|
+
if limit is not None:
|
|
29
|
+
q = q.limit(limit)
|
|
30
|
+
return q.all()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class AsyncSqlAlchemyRepository(AsyncRepository, Generic[T]):
|
|
34
|
+
def __init__(self, session: AsyncSession, model: Type[T]) -> None:
|
|
35
|
+
self.session = session
|
|
36
|
+
self.model = model
|
|
37
|
+
|
|
38
|
+
async def get(self, id) -> Optional[T]:
|
|
39
|
+
return await self.session.get(self.model, id)
|
|
40
|
+
|
|
41
|
+
def add(self, obj: T) -> None:
|
|
42
|
+
self.session.add(obj)
|
|
43
|
+
|
|
44
|
+
async def remove(self, obj: T) -> None:
|
|
45
|
+
await self.session.delete(obj)
|
|
46
|
+
|
|
47
|
+
async def list(self, *, limit: int | None = None, offset: int = 0) -> List[T]:
|
|
48
|
+
stmt = select(self.model).offset(offset)
|
|
49
|
+
if limit is not None:
|
|
50
|
+
stmt = stmt.limit(limit)
|
|
51
|
+
res = await self.session.execute(stmt)
|
|
52
|
+
return list(res.scalars().all())
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
|
|
6
|
+
from sqlalchemy.orm import Session, sessionmaker
|
|
7
|
+
from nlbone.core.ports.uow import UnitOfWork
|
|
8
|
+
from nlbone.core.ports.uow import AsyncUnitOfWork as AsyncUnitOfWorkPort
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SqlAlchemyUnitOfWork(UnitOfWork):
|
|
12
|
+
"""sync UoW for SQLAlchemy."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, session_factory: sessionmaker) -> None:
|
|
15
|
+
self._session_factory = session_factory
|
|
16
|
+
self.session: Session | None = None
|
|
17
|
+
|
|
18
|
+
def __enter__(self) -> "SqlAlchemyUnitOfWork":
|
|
19
|
+
self.session = self._session_factory()
|
|
20
|
+
return self
|
|
21
|
+
|
|
22
|
+
def __exit__(self, exc_type, exc, tb) -> None:
|
|
23
|
+
try:
|
|
24
|
+
if exc_type is None:
|
|
25
|
+
self.commit()
|
|
26
|
+
else:
|
|
27
|
+
self.rollback()
|
|
28
|
+
finally:
|
|
29
|
+
if self.session is not None:
|
|
30
|
+
self.session.close()
|
|
31
|
+
self.session = None
|
|
32
|
+
|
|
33
|
+
def commit(self) -> None:
|
|
34
|
+
if self.session:
|
|
35
|
+
self.session.commit()
|
|
36
|
+
|
|
37
|
+
def rollback(self) -> None:
|
|
38
|
+
if self.session:
|
|
39
|
+
self.session.rollback()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class AsyncSqlAlchemyUnitOfWork(AsyncUnitOfWorkPort):
|
|
43
|
+
"""Transactional boundary for async SQLAlchemy."""
|
|
44
|
+
|
|
45
|
+
def __init__(self, session_factory: async_sessionmaker[AsyncSession]) -> None:
|
|
46
|
+
self._sf = session_factory
|
|
47
|
+
self.session: Optional[AsyncSession] = None
|
|
48
|
+
|
|
49
|
+
async def __aenter__(self) -> "AsyncSqlAlchemyUnitOfWork":
|
|
50
|
+
self.session = self._sf()
|
|
51
|
+
return self
|
|
52
|
+
|
|
53
|
+
async def __aexit__(self, exc_type, exc, tb) -> None:
|
|
54
|
+
try:
|
|
55
|
+
if exc_type is None:
|
|
56
|
+
await self.commit()
|
|
57
|
+
else:
|
|
58
|
+
await self.rollback()
|
|
59
|
+
finally:
|
|
60
|
+
if self.session is not None:
|
|
61
|
+
await self.session.close()
|
|
62
|
+
self.session = None
|
|
63
|
+
|
|
64
|
+
async def commit(self) -> None:
|
|
65
|
+
if self.session:
|
|
66
|
+
await self.session.commit()
|
|
67
|
+
|
|
68
|
+
async def rollback(self) -> None:
|
|
69
|
+
if self.session:
|
|
70
|
+
await self.session.rollback()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .event_bus import InMemoryEventBus
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
from typing import Callable, Dict, Iterable, List
|
|
4
|
+
from nlbone.core.domain.base import DomainEvent
|
|
5
|
+
from nlbone.core.ports.event_bus import EventBusPort
|
|
6
|
+
|
|
7
|
+
class InMemoryEventBus(EventBusPort):
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
self._handlers: Dict[str, List[Callable[[DomainEvent], None]]] = defaultdict(list)
|
|
10
|
+
|
|
11
|
+
def publish(self, events: Iterable[DomainEvent]) -> None:
|
|
12
|
+
for evt in events:
|
|
13
|
+
for h in self._handlers.get(evt.name, []):
|
|
14
|
+
try:
|
|
15
|
+
h(evt)
|
|
16
|
+
except Exception:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
def subscribe(self, event_name: str, handler: Callable[[DomainEvent], None]) -> None:
|
|
20
|
+
self._handlers[event_name].append(handler)
|
nlbone/config/settings.py
CHANGED
|
@@ -22,12 +22,21 @@ def _guess_env_file() -> str | None:
|
|
|
22
22
|
return str(f)
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
def _is_production_env() -> bool:
|
|
26
|
+
raw = os.getenv("NLBONE_ENV") or os.getenv("ENV") or os.getenv("ENVIRONMENT")
|
|
27
|
+
if not raw:
|
|
28
|
+
return False
|
|
29
|
+
return raw.strip().lower() in {"prod", "production"}
|
|
30
|
+
|
|
31
|
+
|
|
25
32
|
class Settings(BaseSettings):
|
|
26
33
|
# ---------------------------
|
|
27
34
|
# App
|
|
28
35
|
# ---------------------------
|
|
29
36
|
PORT: int = 8000
|
|
30
|
-
ENV: Literal["local", "dev", "staging", "prod"] = Field(default="local"
|
|
37
|
+
ENV: Literal["local", "dev", "staging", "prod"] = Field(default="local",
|
|
38
|
+
validation_alias=AliasChoices("NLBONE_ENV", "ENV",
|
|
39
|
+
"ENVIRONMENT"))
|
|
31
40
|
DEBUG: bool = Field(default=False)
|
|
32
41
|
LOG_LEVEL: Literal["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"] = Field(default="INFO")
|
|
33
42
|
LOG_JSON: bool = Field(default=True)
|
|
@@ -54,13 +63,21 @@ class Settings(BaseSettings):
|
|
|
54
63
|
# ---------------------------
|
|
55
64
|
# Database
|
|
56
65
|
# ---------------------------
|
|
57
|
-
POSTGRES_DB_DSN: str = Field(default="postgresql+asyncpg://user:pass@localhost:5432/nlbone",
|
|
58
|
-
|
|
66
|
+
POSTGRES_DB_DSN: str = Field(default="postgresql+asyncpg://user:pass@localhost:5432/nlbone",
|
|
67
|
+
validation_alias=AliasChoices("NLBONE_POSTGRES_DB_DSN",
|
|
68
|
+
"POSTGRES_DB_DSN", "DATABASE_URL", "DB_DSN"))
|
|
69
|
+
DB_ECHO: bool = Field(default=False)
|
|
70
|
+
DB_POOL_SIZE: int = Field(default=5)
|
|
71
|
+
DB_MAX_OVERFLOW: int = Field(default=10)
|
|
59
72
|
|
|
60
73
|
# ---------------------------
|
|
61
74
|
# Messaging / Cache
|
|
62
75
|
# ---------------------------
|
|
63
76
|
REDIS_URL: str = Field(default="redis://localhost:6379/0")
|
|
77
|
+
# --- Event bus / Outbox ---
|
|
78
|
+
EVENT_BUS_BACKEND: Literal["inmemory"] = Field(default="inmemory")
|
|
79
|
+
OUTBOX_ENABLED: bool = Field(default=False)
|
|
80
|
+
OUTBOX_POLL_INTERVAL_MS: int = Field(default=500)
|
|
64
81
|
|
|
65
82
|
# ---------------------------
|
|
66
83
|
# UPLOADCHI
|
|
@@ -80,6 +97,8 @@ class Settings(BaseSettings):
|
|
|
80
97
|
|
|
81
98
|
@classmethod
|
|
82
99
|
def load(cls, env_file: str | None = None) -> "Settings":
|
|
100
|
+
if _is_production_env():
|
|
101
|
+
return cls()
|
|
83
102
|
return cls(_env_file=env_file or _guess_env_file())
|
|
84
103
|
|
|
85
104
|
|
nlbone/container.py
CHANGED
|
@@ -3,15 +3,30 @@ from typing import Any, Mapping, Optional
|
|
|
3
3
|
|
|
4
4
|
from dependency_injector import containers, providers
|
|
5
5
|
|
|
6
|
+
from nlbone.adapters.db.sqlalchemy import SqlAlchemyUnitOfWork, AsyncUnitOfWork
|
|
7
|
+
from nlbone.adapters.db.sqlalchemy.engine import get_sync_session_factory, get_async_session_factory
|
|
6
8
|
from nlbone.adapters.http_clients.uploadchi import UploadchiClient
|
|
7
9
|
from nlbone.adapters.http_clients.uploadchi_async import UploadchiAsyncClient
|
|
8
10
|
from nlbone.adapters.auth.keycloak import KeycloakAuthService
|
|
11
|
+
from nlbone.adapters.messaging import InMemoryEventBus
|
|
12
|
+
from nlbone.core.ports import EventBusPort
|
|
9
13
|
from nlbone.core.ports.files import FileServicePort, AsyncFileServicePort
|
|
10
14
|
|
|
11
15
|
|
|
12
16
|
class Container(containers.DeclarativeContainer):
|
|
13
17
|
config = providers.Configuration(strict=False)
|
|
14
18
|
|
|
19
|
+
sync_session_factory = providers.Singleton(get_sync_session_factory)
|
|
20
|
+
async_session_factory = providers.Singleton(get_async_session_factory)
|
|
21
|
+
|
|
22
|
+
# --- UoW ---
|
|
23
|
+
uow = providers.Factory(SqlAlchemyUnitOfWork, session_factory=sync_session_factory)
|
|
24
|
+
async_uow = providers.Factory(AsyncUnitOfWork, session_factory=async_session_factory)
|
|
25
|
+
|
|
26
|
+
# --- Event bus ---
|
|
27
|
+
event_bus: providers.Singleton[EventBusPort] = providers.Singleton(InMemoryEventBus)
|
|
28
|
+
|
|
29
|
+
# --- Services ---
|
|
15
30
|
auth: providers.Singleton[KeycloakAuthService] = providers.Singleton(KeycloakAuthService, settings=config)
|
|
16
31
|
file_service: providers.Singleton[FileServicePort] = providers.Singleton(UploadchiClient)
|
|
17
32
|
afiles_service: providers.Singleton[AsyncFileServicePort] = providers.Singleton(UploadchiAsyncClient)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Iterable, Sequence
|
|
2
|
+
from nlbone.core.domain.base import AggregateRoot, DomainEvent
|
|
3
|
+
from nlbone.core.ports.event_bus import EventBusPort
|
|
4
|
+
|
|
5
|
+
def collect_events(*aggregates: Iterable[AggregateRoot]) -> list[DomainEvent]:
|
|
6
|
+
events: list[DomainEvent] = []
|
|
7
|
+
for agg in aggregates:
|
|
8
|
+
if isinstance(agg, AggregateRoot):
|
|
9
|
+
events.extend(agg.pull_events())
|
|
10
|
+
else:
|
|
11
|
+
for a in agg:
|
|
12
|
+
events.extend(a.pull_events())
|
|
13
|
+
return events
|
|
14
|
+
|
|
15
|
+
def publish_events(bus: EventBusPort, events: Sequence[DomainEvent]) -> None:
|
|
16
|
+
if events: bus.publish(events)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
from typing import Any, Generic, List, TypeVar
|
|
5
|
+
|
|
6
|
+
TId = TypeVar("TId")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DomainError(Exception):
|
|
10
|
+
"""Base domain exception."""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class DomainEvent:
|
|
15
|
+
"""Immutable domain event."""
|
|
16
|
+
occurred_at: datetime = datetime.now(timezone.utc)
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def name(self):
|
|
20
|
+
return self.__class__.__name__
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ValueObject:
|
|
24
|
+
"""Base for value objects (immutable in practice)."""
|
|
25
|
+
def __eq__(self, other: Any) -> bool:
|
|
26
|
+
return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
|
|
27
|
+
|
|
28
|
+
def __hash__(self) -> int: # allow in sets/dicts
|
|
29
|
+
return hash(tuple(sorted(self.__dict__.items())))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Entity(Generic[TId]):
|
|
33
|
+
id: TId
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class AggregateRoot(Entity[TId]):
|
|
37
|
+
"""Aggregate root with domain event collection."""
|
|
38
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
39
|
+
self._domain_events: List[DomainEvent] = []
|
|
40
|
+
|
|
41
|
+
def _raise(self, event: DomainEvent) -> None:
|
|
42
|
+
self._domain_events.append(event)
|
|
43
|
+
|
|
44
|
+
def pull_events(self) -> List[DomainEvent]:
|
|
45
|
+
events = list(self._domain_events)
|
|
46
|
+
self._domain_events.clear()
|
|
47
|
+
return events
|
nlbone/core/ports/__init__.py
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Callable, Iterable, Protocol
|
|
3
|
+
from nlbone.core.domain.base import DomainEvent
|
|
4
|
+
|
|
5
|
+
class EventBusPort(Protocol):
|
|
6
|
+
def publish(self, events: Iterable[DomainEvent]) -> None: ...
|
|
7
|
+
def subscribe(self, event_name: str, handler: Callable[[DomainEvent], None]) -> None: ...
|
nlbone/core/ports/repo.py
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Iterable, Optional, Protocol, TypeVar, List
|
|
3
|
+
|
|
4
|
+
T = TypeVar("T")
|
|
5
|
+
|
|
6
|
+
class Repository(Protocol[T]): # ← نه Protocol, Generic[T]
|
|
7
|
+
def get(self, id) -> Optional[T]: ...
|
|
8
|
+
def add(self, obj: T) -> None: ...
|
|
9
|
+
def remove(self, obj: T) -> None: ...
|
|
10
|
+
def list(self, *, limit: int | None = None, offset: int = 0) -> Iterable[T]: ...
|
|
11
|
+
|
|
12
|
+
class AsyncRepository(Protocol[T]):
|
|
13
|
+
async def get(self, id) -> Optional[T]: ...
|
|
14
|
+
def add(self, obj: T) -> None: ...
|
|
15
|
+
async def remove(self, obj: T) -> None: ...
|
|
16
|
+
async def list(self, *, limit: int | None = None, offset: int = 0) -> List[T]: ...
|
nlbone/core/ports/uow.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Protocol, runtime_checkable
|
|
3
|
+
|
|
4
|
+
@runtime_checkable
|
|
5
|
+
class UnitOfWork(Protocol):
|
|
6
|
+
def __enter__(self) -> "UnitOfWork": ...
|
|
7
|
+
def __exit__(self, exc_type, exc, tb) -> None: ...
|
|
8
|
+
def commit(self) -> None: ...
|
|
9
|
+
def rollback(self) -> None: ...
|
|
10
|
+
|
|
11
|
+
@runtime_checkable
|
|
12
|
+
class AsyncUnitOfWork(Protocol):
|
|
13
|
+
async def __aenter__(self) -> "AsyncUnitOfWork": ...
|
|
14
|
+
async def __aexit__(self, exc_type, exc, tb) -> None: ...
|
|
15
|
+
async def commit(self) -> None: ...
|
|
16
|
+
async def rollback(self) -> None: ...
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
from .db import get_session, get_async_session
|
|
2
|
-
from .auth import has_access, client_has_access, current_client_id, current_user_id, current_request, user_authenticated
|
|
2
|
+
from .auth import has_access, client_has_access, current_client_id, current_user_id, current_request, user_authenticated
|
|
3
|
+
from .uow import get_uow, get_async_uow
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from collections.abc import Iterator
|
|
3
|
+
from typing import AsyncIterator
|
|
4
|
+
|
|
5
|
+
from fastapi import Request
|
|
6
|
+
|
|
7
|
+
from nlbone.adapters.db.sqlalchemy import AsyncSqlAlchemyUnitOfWork
|
|
8
|
+
from nlbone.core.ports.uow import UnitOfWork, AsyncUnitOfWork
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_uow(request: Request) -> Iterator[UnitOfWork]:
|
|
12
|
+
"""
|
|
13
|
+
Uses DI container mounted at app.state.container to create a UoW per request.
|
|
14
|
+
Assumes container.uow is a provider returning SqlAlchemyUnitOfWork(session_factory).
|
|
15
|
+
"""
|
|
16
|
+
container = getattr(request.app.state, "container", None)
|
|
17
|
+
if container is None or not hasattr(container, "uow"):
|
|
18
|
+
raise RuntimeError("Container with 'uow' provider not configured on app.state.container")
|
|
19
|
+
|
|
20
|
+
uow = container.uow()
|
|
21
|
+
with uow as _uow:
|
|
22
|
+
yield _uow
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
async def get_async_uow(request: Request) -> AsyncIterator[AsyncUnitOfWork]:
|
|
26
|
+
container = getattr(request.app.state, "container", None)
|
|
27
|
+
if container is None or not hasattr(container, "async_uow"):
|
|
28
|
+
raise RuntimeError("Container.async_uow provider not configured")
|
|
29
|
+
uow: AsyncSqlAlchemyUnitOfWork = container.async_uow()
|
|
30
|
+
async with uow as _uow:
|
|
31
|
+
yield _uow
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
nlbone/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
nlbone/container.py,sha256=
|
|
2
|
+
nlbone/container.py,sha256=XQVtW7r13ON6QCMA_MOEct1GO7yOPjHU8ZQ600k3iR8,2083
|
|
3
3
|
nlbone/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
nlbone/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
nlbone/adapters/auth/__init__.py,sha256=Eh9kWjY1I8vi17gK0oOzBLJwJX_GFuUcJIN7cLU6lJg,41
|
|
@@ -7,43 +7,50 @@ nlbone/adapters/auth/keycloak.py,sha256=8UjT1GMenzolR-XAzlKERJDWh3TLBrxaIasMenRY
|
|
|
7
7
|
nlbone/adapters/db/__init__.py,sha256=VzhE_VOTFxDE0yUOw-f8UCLFCVhdyKnrrhbqzZUy76A,218
|
|
8
8
|
nlbone/adapters/db/memory.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
nlbone/adapters/db/postgres.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
nlbone/adapters/db/sqlalchemy/__init__.py,sha256=
|
|
10
|
+
nlbone/adapters/db/sqlalchemy/__init__.py,sha256=0J9r4m72TtlozNh9YAQM4Dxd68SpbME0TniH-G5buh4,312
|
|
11
11
|
nlbone/adapters/db/sqlalchemy/base.py,sha256=-5FnCMKETJ2xykhViHQuNBdbRMaxuieuatgiEl4Lllw,73
|
|
12
|
-
nlbone/adapters/db/sqlalchemy/engine.py,sha256=
|
|
12
|
+
nlbone/adapters/db/sqlalchemy/engine.py,sha256=o2vgFbEfAQuGCPC0GZ-fxBB1T2NJtbeD9wOuCYEMZlA,3447
|
|
13
13
|
nlbone/adapters/db/sqlalchemy/query_builder.py,sha256=mgj0mE0tbBVOAm1nd2nfR3p4EgV_NPYASsfP_4lF6yA,8504
|
|
14
|
+
nlbone/adapters/db/sqlalchemy/repository.py,sha256=RpJ_zjYWkrhplBoQwAPFj3zxy2Qk9N8xP0RWA9kZIf4,1658
|
|
14
15
|
nlbone/adapters/db/sqlalchemy/schema.py,sha256=iiE42UT-DJh-ohezLFBWTBFN5WtrfZdtKToQDNLvoOs,1044
|
|
16
|
+
nlbone/adapters/db/sqlalchemy/uow.py,sha256=CVWYxW5w1bhLM9QAf0hF3Ky4Y52_W414fnztc5jwX64,2087
|
|
15
17
|
nlbone/adapters/http_clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
18
|
nlbone/adapters/http_clients/email_gateway.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
19
|
nlbone/adapters/http_clients/uploadchi.py,sha256=qguGDQ2NGNSN3BOFSFUINn8mKS4LI23UGURJNhDUH2E,4647
|
|
18
20
|
nlbone/adapters/http_clients/uploadchi_async.py,sha256=u-CHisQoTjuhyXb5h-TLDnfeUnN47e-VEbKamUnkaYI,3710
|
|
19
|
-
nlbone/adapters/messaging/__init__.py,sha256=
|
|
21
|
+
nlbone/adapters/messaging/__init__.py,sha256=UDAwu3s-JQmOZjWz2Nu0SgHhnkbeOhKDH_zLD75oWMY,40
|
|
22
|
+
nlbone/adapters/messaging/event_bus.py,sha256=odexwsfBhlPL887tz5-ZWFyJr7PBwA6pX0Bc4wUKMis,778
|
|
20
23
|
nlbone/adapters/messaging/redis.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
24
|
nlbone/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
25
|
nlbone/config/logging.py,sha256=68WRQejEpL6eHEY_cOgdlOjndKc-RWth0n4YmXnceC8,5041
|
|
23
|
-
nlbone/config/settings.py,sha256=
|
|
26
|
+
nlbone/config/settings.py,sha256=mnR-BXIPR3QpDlpAupuzVEd1QPIyEwsGOV2xBOOZzi8,4403
|
|
24
27
|
nlbone/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
28
|
nlbone/core/application/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
+
nlbone/core/application/events.py,sha256=4P4wzKtYFfnbt2_60DGdM3oEFyWLULrZywbjKQEug6s,603
|
|
26
30
|
nlbone/core/application/services.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
+
nlbone/core/application/use_case.py,sha256=JfrCdFx10ngz8KeUF67PxJCzScaySHzCf8kbBN0hfgk,247
|
|
27
32
|
nlbone/core/application/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
-
nlbone/core/application/use_cases/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
-
nlbone/core/application/use_cases/register_user.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
33
|
nlbone/core/domain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
+
nlbone/core/domain/base.py,sha256=e68mygG9-iG-OLKx9oX2GyyJG0nY0TCJ7bBkkWHh-6M,1247
|
|
31
35
|
nlbone/core/domain/events.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
36
|
nlbone/core/domain/models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
-
nlbone/core/ports/__init__.py,sha256=
|
|
37
|
+
nlbone/core/ports/__init__.py,sha256=jhHy1xMOMGBXrLTB56RXkrFfyaP2mQw7rmygfMrUf4M,214
|
|
34
38
|
nlbone/core/ports/auth.py,sha256=v2NiH8FzKXZ1MabzQxaK7AQvnt-GQindYIki90swTE4,492
|
|
39
|
+
nlbone/core/ports/event_bus.py,sha256=pB3c6y-zkQNTHdT49CNTvEzrykc6mlkLMnjN8P8SN4U,322
|
|
35
40
|
nlbone/core/ports/files.py,sha256=yJwW0kFWxkrT4ntfXDdJYyKSEWB6daEuaI6zgmeg0Gg,1596
|
|
36
41
|
nlbone/core/ports/messaging.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
|
-
nlbone/core/ports/repo.py,sha256=
|
|
42
|
+
nlbone/core/ports/repo.py,sha256=d0CqdEslAIb6Zu8hE0GpO1qNDFr2LId152oqIs2h2-o,647
|
|
43
|
+
nlbone/core/ports/uow.py,sha256=fAJUQ--4YUyv00dx0ywOCNoulaKJCwmHiIVKqo40ITo,554
|
|
38
44
|
nlbone/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
45
|
nlbone/interfaces/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
46
|
nlbone/interfaces/api/exception_handlers.py,sha256=Z3_dTGAmpHfgaMe_HTW89OpRtq-aamzaMTNkMIOdW3w,4092
|
|
41
47
|
nlbone/interfaces/api/exceptions.py,sha256=uJWNEu5-cgoMedYebNHuIFJioXl_fnBhO89E6FINT2A,2259
|
|
42
48
|
nlbone/interfaces/api/routers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
49
|
nlbone/interfaces/api/schemas.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
|
-
nlbone/interfaces/api/dependencies/__init__.py,sha256=
|
|
50
|
+
nlbone/interfaces/api/dependencies/__init__.py,sha256=0kXv1SgMhEf8VTarLoY_471JM898t4L9yOJqHBaV1pU,207
|
|
45
51
|
nlbone/interfaces/api/dependencies/auth.py,sha256=GHUlZ5L2N6ilOaOJqRicHrORB3AD3z2Y-qrO9Q2dNr4,1774
|
|
46
52
|
nlbone/interfaces/api/dependencies/db.py,sha256=IqDVq1lcCCxd22FBUg523lVANM_j71BYAQtsbrHc4M8,465
|
|
53
|
+
nlbone/interfaces/api/dependencies/uow.py,sha256=BGU0LUIwS2pjtEFTwYN0zXH78ZT59pj9ngYo76EGnHI,1182
|
|
47
54
|
nlbone/interfaces/api/middleware/__init__.py,sha256=Xcxg9Oy8uToPXaTSdBTKhst-hZwsaIEhqxx4mmo1bZI,157
|
|
48
55
|
nlbone/interfaces/api/middleware/access_log.py,sha256=dEjk_m4fyQ72S2xLzDydDoaw2F9Tvmfl_acat1YThE0,972
|
|
49
56
|
nlbone/interfaces/api/middleware/add_request_context.py,sha256=i8EV4BvZyrBcNfU-uTkybr7J7ypYvJq8mXSntM6oel4,1816
|
|
@@ -58,7 +65,7 @@ nlbone/interfaces/jobs/sync_tokens.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
|
|
|
58
65
|
nlbone/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
66
|
nlbone/utils/context.py,sha256=AUiN1jM0ebNMopZQoJSqWTfUHuVrp-HV8x6g7QsbEJ8,1601
|
|
60
67
|
nlbone/utils/time.py,sha256=dC0ucyAmHdNf3wpA_JPinl2VJRubWqx2vcRpJsT3-0k,102
|
|
61
|
-
nlbone-0.
|
|
62
|
-
nlbone-0.
|
|
63
|
-
nlbone-0.
|
|
64
|
-
nlbone-0.
|
|
68
|
+
nlbone-0.4.0.dist-info/METADATA,sha256=M_qMQmxoDizcmBeS-YQFEU_3MKnz8eOWqtP2mpv6wQA,2298
|
|
69
|
+
nlbone-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
70
|
+
nlbone-0.4.0.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
|
+
nlbone-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|