Created
November 27, 2019 20:59
-
-
Save piq9117/823dce0f2bada6d29442da1e02972cdb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE EmptyDataDecls #-} | |
{-# LANGUAGE FlexibleContexts #-} | |
{-# LANGUAGE GADTs #-} | |
{-# LANGUAGE GeneralizedNewtypeDeriving #-} | |
{-# LANGUAGE MultiParamTypeClasses #-} | |
{-# LANGUAGE OverloadedStrings #-} | |
{-# LANGUAGE QuasiQuotes #-} | |
{-# LANGUAGE TemplateHaskell #-} | |
{-# LANGUAGE TypeFamilies #-} | |
module Main where | |
import Database.Persist | |
import Database.Persist.Postgresql | |
import Database.Persist.TH | |
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| | |
Person | |
name String | |
age Int Maybe | |
deriving Show | |
|] | |
getPerson :: MonadIO m => PersionId -> ( Maybe ( Entity Person ) ) | |
getPerson pid = selectFirst [ PersionId ==. pid ] [ ] | |
connStr = "host=localhost dbname=persistent_expirement user=user password=user port=5432" | |
main :: IO () | |
main = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do | |
flip runSqlPersistMPool pool $ do | |
runMigration migrateAll |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Also when we take this approach, you probably don't need classes as granular as
GetPerson
. You probably want classes likeDatabaseRead
,DatabaseWrite
,LocationService
,FileSystemRead
,FileSystemWrite
,Log
, and similar things. The point of writing such bespoke classes is twofold: (1) hide the details of third-party libraries (e.g.selectFirst
) and runtime dependencies (e.g.MyBackend
); and (2) get an idea of what each function might be doing (and not doing) from its signature.Along those lines, you should never need to write a function with a
MonadIO
constraint: if you need to do someIO
, write a bespoke class for it inClasses
and write an instance of that class forApp
inAppWiring
. Try not to make your classes general-purpose things likeFetch
. Make them represent particular services that your application needs, likeLocationService
. For example a class likedoesn't hide the details of a service from application developers. Neither does it guarantee that the correct URL is used or that the response is parsed correctly. Instead, using a bespoke class like
means you only need to construct the
URL
and parse theResponse
in one place, in theLocationService
instance forApp
.Remember that the point of these bespoke classes isn't for them to be reused in other projects: the point is to abstract the dependencies of this particular application only and to segregate I/O action by class constraints to enforce principle of least privilege.
10/n