packages feed

hasql-effectful (empty) → 0.1.0.0

raw patch · 6 files changed

+240/−0 lines, 6 filesdep +basedep +bytestringdep +effectful

Dependencies added: base, bytestring, effectful, hasql, hasql-effectful, hasql-pool, hasql-transaction, text

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for hasql-effectful++## 0.1.0.0 -- 2023-12-27++* Initial release 
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2023 Nadeem Bitar++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ examples/Main.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Data.ByteString.Char8 (pack)+import Data.Functor.Contravariant ((>$<))+import Data.Int (Int32)+import Data.Text (Text)+import Effectful+import Effectful.Error.Static+import Effectful.Hasql+import Hasql.Decoders qualified as D+import Hasql.Encoders qualified as E+import Hasql.Pool (Pool, UsageError, acquire)+import Hasql.Session (Session, statement)+import Hasql.Statement (Statement (..))+import Hasql.Transaction qualified as T+import Hasql.Transaction.Sessions+import System.Environment (lookupEnv)++data User = User+  { firstName :: Text,+    lastName :: Text,+    userId :: Maybe Int32+  }+  deriving stock (Show)++userDecoder :: D.Row User+userDecoder =+  User+    <$> D.column (D.nonNullable D.text)+    <*> D.column (D.nonNullable D.text)+    <*> D.column (D.nullable D.int4)++userEncoder :: E.Params User+userEncoder =+  (firstName >$< E.param (E.nonNullable E.text))+    <> (lastName >$< E.param (E.nonNullable E.text))++insertUser_ :: Statement User Int32+insertUser_ =+  Statement sql encoder decoder True+  where+    sql = "INSERT INTO users (first_name, last_name) VALUES ($1, $2) RETURNING id"+    encoder = userEncoder+    decoder = D.singleRow ((D.column . D.nonNullable) D.int4)++findUserById_ :: Statement Int32 (Maybe User)+findUserById_ =+  Statement sql encoder decoder True+  where+    sql = "SELECT first_name, last_name, id FROM users WHERE id = $1"+    encoder = E.param $ E.nonNullable E.int4+    decoder = D.rowMaybe userDecoder++findUserById :: Int32 -> Session (Maybe User)+findUserById userId = statement userId findUserById_++insertUser :: User -> Session Int32+insertUser user = transaction Serializable Write $ do+  T.statement user insertUser_++createUser :: (Hasql :> es, Error UsageError :> es) => User -> Eff es Int32+createUser user = do+  runSession $ insertUser user++findUser :: (Hasql :> es, Error UsageError :> es) => Int32 -> Eff es (Maybe User)+findUser userId = do+  runSession $ findUserById userId++mkPool :: IO Pool+mkPool = do+  pgHost <- lookupEnv "PG_CONNECTION_STRING"+  case pgHost of+    Just h -> acquire 3 10 1_800 1_800 (pack h)+    Nothing -> error "PG_CONNECTION_STRING env is not defined or is invalid"++createTableStatement :: Statement () ()+createTableStatement = Statement sql mempty D.noResult False+  where+    sql = "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, first_name TEXT, last_name TEXT)"++createTable :: (Hasql :> es, Error UsageError :> es) => Eff es ()+createTable = do+  runSession $ statement () createTableStatement++newUser :: User+newUser = User "Sung-kyung" "Lee" Nothing++sampleApp :: (Hasql :> es, Error UsageError :> es) => Eff es (Maybe User)+sampleApp = do+  uId <- createUser newUser+  findUser uId++runToIO :: Pool -> Eff [Hasql, Error UsageError, IOE] a -> IO a+runToIO pool = runEff . runErrorWith @UsageError handleUsageError . runHasqlIO pool++handleUsageError :: (IOE :> es) => CallStack -> UsageError -> Eff es a+handleUsageError callStack err = do+  liftIO $ putStrLn $ "Usage error" <> show err <> prettyCallStack callStack+  error "hasql usage error"++main :: IO ()+main = do+  pool <- mkPool+  _ <- runToIO pool createTable+  u <- runToIO pool sampleApp+  print u
+ hasql-effectful.cabal view
@@ -0,0 +1,62 @@+cabal-version:   3.4+name:            hasql-effectful+version:         0.1.0.0+synopsis:        Effectful bindings for hasql+description:+  @<https://hackage.haskell.org/package/effectful Effectful>@ bindings for @<https://hackage.haskell.org/package/hasql hasql>@++category:        Database+homepage:        https://github.com/shinzui/hasql-effectful+license:         MIT+license-file:    LICENSE+author:          Nadeem Bitar+maintainer:      nadeem@gmail.com+build-type:      Simple+extra-doc-files: CHANGELOG.md++common common+  ghc-options:        -Wall+  default-extensions:+    DataKinds+    DerivingStrategies+    LambdaCase+    TypeFamilies++library+  import:           common+  exposed-modules:  Effectful.Hasql+  build-depends:+    , base        ^>=4.17   && <5+    , effectful   >=1.3.0.0 && <3.0.0.0+    , hasql       ^>=1.6    && <2+    , hasql-pool  ^>=0.10++  hs-source-dirs:   src+  default-language: GHC2021++executable hasql-effectful-example+  import:           common+  ghc-options:      -threaded -rtsopts -with-rtsopts=-N+  main-is:          Main.hs+  build-depends:+    , base               ^>=4.17+    , bytestring         ^>=0.11.5+    , effectful          ^>=2.3.0+    , hasql              ^>=1.6+    , hasql-effectful+    , hasql-pool         ^>=0.10.0+    , hasql-transaction  ^>=1.0.1+    , text               ^>=2.0++  hs-source-dirs:   examples+  default-language: GHC2021++test-suite hasql-effectful-test+  import:           common+  default-language: GHC2021+  type:             exitcode-stdio-1.0+  hs-source-dirs:   test+  main-is:          Main.hs+  build-depends:+    , base             ^>=4.17+    , hasql-effectful
+ src/Effectful/Hasql.hs view
@@ -0,0 +1,41 @@+module Effectful.Hasql+  ( -- * Effect+    Hasql (..),+    runSession,++    -- * Handlers+    runHasqlIO,+    runWithPool,+  )+where++import Effectful+import Effectful.Dispatch.Dynamic+import Effectful.Error.Static+import Hasql.Pool (Pool, UsageError, use)+import Hasql.Session (Session)++-- | Provides the ability to execute actions against a postgresql database+data Hasql :: Effect where+  RunSession :: Error UsageError :> es => Session a -> Hasql (Eff es) a++type instance DispatchOf Hasql = Dynamic++runSession :: (HasCallStack, Error UsageError :> es, Hasql :> es) => Session a -> Eff es a+runSession = send . RunSession++runHasqlIO ::+  forall es a.+  ( IOE :> es+  ) =>+  Pool ->+  Eff (Hasql : es) a ->+  Eff es a+runHasqlIO pool = interpret $ \env -> \case+  RunSession session -> do+    r <- liftIO $ use pool session+    localSeqUnlift env $ \unlift -> unlift $ do+      either throwError pure r++runWithPool :: Pool -> Eff [Hasql, Error UsageError, IOE] a -> IO (Either (CallStack, UsageError) a)+runWithPool pool = runEff . runError @UsageError . runHasqlIO pool
+ test/Main.hs view
@@ -0,0 +1,4 @@+module Main (main) where++main :: IO ()+main = putStrLn "Test suite not yet implemented."