Skip to content

update to PS 0.11 and other stuff #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,22 @@
"output"
],
"dependencies": {
"purescript-arrays": "^3.0.0",
"purescript-either": "^2.0.0",
"purescript-foreign": "^3.0.0",
"purescript-foldable-traversable": "^2.0.0",
"purescript-transformers": "^2.0.0",
"purescript-aff": "^2.0.0",
"purescript-integers": "^2.0.0",
"purescript-datetime": "^2.0.0",
"purescript-unsafe-coerce": "^2.0.0",
"purescript-nullable": "^2.0.0"
"purescript-arrays": "^4.0.0",
"purescript-either": "^3.0.0",
"purescript-foreign": "^4.0.0",
"purescript-foldable-traversable": "^3.0.0",
"purescript-transformers": "^3.0.0",
"purescript-aff": "^3.0.0",
"purescript-integers": "^3.0.0",
"purescript-datetime": "^3.0.0",
"purescript-unsafe-coerce": "^3.0.0",
"purescript-nullable": "^3.0.0",
"purescript-prelude": "^3.0.0",
"purescript-foreign-generic": "^4.0.0"
},
"devDependencies": {
"purescript-spec": "^0.10.0",
"purescript-generics": "^3.0.0",
"purescript-js-date": "^3.0.0"
"purescript-spec": "^1.0.0",
"purescript-generics": "^4.0.0",
"purescript-js-date": "^4.0.0"
}
}
36 changes: 18 additions & 18 deletions src/Database/Postgres.purs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ module Database.Postgres
) where

import Prelude
import Control.Monad.Eff (Eff)
import Control.Monad.Eff (kind Effect, Eff)
import Data.Either (Either, either)
import Data.Function.Uncurried (Fn2(), runFn2)
import Data.Array ((!!))
import Data.Foreign (Foreign, MultipleErrors)
import Data.Foreign.Class (class IsForeign, read)
import Data.Foreign.Class (class Decode, decode)
import Data.Maybe (Maybe(Just, Nothing), maybe)
import Control.Monad.Except (runExcept)
import Control.Monad.Aff (Aff, finally)
Expand All @@ -35,9 +35,9 @@ import Database.Postgres.SqlValue (SqlValue)

newtype Query a = Query String

foreign import data Client :: *
foreign import data Client :: Type

foreign import data DB :: !
foreign import data DB :: Effect

type ConnectionString = String

Expand Down Expand Up @@ -72,45 +72,45 @@ execute_ (Query sql) client = void $ runQuery_ sql client

-- | Runs a query and returns all results.
query :: forall eff a
. (IsForeign a)
. (Decode a)
=> Query a -> Array SqlValue -> Client -> Aff (db :: DB | eff) (Array a)
query (Query sql) params client = do
rows <- runQuery sql params client
either liftError pure (runExcept (sequence $ read <$> rows))
either liftError pure (runExcept (sequence $ decode <$> rows))

-- | Just like `query` but does not make any param replacement
query_ :: forall eff a. (IsForeign a) => Query a -> Client -> Aff (db :: DB | eff) (Array a)
query_ :: forall eff a. (Decode a) => Query a -> Client -> Aff (db :: DB | eff) (Array a)
query_ (Query sql) client = do
rows <- runQuery_ sql client
either liftError pure (runExcept (sequence $ read <$> rows))
either liftError pure (runExcept (sequence $ decode <$> rows))

-- | Runs a query and returns the first row, if any
queryOne :: forall eff a
. (IsForeign a)
. (Decode a)
=> Query a -> Array SqlValue -> Client -> Aff (db :: DB | eff) (Maybe a)
queryOne (Query sql) params client = do
rows <- runQuery sql params client
maybe (pure Nothing) (either liftError (pure <<< Just)) (readFirst rows)
maybe (pure Nothing) (either liftError (pure <<< Just)) (decodeFirst rows)

-- | Just like `queryOne` but does not make any param replacement
queryOne_ :: forall eff a. (IsForeign a) => Query a -> Client -> Aff (db :: DB | eff) (Maybe a)
queryOne_ :: forall eff a. (Decode a) => Query a -> Client -> Aff (db :: DB | eff) (Maybe a)
queryOne_ (Query sql) client = do
rows <- runQuery_ sql client
maybe (pure Nothing) (either liftError (pure <<< Just)) (readFirst rows)
maybe (pure Nothing) (either liftError (pure <<< Just)) (decodeFirst rows)

-- | Runs a query and returns a single value, if any.
queryValue :: forall eff a
. (IsForeign a)
. (Decode a)
=> Query a -> Array SqlValue -> Client -> Aff (db :: DB | eff) (Maybe a)
queryValue (Query sql) params client = do
val <- runQueryValue sql params client
pure $ either (const Nothing) Just (runExcept (read val))
pure $ either (const Nothing) Just (runExcept (decode val))

