print(ctx)
. Но в коде будет грязь.
@dataclass
class TokenUseCase:
@story
@arguments('user')
def obtain_token(I):
I.require_user_active
I.create_token
I.return_token
def require_user_active(self, ctx):
if ctx.user.is_active:
return Success()
return Failure()
def create_token(self, ctx):
ctx.token = self.create_user_token(ctx.user)
return Success()
def return_token(self, ctx):
return Result({'token': ctx.token})
# deps
create_user_token: Callable
@proofit404 Добрый вечер! Например у меня есть TokenUseCase, который я хочу использовать напрямую для получения токена.
result = TokenUseCase(create_user_token=create_user_token).obtain_token.run(user=user)
token = result.value['token']
Но также я хочу переиспользовать TokenUseCase.obtain_token как sub-story.
Но так сделать не получается, т.к. obtain_token возвращает Result и прекращает выполнение OtherUseCase.outer_story
obtain_token = TokenUseCase(create_user_token=create_user_token).obtain_token
OtherUseCase(find_token=obtain_token).outer_story.run()
Как правильно организовать код в таком случае? Заранее спасибо!
Привет. Сразу скажу что красивого решения я пока не нашёл.
Я обычно такое поведение выношу в отдельную story, т.е. Result
возвращаю на верхнем уровне вложенности.
@dataclass
class TokenUseCase:
@story
@arguments('user')
def obtain_user_token(I):
I.obtain_token
I.return_token
@story
@arguments('user')
def obtain_token(I):
I.require_user_active
I.create_token
Таким образом мы можем вызвать obtain_user_token
как самостоятельную сторю, а obtain_token
как дочернюю сторю для какой-то более большой.
Что-то вроде такого:
```
# step
def load_image(self, ctx):
result = io_call(ctx.get_image_file(image_id=ctx.image_id))
if not is_successful(result):
return Failure('image_cannot_be_loaded')
ctx.image = unwrap(result)
return Success()
```
С целью обозначить что будет выполнена io операция, которая которая может вызвать исключение, и чтобы можно было это исключение транслировать на зарегистрированную Failure.
mappers
нужен, поэтому не факт что враппер станет частью stories.
И в идеале наверное, чтобы был какой-то маппер, для для более гранулярного сопоставления исключений с failures.
А необработанные летели наверх или маппились с дефолтным failure. Имхо))
```
# step
def load_image(self, ctx):
wrapped = io_call(ctx.get_image_file(image_id=ctx.image_id))
if not is_successful(wrapped):
return Failure(wrapped.failure)
ctx.image = unwrap(wrapped)
return Success()
class RegisteredFailures(Enum):
image_cannot_be_loaded = auto()
image_not_found = auto()
permission_denied = auto()
def io_call(): -> FailureResult
pass
class ImageFailureResult(FailureResult):
@property
def failure(self):
failure = self._map(self._exception, RegisteredFailures.image_cannot_be_loaded)
return failure
```
return Failure(self.convert('low-level-reason'))
и этот convert прокидывать через DI. Тогда можно будет написать свой convert для разных доменов.
These chat rooms left for historical purposes only. All active maintainers of the project have left gitter.
Projects are still properly maintained. If you have any questions, please file an issue in our issue tracker:
Issues are better to keep track of the community interests. It could be converted to tasks easily. It preserves the history of resolution. It's google friendly. Let's keep our conversation in a structured way! See you there.