Skip to content
Open
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 0.5.1.0

* Added
* support for JSON operators
* Many improvements to the Haddocks
* RIGHT and FULL OUTER joins

## 0.5.0.0

* Added
Expand Down
72 changes: 72 additions & 0 deletions Doc/Tutorial/TutorialBasic.lhs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
> {-# LANGUAGE FlexibleInstances #-}
> {-# LANGUAGE MultiParamTypeClasses #-}
> {-# LANGUAGE TemplateHaskell #-}
> {-# LANGUAGE OverloadedStrings #-}
>
> module TutorialBasic where
>
Expand All @@ -17,6 +18,8 @@
> showSqlForPostgres, Unpackspec,
> PGInt4, PGInt8, PGText, PGDate, PGFloat8, PGBool)
>
> import Opaleye.RunQuery
>
> import Data.Profunctor.Product (p2, p3)
> import Data.Profunctor.Product.Default (Default)
> import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
Expand All @@ -25,6 +28,7 @@
> import Control.Arrow (returnA, (<<<))
>
> import qualified Database.PostgreSQL.Simple as PGS
> import Database.PostgreSQL.Simple.FromField

Introduction
============
Expand Down Expand Up @@ -458,6 +462,74 @@ SELECT CASE WHEN boss IS NULL
FROM employeeTable


Database to Haskell types conversion
====================================

Opaleye provides default implementations that you can seamlessly
use for simple types but sometimes the types used in your database
won't get converted to your Haskell types natively.

Consider this data type:

> data User' a b c = User'
> { name :: a
> , gender :: b
> , situation :: c
> }
>
> data Gender = Female | Male | Other
> data Situation = Alive | Dead | Unknown
>
> type User = User' String Gender Situation
> type UserColumn = User' (Column PGText) (Column PGText) (Column PGText)

Opaleye won't know how to convert the postgres value 'female' to the
Haskell type `Female`. So we have to provide our own conversion
implementation. To do so, you'll have to derive QueryRunnerColumnDefault.
This can be done through 3 different ways.

FromField method
----------------

If you already have a FromField instance then you can use fieldQueryRunnerColumn
like this:

> instance FromField (Gender) where
> fromField f mdata =
> return gender
> where
> gender = case mdata of
> Just "female" -> Female
> Just "male" -> Male
> _ -> Other
>
> instance QueryRunnerColumnDefault PGText Gender where
> queryRunnerColumnDefault = fieldQueryRunnerColumn

The FromField instance is part of the Postgresql-simple package.
(https://hackage.haskell.org/package/postgresql-simple/docs/Database-PostgreSQL-Simple-FromField.html)

queryRunnerColumn method
------------------------

If you don't have a FromField instance you should use queryRunnerColumn like this:

> toSituation :: String -> Situation
> toSituation "alive" = Alive
> toSituation "dead" = Dead
> toSituation _ = Unknown
>
> instance QueryRunnerColumnDefault PGText Situation where
> queryRunnerColumnDefault = queryRunnerColumn id toSituation fieldQueryRunnerColumn

FieldParser method
------------------

For more complicated case, you can write your custom field parser and
use fieldParserQueryRunnerColumn.
Examples can be found in the source code (https://github.com/tomjaguarpaw/haskell-opaleye/blob/master/src/Opaleye/Internal/RunQuery.hs)
Like the 'FromField' method, FieldParser are part of the package postgresql-simple. (https://hackage.haskell.org/package/postgresql-simple/docs/Database-PostgreSQL-Simple-FromField.html)

Composability
=============

Expand Down
2 changes: 1 addition & 1 deletion opaleye.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: opaleye
copyright: Copyright (c) 2014-2016 Purely Agile Limited
version: 0.5.0.0
version: 0.5.1.1
synopsis: An SQL-generating DSL targeting PostgreSQL
description: An SQL-generating DSL targeting PostgreSQL. Allows
Postgres queries to be written within Haskell in a
Expand Down
56 changes: 47 additions & 9 deletions src/Opaleye/Manipulation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,51 +46,89 @@ import Data.Int (Int64)
import Data.String (fromString)
import qualified Data.List.NonEmpty as NEL

-- | Returns the number of rows inserted
-- | Insert rows into a table
runInsertMany :: PGS.Connection
-- ^
-> T.Table columns columns'
-- ^ Table to insert into
-> [columns]
-- ^ Rows to insert
-> IO Int64
-- ^ Number of rows inserted
runInsertMany conn table columns = case NEL.nonEmpty columns of
-- Inserting the empty list is just the same as returning 0
Nothing -> return 0
Just columns' -> (PGS.execute_ conn . fromString .: arrangeInsertManySql) table columns'

-- | @runInsertManyReturning@'s use of the 'D.Default' typeclass means that the
-- | Insert rows into a table and return a function of the inserted rows
--
-- @runInsertManyReturning@'s use of the 'D.Default' typeclass means that the
-- compiler will have trouble inferring types. It is strongly
-- recommended that you provide full type signatures when using
-- @runInsertManyReturning@.
runInsertManyReturning :: (D.Default RQ.QueryRunner returned haskells)
=> PGS.Connection
-- ^
-> T.Table columnsW columnsR
-- ^ Table to insert into
-> [columnsW]
-- ^ Rows to insert
-> (columnsR -> returned)
-- ^ Function @f@ to apply to the inserted rows
-> IO [haskells]
-- ^ Returned rows after @f@ has been applied
runInsertManyReturning = runInsertManyReturningExplicit D.def

-- | Where the predicate is true, update rows using the supplied
-- function.
runUpdate :: PGS.Connection -> T.Table columnsW columnsR
-> (columnsR -> columnsW) -> (columnsR -> Column PGBool)
-- | Update rows in a table
runUpdate :: PGS.Connection
-> T.Table columnsW columnsR
-- ^ Table to update
-> (columnsR -> columnsW)
-- ^ Update function to apply to chosen rows
-> (columnsR -> Column PGBool)
-- ^ Predicate function @f@ to choose which rows to update.
-- 'runUpdate' will update rows for which @f@ returns @TRUE@
-- and leave unchanged rows for which @f@ returns @FALSE@.
-> IO Int64
-- ^ The number of updated rows
runUpdate conn = PGS.execute_ conn . fromString .:. arrangeUpdateSql

-- | @runUpdateReturning@'s use of the 'D.Default' typeclass means

-- | Update rows in a table and return a function of the updated rows
--
-- @runUpdateReturning@'s use of the 'D.Default' typeclass means
-- that the compiler will have trouble inferring types. It is
-- strongly recommended that you provide full type signatures when
-- using @runInsertReturning@.
runUpdateReturning :: (D.Default RQ.QueryRunner returned haskells)
=> PGS.Connection
-- ^
-> T.Table columnsW columnsR
-- ^ Table to update
-> (columnsR -> columnsW)
-- ^ Update function to apply to chosen rows
-> (columnsR -> Column PGBool)
-- ^ Predicate function @f@ to choose which rows to
-- update. 'runUpdate' will update rows for which
-- @f@ returns @TRUE@ and leave unchanged rows for
-- which @f@ returns @FALSE@.
-> (columnsR -> returned)
-- ^ Functon @g@ to apply to the updated rows
-> IO [haskells]
-- ^ Returned rows after @g@ has been applied
runUpdateReturning = runUpdateReturningExplicit D.def

-- | Delete rows where the predicate is true.
runDelete :: PGS.Connection -> T.Table a columnsR -> (columnsR -> Column PGBool)
-- | Delete rows from a table
runDelete :: PGS.Connection
-- ^
-> T.Table a columnsR
-- ^ Table to delete rows from
-> (columnsR -> Column PGBool)
-- ^ Predicate function @f@ to choose which rows to delete.
-- 'runDelete' will delete rows for which @f@ returns @TRUE@
-- and leave unchanged rows for which @f@ returns @FALSE@.
-> IO Int64
-- ^ The number of deleted rows
runDelete conn = PGS.execute_ conn . fromString .: arrangeDeleteSql

-- | You probably don't need this, but can just use
Expand Down