stories icon indicating copy to clipboard operation
stories copied to clipboard

Instantiate domain entities using variable normalization.

Open proofit404 opened this issue 5 years ago • 0 comments

Ideally, data storage layer functions should return naked data like dictionaries and tuples.

We could avoid implementation of a private variable concept, if all dirty data from database and third-party services would be encapsulated in the domain objects without being stored in state.

from dataclasses import dataclass
from typing import Callable

from generics import defended, private
from marshmallow import Schema, post_load
from marshmallow.fields import Integer, Nested, String
from stories import I, Story
from stories_marshmallow import Argument, state


@defended
@dataclass
class Action(Story):
    I.find_user
    I.check_balance

    def find_user(self, state):
        state.user = self.load_user(state.user_id)

    def check_balance(self, state):
        if not state.user.has_enough():
            raise Exception

    load_user: Callable


@private
@dataclass
class User:
    name: str
    balance: int

    def has_enough(self):
        return self.balance > 0


class UserSchema(Schema):
    name = String()
    balance = Integer()

    @post_load
    def make_user(self, data, **kwargs):
        return User(**data)


@state
class ActionState(Schema):
    user_id = Argument(Integer())
    user = Nested(UserSchema())


def load_user(user_id):
    return {"name": "Jeff", "balance": 14}


action = Action(load_user)
action(ActionState(user_id=1))

See https://marshmallow.readthedocs.io/en/stable/quickstart.html#deserializing-to-objects

from typing import Callable

from generics import private
from pydantic import BaseModel
from pydantic_initialized import initialized
from stories_pydantic import Argument, I, state, Story


@initialized
class Action(Story):
    I.find_user
    I.check_balance

    def find_user(self, state):
        state.user = self.load_user(state.user_id)

    def check_balance(self, state):
        if not state.user.has_enough():
            raise Exception

    load_user: Callable


@private
@initialized
class User(BaseModel):
    name: str
    balance: int

    class Config:
        allow_mutation = False

    def has_enough(self):
        return self.balance > 0


@state
class ActionState(BaseModel):
    user_id = Argument[int]
    user = User


def load_user(user_id):
    return {"name": "Jeff", "balance": 14}


action = Action(load_user)
action(ActionState(user_id=1))
from attrs import define
from attrs import field
from trafaret import Bool
from trafaret import Int
from trafaret import Mapping

from cruftbot.entities import Invitations
from cruftbot.entities import Repository


@define
class AcceptInvitations:
    invitations = field(
        init=False, converter=Mapping(Int(), Bool() >> Repository) >> Invitations
    )

proofit404 avatar Jul 31 '20 23:07 proofit404