packages feed

railroad-0.3.0.0: railroad.cabal

cabal-version:      3.0
name:               railroad
version:            0.3.0.0
license:            BSD-3-Clause
license-file:       LICENSE
author:             Frederik Kallstrup Mastratisi
maintainer:         mastratisi@proton.me
category:           Control, Error Handling
build-type:         Simple
tested-with:        GHC == 9.10.3, GHC == 9.12.4, GHC == 9.14.1
extra-doc-files:    CHANGELOG.md, readme.md
synopsis:           Railway-oriented error handling: unwrap, throw, recover or fall back
description:
    Railway-oriented error handling for Haskell: one short operator per
    step, and the failure paths stop taking up lines.

    Each operator looks at a result (@Maybe@, @Either@, @Bool@,
    @Validation@, or a collection of them), decides whether it is a failure,
    and says what to do about it. Where you would write

    > rows <- runQuery (userById uid) >>= either (const (throwError err503)) pure
    > user <- case rows of
    >   []  -> throwError err404
    >   [u] -> pure u
    >   _   -> throwError err500

    you write

    > user <- runQuery (userById uid) ? err503 ?! cardinalityErr err404 (const err500)

    Layers are unwrapped left to right: @? err503@ unwraps the database
    @Either@, then @?!@ demands exactly one row (none is a 404, several a 500).

    What to do about a failure:

    * Throw: @?@ (constant error) and @??@ (error computed from the failure).

    * Recover: @?~@ and @??~@.

    * Observe, then carry on: @?\<*@, as in @runQuery q ?\<* logDbError ? err503@.

    * Fall back to another source: @?|@, or @?|<>@ to combine the errors.

    What counts as a failure:

    * @Nothing@, @Left@, @False@ and @Failure@. A collection fails if any
      element does, so an empty collection passes. @Validation@ failures
      accumulate, so a whole request can report every problem at once.

    * Collections are also checked by size: @?+@ (at least one), @?!@ (exactly
      one), @?∅@ (none), and @?∃@ (at least one element succeeded; keeps the
      successes).

    * Classifiers: @?>@ tags by a predicate. Any function into @Either@,
      @Maybe@, @Bool@ or @Validation@ is a classifier, applied with @\<&\>@.
      "Railroad.Bifurcate" provides @neg@, @atLeastOne@, @exactlyOne@,
      @noneAtAll@ and @anySucceeds@.

    Works in any @MonadError@ ("Railroad.MonadError": @mtl@, @ExceptT@,
    servant's @Handler@) and in @effectful@ with the @Error@ effect
    ("Railroad"). All operators are @infixl 1@ like @>>=@ and @\<&\>@, so
    they chain without parentheses. The readme has more examples.
homepage:     https://github.com/mastratisi/railroad
bug-reports:  https://github.com/mastratisi/railroad/issues
source-repository head
  type:     git
  location: https://github.com/mastratisi/railroad

common stuff
    ghc-options: -Wall
    build-depends:
      base >=4.17 && < 4.23,
      effectful >= 2.5 && < 2.8,
      mtl >= 2.2 && < 2.4,
      validation (>= 1.1 && < 1.3) || (>= 1.3.1 && < 1.4)

library
    import:           stuff
    exposed-modules:  Railroad
                      Railroad.Bifurcate
                      Railroad.MonadError
    hs-source-dirs:   src
    default-language: GHC2021
    

test-suite railroad-test
    import:           stuff
    default-language: GHC2021
    type:             exitcode-stdio-1.0
    hs-source-dirs:   test
    main-is:          Main.hs
    other-modules:    Model
                      RailroadSpec
                      Railroad.BifurcateSpec
                      Railroad.MonadErrorSpec
    build-tool-depends:
                  hspec-discover:hspec-discover >= 2.11.14 && < 2.12
    build-depends:
                  base  >=4.17 && < 4.23,
                  hspec  >= 2.11.14 && < 2.12,
                  QuickCheck >= 2.14 && < 2.16,
                  railroad