コード例 #1
0
ファイル: uow.py プロジェクト: 2021-msa-study/fastmsa
from typing import Any, Callable, Optional, Sequence, Type

from fastmsa.core import (
    AbstractRepository,
    AbstractUnitOfWork,
    Aggregate,
    AggregateReposMap,
)
from fastmsa.logging import get_logger
from fastmsa.orm import Session, SessionMaker, get_sessionmaker
from fastmsa.repo import SqlAlchemyRepository

RepoMakerFunc = Callable[[Session], AbstractRepository]
RepoMakerDict = dict[Type[Aggregate], RepoMakerFunc]

logger = get_logger("fastmsa.uow")


class SqlAlchemyUnitOfWork(AbstractUnitOfWork):  # type: ignore
    """``SqlAlchemy`` ORM을 이용한 UnitOfWork 패턴 구현입니다."""

    # pylint: disable=super-init-not-called
    def __init__(
        self,
        agg_classes: Sequence[Type[Aggregate]],
        get_session: Optional[SessionMaker] = None,
        repo_maker: Optional[RepoMakerDict] = None,
    ) -> None:
        """``SqlAlchemy`` 기반의 UoW를 초기화합니다."""
        super().__init__()
        self.agg_classes = agg_classes
コード例 #2
0
ファイル: command.py プロジェクト: 2021-msa-study/fastmsa
from fastmsa.logging import get_logger
from fastmsa.utils import Fore, Style, bold, cwd, fg, scan_resource_dir

YELLOW, CYAN, RED, GREEN, WHITE = (
    Fore.YELLOW,
    Fore.CYAN,
    Fore.RED,
    Fore.GREEN,
    Fore.WHITE,
)
WHITE_EX, CYAN_EX = Fore.LIGHTWHITE_EX, Fore.LIGHTCYAN_EX
BRIGHT, RESET_ALL = Style.BRIGHT, Style.RESET_ALL

TEMPLATE_DIR = "templates/app"

logger = get_logger("fastmsa.command")


class FastMSACommand:
    def __init__(self):
        """Constructor.

        작업 순서:
            1. `<pkg_name>/config.py` 위치를 찾기 위해 앱 name 을 구한다.
            2. <pkg_name> 은 암시적으로는 현재 경로의 이름인데, `setup.cfg` 파일에
               `[fastmsa]` 섹션에도 지정 가능하다.
            3. config 파일을 로드해서 나머지 정보를 읽는다.
        """
        self.path = Path(os.path.abspath("."))
        self.msa = cast(FastMSA, FastMSA.load_from_config(self.path))
コード例 #3
0
import logging
import re
from contextlib import AbstractContextManager, contextmanager
from typing import Any, Callable, Generator, Optional, Type, Union, cast

from sqlalchemy import MetaData, create_engine
from sqlalchemy.engine import Engine
from sqlalchemy.orm import clear_mappers as _clear_mappers
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.session import Session
from sqlalchemy.pool import Pool, StaticPool

from fastmsa.core import AbstractFastMSA
from fastmsa.logging import get_logger

logger = get_logger("fastmsa.orm")

SessionMaker = Callable[[], Session]
"""Session 팩토리 타입."""
ScopedSession = AbstractContextManager[Session]
metadata: Optional[MetaData] = None

__session_factory: Optional[SessionMaker] = None


def set_default_sessionmaker(sessionmaker: SessionMaker):
    global __session_factory
    __session_factory = sessionmaker


def init_default_sessionmaker(
コード例 #4
0
ファイル: allocation.py プロジェクト: 2021-msa-study/fastmsa
from dataclasses import asdict

from fastmsa.core import AbstractPubsubClient
from fastmsa.event import on_command, on_event
from fastmsa.logging import get_logger
from fastmsa.uow import AbstractUnitOfWork, SqlAlchemyUnitOfWork
from tests.app.adapters import email
from tests.app.domain import commands, events
from tests.app.domain.aggregates import Product
from tests.app.domain.models import Batch, OrderLine

logger = get_logger("fastmsa.handlers.batch")


class InvalidSku(Exception):
    """배치의 SKU와 다른 SKU를 할당하려 할 때 발생하는 예외입니다."""

    ...


@on_event(events.OutOfStock)
def send_out_of_stock_notification(event: events.OutOfStock):
    """OutOfStock 예외 이벤트 발생시 에러 이메일을 발송합니다."""
    email.send(
        "[email protected]\n",
        f"Out of stock for {event.sku}",
    )


@on_command(commands.CreateBatch)
def add_batch(e: commands.CreateBatch, uow: AbstractUnitOfWork):
コード例 #5
0
from dataclasses import asdict, dataclass, is_dataclass
from typing import Callable, Optional, Any

import aioredis  # type: ignore

from fastmsa.core import (
    AbstractChannelListener,
    AbstractFastMSA,
    AbstractMessageBroker,
    AbstractPubsubClient,
)
from fastmsa.event import messagebroker
from fastmsa.logging import get_logger
from fastmsa.utils import Fore, bold

logger = get_logger("fastmsa.redis")


@dataclass
class RedisConnectInfo:
    host: str
    port: int

    @property
    def conn_args(self):
        return {"host": self.host, "port": self.port}

    @property
    def url(self) -> str:
        return f"redis://{self.host}:{self.port}"
コード例 #6
0
from __future__ import annotations

from typing import Optional

from fastmsa.core import Aggregate
from fastmsa.logging import get_logger
from tests.app.domain import commands, events
from tests.app.domain.models import Batch, OrderLine

logger = get_logger("tests.app.domain")


class Product(Aggregate[Batch]):
    def __init__(self, sku: str, items: list[Batch], version_number: int = 0):
        self.id = sku  # Entity 프로토콜을 준수하기 위해 반드시 정의해야 하는 속성.
        self.sku = sku
        self.items = items
        self.version_number = version_number

    def allocate(self, line: OrderLine) -> Optional[str]:
        try:
            if not self.items:
                raise StopIteration
            batch = next(b for b in sorted(self.items) if b.can_allocate(line))
            batch.allocate(line)
            self.version_number += 1
            self.messages.append(
                events.Allocated(
                    orderid=line.orderid,
                    sku=line.sku,
                    qty=line.qty,