-- | Just like `queryValue` but does not make any param replacement
queryValue_ :: forall eff a. (IsForeign a) => Query a -> Client -> Aff (db :: DB | eff) (Maybe a)
queryValue_ :: forall eff a. (Decode a) => Query a -> Client -> Aff (db :: DB | eff) (Maybe a)
queryValue_ (Query sql) client = do
val <- runQueryValue_ sql client
either liftError (pure <<< Just) $ runExcept (read val)
either liftError (pure <<< Just) $ runExcept (decode val)

-- | Connects to the database, calls the provided function with the client
-- | and returns the results.
Expand All @@ -130,8 +130,8 @@ withClient :: forall eff a
-> Aff (db :: DB | eff) a
withClient info p = runFn2 _withClient (mkConnectionString info) p

readFirst :: forall a. IsForeign a => Array Foreign -> Maybe (Either MultipleErrors a)
readFirst rows = runExcept <<< read <$> (rows !! 0)
decodeFirst :: forall a. Decode a => Array Foreign -> Maybe (Either MultipleErrors a)
decodeFirst rows = runExcept <<< decode <$> (rows !! 0)

liftError :: forall e a. MultipleErrors -> Aff e a
liftError errs = throwError $ error (show errs)
Expand Down
2 changes: 1 addition & 1 deletion src/Database/Postgres/SqlValue.purs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Data.Time (hour, minute, second)
import Unsafe.Coerce (unsafeCoerce)
import Data.Nullable (toNullable)

foreign import data SqlValue :: *
foreign import data SqlValue :: Type

class IsSqlValue a where
toSql :: a -> SqlValue
Expand Down
43 changes: 27 additions & 16 deletions test/Main.purs
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
module Test.Main where

import Prelude

import Control.Monad.Aff (Aff, apathize, attempt)
import Control.Monad.Aff.AVar (AVAR)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Class (liftEff)
import Control.Monad.Eff.Console (CONSOLE)
import Control.Monad.Eff.Exception (error)
import Control.Monad.Eff.Timer (TIMER)
import Control.Monad.Error.Class (throwError)
import Data.Array (length)
import Data.Date (canonicalDate)
import Data.DateTime (DateTime(..))
import Data.Date.Component (Month(..))
import Data.Enum (toEnum)
import Data.Time (Time(..))
import Data.DateTime (DateTime(..))
import Data.Either (either)
import Data.Enum (toEnum)
import Data.Foreign (Foreign)
import Data.Foreign.Class (class Decode, decode)
import Data.Foreign.Index (readProp)
import Data.Generic (class Generic, gEq)
import Data.JSDate (toDateTime)
import Data.Maybe (Maybe(Nothing, Just), maybe)
import Data.Foreign.Class (class IsForeign, readProp)
import Data.Generic (class Generic, gEq)
import Database.Postgres (DB, Query(Query), queryOne_, execute, execute_, withConnection, query, withClient, end, query_, connect, queryValue_, mkConnectionString)
import Data.Time (Time(..))
import Database.Postgres (DB, Query(Query), connect, end, execute, execute_, mkConnectionString, query, queryOne_, queryValue_, query_, withClient, withConnection)
import Database.Postgres.SqlValue (toSql)
import Database.Postgres.Transaction (withTransaction)
import Node.Process (PROCESS)

import Unsafe.Coerce (unsafeCoerce)

import Test.Spec (describe, it)
import Test.Spec.Runner (run)
import Test.Spec.Assertions (fail, shouldEqual)
import Test.Spec.Reporter.Console (consoleReporter)
import Test.Spec.Runner (run)
import Unsafe.Coerce (unsafeCoerce)

data Artist = Artist
{ name :: String
Expand All @@ -45,7 +47,16 @@ connectionInfo =
, password: "test"
}

main :: Eff (process :: PROCESS, console :: CONSOLE , db :: DB) Unit
main :: forall eff.
Eff
( console :: CONSOLE
, timer :: TIMER
, avar :: AVAR
, process :: PROCESS
, db :: DB
| eff
)
Unit
main = run [consoleReporter] do
describe "connection string" do
it "should build one from the connection record" do
Expand Down Expand Up @@ -111,7 +122,7 @@ main = run [consoleReporter] do
) dt


describe "transactions" do
describe "transactions" do
it "does not commit after an error inside a transation" do
withConnection connectionInfo $ \c -> do
execute_ (Query "delete from artist") c
Expand All @@ -138,8 +149,8 @@ derive instance genericArtist :: Generic Artist
instance eqArtist :: Eq Artist where
eq = gEq

instance artistIsForeign :: IsForeign Artist where
read obj = do
n <- readProp "name" obj
y <- readProp "year" obj
instance artistIsForeign :: Decode Artist where
decode obj = do
n <- decode =<< readProp "name" obj
y <- decode =<< readProp "year" obj
pure $ Artist { name: n, year: y }