Coder Social home page Coder Social logo

theiterators / sealed-monad Goto Github PK

View Code? Open in Web Editor NEW
23.0 12.0 6.0 780 KB

Scala library for nice business logic oriented, for-comprehension-style error handling

License: Apache License 2.0

Scala 91.95% JavaScript 6.64% CSS 1.41%
scala for-comprehension monad monad-transformers monaderror error-handling

sealed-monad's Introduction

sealed-monad

Maven Central GitHub license sealed-monad Scala version support

Scala library for nice business logic oriented, for-comprehension-style error handling. Write logic that even your manager can understand!

Or in more technical terms, think of EitherT on steroids, with more human-readable method names.

Installation

Add the following to your build.sbt:

libraryDependencies += "pl.iterators" %% "sealed-monad" % "1.3.0"

Available for Scala 2.12.x, 2.13.x and 3.x.

Usage

  def createTodo(userId: UUID, organizationId: UUID, request: CreateTodoRequest): IO[CreateTodoResponse] = {
    (for {
      user <- userRepository
        .find(userId) // IO[Option[User]]
        .valueOr(CreateTodoResponse.UserNotFound) // extracts User or returns UserNotFound
      _ <- organizationRepository
        .findFor(userId) // IO[Option[Organization]]
        .valueOr(CreateTodoResponse.UserNotInOrganization) // extracts Organization or returns UserNotInOrganization
        .ensure(_.canCreateTodos(user), CreateTodoResponse.UserNotAllowedToCreateTodos) // checks if user can create todos or returns UserNotAllowedToCreateTodos
      _ <- todoRepository
        .find(request.title) // IO[Option[Todo]]
        .ensure(_.isEmpty, CreateTodoResponse.TodoAlreadyExists) // checks if todo already exists or returns TodoAlreadyExists
      _ <- Todo
        .from(request)
        .pure[IO] // IO[Todo]
        .ensure(_.title.nonEmpty, CreateTodoResponse.TodoTitleEmpty) // checks if todo title is non-empty or returns TodoTitleEmpty
      todo <- todoRepository.insert(Todo(UUID.randomUUID(), request.title)).seal // todo created!
    } yield CreateTodoResponse.Created(todo)).run // compile to IO[CreateTodoResponse]
  }

Documentation

Please refer to the docs site.

logo

License

This project is licensed under the Apache 2.0 License - see the LICENSE file for details.

sealed-monad's People

Contributors

bryljaku avatar kgawrys avatar kristerr avatar luksow avatar marcin-rzeznicki avatar piotrkuczko avatar pk044 avatar scala-steward avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sealed-monad's Issues

Improve documentation

The project is currently undocumented - adding descriptions, tips and example (typechecked) usages to functions exposed to the user will be extremely helpful.

Add effectful version of `ensure`

We could use an alternative to this function, preferably named ensureF:

def ensure[ADT](pred: A => Boolean, orElse: => ADT): Sealed[F, A, ADT]     = seal[ADT].ensure(pred, orElse)

This could cut off some boilerplate compared to the following usage of attemptF:

private def setFailed(obj: SomeObj): F[Result] = ???

private def ensureSomething(obj: SomeObj): StepF[Unit] =
    transactor
      .execute(someDbCall())
      .attemptF[Result, Unit] {
        case list if !list.exists(_.id != obj.id) => F.pure(Right(()))
        case _ =>
          setFailed(obj)
            .map(result => Left(result))
      }

versus potential ensureF:

private def ensureSomething(obj: SomeObj): StepF[Unit] =
    transactor
      .execute(someDbCall())
      .ensureF(!_.exists(_.id != deployment.id), setFailed(obj))

`attemptF` - inconsistent type parameter order

Hi,

I have encountered an inconsistency with the order of type parameters in the attemptF method within which could potentially cause confusion.

final class SealedFAOps {
  def attemptF[ADT, B]
}

// When using attemptF:
attemptF[FooResult, Unit]

sealed trait Sealed {
  def attemptF[B, ADT1 >: ADT]
}

// When using attemptF:
attemptF[Unit, FooResult]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.