-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Simple storage interface to PostgreSQL -- -- Simple storage interface to PostgreSQL @package pg-store @version 0.1.0 module Database.PostgreSQL.Store.OIDs -- | A type which can be coerced into Q Exp or Q Pat. type OIDQ = forall a. GenOID a => Q a -- | Boolean bool :: OIDQ -- | 16-bit integer int2 :: OIDQ -- | 32-bit integer int4 :: OIDQ -- | 64-bit integer int8 :: OIDQ -- | Single-precision floating-point number float4 :: OIDQ -- | Double-precision floating-point number float8 :: OIDQ -- | Arbitrary precision number numeric :: OIDQ -- | Fixed-length string char :: OIDQ -- | Variable-length string varchar :: OIDQ -- | Unlimited variable-length string text :: OIDQ -- | Byte array bytea :: OIDQ -- | Timestamp without timezone timestamp :: OIDQ -- | Timestamp with timezone timestamptz :: OIDQ instance Database.PostgreSQL.Store.OIDs.GenOID Language.Haskell.TH.Syntax.Exp instance Database.PostgreSQL.Store.OIDs.GenOID Language.Haskell.TH.Syntax.Pat module Database.PostgreSQL.Store.Columns -- | Query parameter or value of a column - see pack on how to -- generate Values manually but conveniently. data Value Value :: Oid -> ByteString -> Value -- | Type object identifier [valueType] :: Value -> Oid -- | Data value [valueData] :: Value -> ByteString NullValue :: Value -- | Types which implement this type class may be used as column types. class Column a where columnAllowNull _proxy = False columnCheck _proxy _identifier = Nothing columnDescription proxy identifier = identifier ++ " " ++ columnTypeName proxy ++ if columnAllowNull proxy then "" else " NOT NULL" ++ case columnCheck proxy identifier of { Just stmt -> " CHECK (" ++ stmt ++ ")" Nothing -> "" } -- | Pack column value. pack :: Column a => a -> Value -- | Unpack column value. unpack :: Column a => Value -> Maybe a -- | Name of the underlying SQL type. columnTypeName :: Column a => Proxy a -> String -- | May the column be NULL? columnAllowNull :: Column a => Proxy a -> Bool -- | A condition that must hold true for the column. columnCheck :: Column a => Proxy a -> String -> Maybe String -- | Generate column description in SQL. Think CREATE TABLE. columnDescription :: Column a => Proxy a -> String -> String instance GHC.Classes.Ord Database.PostgreSQL.Store.Columns.Value instance GHC.Classes.Eq Database.PostgreSQL.Store.Columns.Value instance GHC.Show.Show Database.PostgreSQL.Store.Columns.Value instance Database.PostgreSQL.Store.Columns.Column Database.PostgreSQL.Store.Columns.Value instance Database.PostgreSQL.Store.Columns.Column a => Database.PostgreSQL.Store.Columns.Column (GHC.Base.Maybe a) instance Database.PostgreSQL.Store.Columns.Column GHC.Types.Bool instance Database.PostgreSQL.Store.Columns.Column GHC.Types.Int instance Database.PostgreSQL.Store.Columns.Column GHC.Int.Int8 instance Database.PostgreSQL.Store.Columns.Column GHC.Int.Int16 instance Database.PostgreSQL.Store.Columns.Column GHC.Int.Int32 instance Database.PostgreSQL.Store.Columns.Column GHC.Int.Int64 instance Database.PostgreSQL.Store.Columns.Column GHC.Types.Word instance Database.PostgreSQL.Store.Columns.Column GHC.Word.Word8 instance Database.PostgreSQL.Store.Columns.Column GHC.Word.Word16 instance Database.PostgreSQL.Store.Columns.Column GHC.Word.Word32 instance Database.PostgreSQL.Store.Columns.Column GHC.Word.Word64 instance Database.PostgreSQL.Store.Columns.Column GHC.Integer.Type.Integer instance Database.PostgreSQL.Store.Columns.Column Data.Time.Clock.UTC.UTCTime instance Database.PostgreSQL.Store.Columns.Column [GHC.Types.Char] instance Database.PostgreSQL.Store.Columns.Column Data.Text.Internal.Text instance Database.PostgreSQL.Store.Columns.Column Data.Text.Internal.Lazy.Text instance Database.PostgreSQL.Store.Columns.Column Data.ByteString.Internal.ByteString instance Database.PostgreSQL.Store.Columns.Column Data.ByteString.Lazy.Internal.ByteString module Database.PostgreSQL.Store.Query -- | Query including statement and parameters -- -- Use the pgsq quasi-quoter to conveniently create queries. data Query Query :: !ByteString -> ![Value] -> Query -- | Statement [queryStatement] :: Query -> !ByteString -- | Parameters [queryParams] :: Query -> ![Value] -- | SELECT expression data SelectorElement -- | Select a field. The field nme will be quoted and properly escaped. SelectorField :: String -> SelectorElement -- | Select a special expression. The expression will be inlined as is. SelectorSpecial :: String -> SelectorElement -- | A type which implements this class can be used as a table in a -- quasi-quoted query. mkTable can implement this for you. class QueryTable a -- | Unquoted name of the table tableName :: QueryTable a => Proxy a -> String -- | Unquoted name of the ID field tableIDName :: QueryTable a => Proxy a -> String -- | Selectors needed to retrieve all fields necessary to construct the -- type - think SELECT. tableSelectors :: QueryTable a => Proxy a -> [SelectorElement] -- | This quasi-quoter allows you to generate instances of Query. It -- lets you write SQL with some small enhancements. pgsq heavily -- relies on QueryTable which can be implemented by -- mkTable for a type of your choice. -- -- Some syntax definitions that might be useful later on: -- --
--   TypeName          ::= UpperAlpha {AlphaNumeric | '_'}
--   Name              ::= (Alpha | '_') {AlphaNumeric | '_'}
--   QualifiedTypeName ::= {TypeName '.'} TypeName
--   
-- -- Alpha includes all alphabetical characters; -- UpperAlpha includes all upper-case alphabetical characters; -- AlphaNumeric includes all alpha-numeric characters. -- --

Embed values

-- -- You can embed values whose types implement Column. -- --
--   ValueExp ::= '$' Name
--   
-- --
--   magicNumber :: Int
--   magicNumber = 1337
--   
--   myQuery :: Query
--   myQuery =
--       [pgsq| SELECT * FROM table t WHERE t.column1 > $magicNumber AND t.column2 < $otherNumber |]
--       where otherNumber = magicNumber * 2
--   
-- -- $magicNumber and $otherNumber are references to -- values magicNumber and otherNumber. -- -- The quasi-quoter will generate a Query expression similar to -- the following. -- --
--   Query "SELECT * FROM table t WHERE t.column1 > $1 AND t.column2 < $2"
--         [pack magicNumber, pack otherNumber]
--   
-- --

Table names

-- -- Types that implement QueryTable associate a table name with -- themselves. Since the table name is not always known to the user, one -- can insert it dynamically. -- --
--   TableNameExp ::= '@' QualifiedTypeName
--   
-- -- The @-operators is also an alias for the function -- ABS. If you have an expression that triggers the quasi-quoter -- such as @A, but you would like to use the ABS -- functionality, then simply reformat your expression to @(A) -- or @"A" or ABS(A). -- --
--   instance QueryTable YourType where
--       tableName _ = "YourTable"
--   
--   myQuery :: Query
--   myQuery =
--       [pgsq| SELECT * FROM @Table WHERE @Table.column = 1337 |]
--   
-- -- The table name will be inlined which results in the following. -- --
--   Query "SELECT * FROM \"YourTable\" WHERE \"YourTable\".column = 1337" []
--   
-- --

Identifier column names

-- -- Each instance of QueryTable also provides the name of the -- identifier column. Using this column name you can identify specific -- rows of a certain table. -- --
--   TableIdentExp ::= '&' TypeName
--   
-- -- & is also the operator for bitwise-AND. To resolve the -- ambiguity for expressions like A&B, simply reformat it to -- A & B or A&(B) or A&"B". -- --
--   instance QueryTable YourType where
--       tableName _   = "YourTable"
--       tableIDName _ = "id"
--   
--   listIDs :: Query
--   listIDs =
--       [pgsq| SELECT &YourType FROM @YourType |]
--   
-- -- listIDs is now a query which lists the IDs of each row. This -- is especially useful in combination with Reference. -- --
--   fetchIDs :: Errand [Reference YourType]
--   fetchIDs =
--       query [pgsq| SELECT &YourType FROM @YourType |]
--   
-- -- Note, just like @, the operator & is reserved. -- Although A&B is a valid SQL expression, it will trigger -- the quasi-quoter. To avoid this, you reform your expression to A -- & B or A&(B). -- --

Selectors

-- -- mkTable will automatically implement Result and -- QueryTable for you. This allows you to make use of the selector -- expander. -- --
--   SelectorExp ::= '#' QualifiedTypeName
--   
-- -- # is also the operator for bitwise-XOR. To resolve the -- ambiguity for expressions like A#B, simply reformat it to -- A # B or A#(B) or A#"B". -- --
--   data Actor = Actor {
--       actorName :: String,
--       actorAge  :: Word
--   } deriving (Show, Eq, Ord)
--   
--   mkTable ''Actor []
--   
--   fetchOldActors :: Errand [Actor]
--   fetchOldActors =
--       query [pgsq| SELECT #Actor FROM @Actor a WHERE a.actorAge >= $oldAge |]
--       where oldAge = 70
--   
-- -- #Actor will expand to a list of columns that are necessary to -- construct an instance of Actor. In this case it is equivalent -- to -- --
--   @Actor.actorName, @Actor.actorAge
--   
pgsq :: QuasiQuoter -- | Just like pgsq but only produces the statement associated with -- the query. Referenced values are not inlined, they are simply -- dismissed. pgss :: QuasiQuoter -- | Properly quote an identifier. quoteIdentifier :: String -> String class QueryCode s -- | Can build o using s and [p]. class QueryBuildable s p o | s p -> o -- | Query builder type QueryBuilder s p = State (BuilderState s p) () -- | Run query builder. runQueryBuilder :: (QueryBuildable s p o, Monoid s) => QueryBuilder s p -> o -- | Write code. writeCode :: (QueryCode s) => Code s -> QueryBuilder s p -- | Write string code. writeStringCode :: (QueryCode s) => String -> QueryBuilder s p -- | Add an identifier. writeIdentifier :: (QueryCode s) => String -> QueryBuilder s p -- | Add an absolute identifier. writeAbsIdentifier :: (QueryCode s) => String -> String -> QueryBuilder s p -- | Embed a parameter. writeParam :: (QueryCode s) => p -> QueryBuilder s p -- | Embed a value parameter. writeColumn :: (Column p, QueryCode s) => p -> QueryBuilder s Value -- | Do something between other builders. intercalateBuilder :: QueryBuilder s p -> [QueryBuilder s p] -> QueryBuilder s p instance GHC.Classes.Ord Database.PostgreSQL.Store.Query.SelectorElement instance GHC.Classes.Eq Database.PostgreSQL.Store.Query.SelectorElement instance GHC.Show.Show Database.PostgreSQL.Store.Query.SelectorElement instance GHC.Classes.Ord Database.PostgreSQL.Store.Query.Query instance GHC.Classes.Eq Database.PostgreSQL.Store.Query.Query instance GHC.Show.Show Database.PostgreSQL.Store.Query.Query instance Database.PostgreSQL.Store.Query.QueryCode Data.ByteString.Internal.ByteString instance Database.PostgreSQL.Store.Query.QueryCode [Language.Haskell.TH.Syntax.Q Language.Haskell.TH.Syntax.Exp] instance Database.PostgreSQL.Store.Query.QueryCode GHC.Base.String instance Database.PostgreSQL.Store.Query.QueryBuildable Data.ByteString.Internal.ByteString Database.PostgreSQL.Store.Columns.Value Database.PostgreSQL.Store.Query.Query instance Database.PostgreSQL.Store.Query.QueryBuildable GHC.Base.String (Language.Haskell.TH.Syntax.Q Language.Haskell.TH.Syntax.Exp) (Language.Haskell.TH.Syntax.Q Language.Haskell.TH.Syntax.Exp) instance Database.PostgreSQL.Store.Query.QueryBuildable [Language.Haskell.TH.Syntax.Q Language.Haskell.TH.Syntax.Exp] (Language.Haskell.TH.Syntax.Q Language.Haskell.TH.Syntax.Exp) (Language.Haskell.TH.Syntax.Q Language.Haskell.TH.Syntax.Exp) module Database.PostgreSQL.Store.Result -- | Error that occured during result processing data ResultError -- | Occurs when you're trying to access a column that does not exist. TooFewColumnsError :: Column -> ResultError -- | The value at a given row and column could not be unpacked. UnpackError :: Row -> Column -> Oid -> Format -> ResultError -- | Result processor data ResultProcessor a -- | Process the entire result set. processResult :: Result -> ResultProcessor a -> ExceptT ResultError IO [a] -- | Process one row of the result set. processOneResult :: Result -> ResultProcessor a -> ExceptT ResultError IO (Maybe a) -- | Move cursor to the next column. skipColumn :: ResultProcessor () -- | Unpack the current column and move the cursor to the next column. unpackColumn :: (Column a) => ResultProcessor a instance Control.Monad.Error.Class.MonadError Database.PostgreSQL.Store.Result.ResultError Database.PostgreSQL.Store.Result.ResultProcessor instance Control.Monad.IO.Class.MonadIO Database.PostgreSQL.Store.Result.ResultProcessor instance GHC.Base.Monad Database.PostgreSQL.Store.Result.ResultProcessor instance GHC.Base.Applicative Database.PostgreSQL.Store.Result.ResultProcessor instance GHC.Base.Functor Database.PostgreSQL.Store.Result.ResultProcessor instance GHC.Classes.Eq Database.PostgreSQL.Store.Result.ResultError instance GHC.Show.Show Database.PostgreSQL.Store.Result.ResultError module Database.PostgreSQL.Store.Errand -- | Error during errand data ErrandError -- | No Result has been returned. NoResult :: ErrandError -- | Result set is empty. EmptyResult :: ErrandError -- | A user has thrown an error. UserError :: String -> ErrandError -- | Query execution failed. ExecError :: ExecStatus -> ErrorCode -> ByteString -> ByteString -> ByteString -> ErrandError -- | Result processing failed. ResultError :: ResultError -> ErrandError -- | Error codes data ErrorCode UnknownErrorCause :: ByteString -> ErrorCode IntegrityViolation :: ErrorCode RestrictViolation :: ErrorCode NotNullViolation :: ErrorCode ForeignKeyViolation :: ErrorCode UniqueViolation :: ErrorCode CheckViolation :: ErrorCode ExclusionViolation :: ErrorCode data ExecStatus :: * -- | The string sent to the server was empty. EmptyQuery :: ExecStatus -- | Successful completion of a command returning no data. CommandOk :: ExecStatus -- | Successful completion of a command returning data (such as a SELECT or -- SHOW). TuplesOk :: ExecStatus -- | Copy Out (from server) data transfer started. CopyOut :: ExecStatus -- | Copy In (to server) data transfer started. CopyIn :: ExecStatus -- | The server's response was not understood. BadResponse :: ExecStatus -- | A nonfatal error (a notice or warning) occurred. NonfatalError :: ExecStatus -- | A fatal error occurred. FatalError :: ExecStatus -- | The PGresult contains a single result tuple from the current command. -- This status occurs only when single-row mode has been selected for the -- query. SingleTuple :: ExecStatus -- | An interaction with the database data Errand a -- | Run an errand. runErrand :: Connection -> Errand a -> IO (Either ErrandError a) -- | Execute a query and return the internal raw result. execute :: Query -> Errand Result -- | Execute a query and process its result set. query :: (Result a) => Query -> Errand [a] -- | Execute a query and dismiss its result. query_ :: Query -> Errand () -- | Execute a query and process its result set using the provided result -- processor. queryWith :: Query -> ResultProcessor a -> Errand [a] -- | Allows you to implement a custom result parser for your type. -- mkTable can implement this for your type. class Result a queryResultProcessor :: Result a => ResultProcessor a -- | Helper type to capture an single column. newtype Single a Single :: a -> Single a [fromSingle] :: Single a -> a instance GHC.Classes.Ord a => GHC.Classes.Ord (Database.PostgreSQL.Store.Errand.Single a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Database.PostgreSQL.Store.Errand.Single a) instance Control.Monad.Error.Class.MonadError Database.PostgreSQL.Store.Errand.ErrandError Database.PostgreSQL.Store.Errand.Errand instance Control.Monad.IO.Class.MonadIO Database.PostgreSQL.Store.Errand.Errand instance GHC.Base.Monad Database.PostgreSQL.Store.Errand.Errand instance GHC.Base.Applicative Database.PostgreSQL.Store.Errand.Errand instance GHC.Base.Functor Database.PostgreSQL.Store.Errand.Errand instance GHC.Classes.Eq Database.PostgreSQL.Store.Errand.ErrandError instance GHC.Show.Show Database.PostgreSQL.Store.Errand.ErrandError instance GHC.Classes.Eq Database.PostgreSQL.Store.Errand.ErrorCode instance GHC.Show.Show Database.PostgreSQL.Store.Errand.ErrorCode instance (Database.PostgreSQL.Store.Errand.Result a, Database.PostgreSQL.Store.Errand.Result b) => Database.PostgreSQL.Store.Errand.Result (a, b) instance (Database.PostgreSQL.Store.Errand.Result a, Database.PostgreSQL.Store.Errand.Result b, Database.PostgreSQL.Store.Errand.Result c) => Database.PostgreSQL.Store.Errand.Result (a, b, c) instance (Database.PostgreSQL.Store.Errand.Result a, Database.PostgreSQL.Store.Errand.Result b, Database.PostgreSQL.Store.Errand.Result c, Database.PostgreSQL.Store.Errand.Result d) => Database.PostgreSQL.Store.Errand.Result (a, b, c, d) instance (Database.PostgreSQL.Store.Errand.Result a, Database.PostgreSQL.Store.Errand.Result b, Database.PostgreSQL.Store.Errand.Result c, Database.PostgreSQL.Store.Errand.Result d, Database.PostgreSQL.Store.Errand.Result e) => Database.PostgreSQL.Store.Errand.Result (a, b, c, d, e) instance (Database.PostgreSQL.Store.Errand.Result a, Database.PostgreSQL.Store.Errand.Result b, Database.PostgreSQL.Store.Errand.Result c, Database.PostgreSQL.Store.Errand.Result d, Database.PostgreSQL.Store.Errand.Result e, Database.PostgreSQL.Store.Errand.Result f) => Database.PostgreSQL.Store.Errand.Result (a, b, c, d, e, f) instance (Database.PostgreSQL.Store.Errand.Result a, Database.PostgreSQL.Store.Errand.Result b, Database.PostgreSQL.Store.Errand.Result c, Database.PostgreSQL.Store.Errand.Result d, Database.PostgreSQL.Store.Errand.Result e, Database.PostgreSQL.Store.Errand.Result f, Database.PostgreSQL.Store.Errand.Result g) => Database.PostgreSQL.Store.Errand.Result (a, b, c, d, e, f, g) instance GHC.Show.Show a => GHC.Show.Show (Database.PostgreSQL.Store.Errand.Single a) instance Database.PostgreSQL.Store.Columns.Column a => Database.PostgreSQL.Store.Errand.Result (Database.PostgreSQL.Store.Errand.Single a) module Database.PostgreSQL.Store.Table -- | Reference a row of type a. newtype Reference a Reference :: Int64 -> Reference a [referenceID] :: Reference a -> Int64 -- | Qualify a as a table type. mkTable can implement this -- class for you. class Table a where insertMany = mapM insert -- | Insert a row into the table and return a Reference to the -- inserted row. insert :: Table a => a -> Errand (Reference a) -- | Insert multiple rows into the table at once. insertMany :: Table a => [a] -> Errand [Reference a] -- | Find the row identified by the given reference. find :: Table a => Reference a -> Errand a -- | Update an existing row. update :: Table a => Reference a -> a -> Errand () -- | Delete a row from the table. delete :: Table a => Reference a -> Errand () -- | Generate the query which creates this table inside the database. Use -- mkCreateQuery for convenience. createTableQuery :: Table a => Proxy a -> Query -- | Generate a Query expression which will create the table -- described by the given type. -- -- Example: -- --
--   data Table = Table { myField :: Int }
--   mkTable ''Table []
--   ...
--   query_ $(mkCreateQuery ''Table)
--   
mkCreateQuery :: Name -> Q Exp -- | Options to mkTable. data TableConstraint -- | A combination of fields must be unique. Unique ['name1, 'name2, -- ...] works analogous to the table constraint UNIQUE (name1, -- name2, ...) in SQL. Unique :: [Name] -> TableConstraint -- | The given statement must evaluate to true. Just like CHECK -- (statement) in SQL. Check :: String -> TableConstraint -- | Implement the type classes QueryTable, Table and -- Result for the given type. -- -- The given type must fulfill these requirements: -- -- -- -- Example: -- --
--   {-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
--   module Movies where
--   
--   ...
--   
--   data Movie = Movie {
--       movieTitle :: String,
--       movieYear  :: Int
--   } deriving Show
--   
--   mkTable ''Movie []
--   
--   data Actor = Actor {
--       actorName :: String,
--       actorAge  :: Int
--   } deriving Show
--   
--   mkTable ''Actor [Unique ['actorName], Check [pgss| actorAge >= 18 |]]
--   
--   data MovieCast = MovieCast {
--       movieCastMovie :: Reference Movie,
--       movieCastActor :: Reference Actor
--   } deriving Show
--   
--   mkTable ''MovieCast [Unique ['movieCastMovie, 'movieCastActor]]
--   
-- -- In this example, Reference takes care of adding the FOREIGN -- KEY constraint, so we don't have to. mkTable :: Name -> [TableConstraint] -> Q [Dec] instance GHC.Classes.Ord Database.PostgreSQL.Store.Table.TableConstraint instance GHC.Classes.Eq Database.PostgreSQL.Store.Table.TableConstraint instance GHC.Show.Show Database.PostgreSQL.Store.Table.TableConstraint instance GHC.Classes.Ord (Database.PostgreSQL.Store.Table.Reference a) instance GHC.Classes.Eq (Database.PostgreSQL.Store.Table.Reference a) instance GHC.Show.Show (Database.PostgreSQL.Store.Table.Reference a) instance Database.PostgreSQL.Store.Query.QueryTable a => Database.PostgreSQL.Store.Columns.Column (Database.PostgreSQL.Store.Table.Reference a) instance Database.PostgreSQL.Store.Errand.Result (Database.PostgreSQL.Store.Table.Reference a) module Database.PostgreSQL.Store -- | An interaction with the database data Errand a -- | Error during errand data ErrandError -- | No Result has been returned. NoResult :: ErrandError -- | Result set is empty. EmptyResult :: ErrandError -- | A user has thrown an error. UserError :: String -> ErrandError -- | Query execution failed. ExecError :: ExecStatus -> ErrorCode -> ByteString -> ByteString -> ByteString -> ErrandError -- | Result processing failed. ResultError :: ResultError -> ErrandError -- | Error codes data ErrorCode UnknownErrorCause :: ByteString -> ErrorCode IntegrityViolation :: ErrorCode RestrictViolation :: ErrorCode NotNullViolation :: ErrorCode ForeignKeyViolation :: ErrorCode UniqueViolation :: ErrorCode CheckViolation :: ErrorCode ExclusionViolation :: ErrorCode data ExecStatus :: * -- | The string sent to the server was empty. EmptyQuery :: ExecStatus -- | Successful completion of a command returning no data. CommandOk :: ExecStatus -- | Successful completion of a command returning data (such as a SELECT or -- SHOW). TuplesOk :: ExecStatus -- | Copy Out (from server) data transfer started. CopyOut :: ExecStatus -- | Copy In (to server) data transfer started. CopyIn :: ExecStatus -- | The server's response was not understood. BadResponse :: ExecStatus -- | A nonfatal error (a notice or warning) occurred. NonfatalError :: ExecStatus -- | A fatal error occurred. FatalError :: ExecStatus -- | The PGresult contains a single result tuple from the current command. -- This status occurs only when single-row mode has been selected for the -- query. SingleTuple :: ExecStatus -- | Run an errand. runErrand :: Connection -> Errand a -> IO (Either ErrandError a) -- | Execute a query and return the internal raw result. execute :: Query -> Errand Result -- | Execute a query and process its result set. query :: (Result a) => Query -> Errand [a] -- | Execute a query and dismiss its result. query_ :: Query -> Errand () -- | Execute a query and process its result set using the provided result -- processor. queryWith :: Query -> ResultProcessor a -> Errand [a] -- | Query including statement and parameters -- -- Use the pgsq quasi-quoter to conveniently create queries. data Query Query :: !ByteString -> ![Value] -> Query -- | Statement [queryStatement] :: Query -> !ByteString -- | Parameters [queryParams] :: Query -> ![Value] -- | This quasi-quoter allows you to generate instances of Query. It -- lets you write SQL with some small enhancements. pgsq heavily -- relies on QueryTable which can be implemented by -- mkTable for a type of your choice. -- -- Some syntax definitions that might be useful later on: -- --
--   TypeName          ::= UpperAlpha {AlphaNumeric | '_'}
--   Name              ::= (Alpha | '_') {AlphaNumeric | '_'}
--   QualifiedTypeName ::= {TypeName '.'} TypeName
--   
-- -- Alpha includes all alphabetical characters; -- UpperAlpha includes all upper-case alphabetical characters; -- AlphaNumeric includes all alpha-numeric characters. -- --

Embed values

-- -- You can embed values whose types implement Column. -- --
--   ValueExp ::= '$' Name
--   
-- --
--   magicNumber :: Int
--   magicNumber = 1337
--   
--   myQuery :: Query
--   myQuery =
--       [pgsq| SELECT * FROM table t WHERE t.column1 > $magicNumber AND t.column2 < $otherNumber |]
--       where otherNumber = magicNumber * 2
--   
-- -- $magicNumber and $otherNumber are references to -- values magicNumber and otherNumber. -- -- The quasi-quoter will generate a Query expression similar to -- the following. -- --
--   Query "SELECT * FROM table t WHERE t.column1 > $1 AND t.column2 < $2"
--         [pack magicNumber, pack otherNumber]
--   
-- --

Table names

-- -- Types that implement QueryTable associate a table name with -- themselves. Since the table name is not always known to the user, one -- can insert it dynamically. -- --
--   TableNameExp ::= '@' QualifiedTypeName
--   
-- -- The @-operators is also an alias for the function -- ABS. If you have an expression that triggers the quasi-quoter -- such as @A, but you would like to use the ABS -- functionality, then simply reformat your expression to @(A) -- or @"A" or ABS(A). -- --
--   instance QueryTable YourType where
--       tableName _ = "YourTable"
--   
--   myQuery :: Query
--   myQuery =
--       [pgsq| SELECT * FROM @Table WHERE @Table.column = 1337 |]
--   
-- -- The table name will be inlined which results in the following. -- --
--   Query "SELECT * FROM \"YourTable\" WHERE \"YourTable\".column = 1337" []
--   
-- --

Identifier column names

-- -- Each instance of QueryTable also provides the name of the -- identifier column. Using this column name you can identify specific -- rows of a certain table. -- --
--   TableIdentExp ::= '&' TypeName
--   
-- -- & is also the operator for bitwise-AND. To resolve the -- ambiguity for expressions like A&B, simply reformat it to -- A & B or A&(B) or A&"B". -- --
--   instance QueryTable YourType where
--       tableName _   = "YourTable"
--       tableIDName _ = "id"
--   
--   listIDs :: Query
--   listIDs =
--       [pgsq| SELECT &YourType FROM @YourType |]
--   
-- -- listIDs is now a query which lists the IDs of each row. This -- is especially useful in combination with Reference. -- --
--   fetchIDs :: Errand [Reference YourType]
--   fetchIDs =
--       query [pgsq| SELECT &YourType FROM @YourType |]
--   
-- -- Note, just like @, the operator & is reserved. -- Although A&B is a valid SQL expression, it will trigger -- the quasi-quoter. To avoid this, you reform your expression to A -- & B or A&(B). -- --

Selectors

-- -- mkTable will automatically implement Result and -- QueryTable for you. This allows you to make use of the selector -- expander. -- --
--   SelectorExp ::= '#' QualifiedTypeName
--   
-- -- # is also the operator for bitwise-XOR. To resolve the -- ambiguity for expressions like A#B, simply reformat it to -- A # B or A#(B) or A#"B". -- --
--   data Actor = Actor {
--       actorName :: String,
--       actorAge  :: Word
--   } deriving (Show, Eq, Ord)
--   
--   mkTable ''Actor []
--   
--   fetchOldActors :: Errand [Actor]
--   fetchOldActors =
--       query [pgsq| SELECT #Actor FROM @Actor a WHERE a.actorAge >= $oldAge |]
--       where oldAge = 70
--   
-- -- #Actor will expand to a list of columns that are necessary to -- construct an instance of Actor. In this case it is equivalent -- to -- --
--   @Actor.actorName, @Actor.actorAge
--   
pgsq :: QuasiQuoter -- | Just like pgsq but only produces the statement associated with -- the query. Referenced values are not inlined, they are simply -- dismissed. pgss :: QuasiQuoter -- | A type which implements this class can be used as a table in a -- quasi-quoted query. mkTable can implement this for you. class QueryTable a -- | Unquoted name of the table tableName :: QueryTable a => Proxy a -> String -- | Unquoted name of the ID field tableIDName :: QueryTable a => Proxy a -> String -- | Selectors needed to retrieve all fields necessary to construct the -- type - think SELECT. tableSelectors :: QueryTable a => Proxy a -> [SelectorElement] -- | SELECT expression data SelectorElement -- | Select a field. The field nme will be quoted and properly escaped. SelectorField :: String -> SelectorElement -- | Select a special expression. The expression will be inlined as is. SelectorSpecial :: String -> SelectorElement -- | Query parameter or value of a column - see pack on how to -- generate Values manually but conveniently. data Value Value :: Oid -> ByteString -> Value -- | Type object identifier [valueType] :: Value -> Oid -- | Data value [valueData] :: Value -> ByteString NullValue :: Value -- | Types which implement this type class may be used as column types. class Column a where columnAllowNull _proxy = False columnCheck _proxy _identifier = Nothing columnDescription proxy identifier = identifier ++ " " ++ columnTypeName proxy ++ if columnAllowNull proxy then "" else " NOT NULL" ++ case columnCheck proxy identifier of { Just stmt -> " CHECK (" ++ stmt ++ ")" Nothing -> "" } -- | Pack column value. pack :: Column a => a -> Value -- | Unpack column value. unpack :: Column a => Value -> Maybe a -- | Name of the underlying SQL type. columnTypeName :: Column a => Proxy a -> String -- | May the column be NULL? columnAllowNull :: Column a => Proxy a -> Bool -- | A condition that must hold true for the column. columnCheck :: Column a => Proxy a -> String -> Maybe String -- | Generate column description in SQL. Think CREATE TABLE. columnDescription :: Column a => Proxy a -> String -> String -- | Allows you to implement a custom result parser for your type. -- mkTable can implement this for your type. class Result a queryResultProcessor :: Result a => ResultProcessor a -- | Result processor data ResultProcessor a -- | Error that occured during result processing data ResultError -- | Occurs when you're trying to access a column that does not exist. TooFewColumnsError :: Column -> ResultError -- | The value at a given row and column could not be unpacked. UnpackError :: Row -> Column -> Oid -> Format -> ResultError -- | Move cursor to the next column. skipColumn :: ResultProcessor () -- | Unpack the current column and move the cursor to the next column. unpackColumn :: (Column a) => ResultProcessor a -- | Helper type to capture an single column. newtype Single a Single :: a -> Single a [fromSingle] :: Single a -> a -- | Reference a row of type a. newtype Reference a Reference :: Int64 -> Reference a [referenceID] :: Reference a -> Int64 -- | Qualify a as a table type. mkTable can implement this -- class for you. class Table a where insertMany = mapM insert -- | Insert a row into the table and return a Reference to the -- inserted row. insert :: Table a => a -> Errand (Reference a) -- | Insert multiple rows into the table at once. insertMany :: Table a => [a] -> Errand [Reference a] -- | Find the row identified by the given reference. find :: Table a => Reference a -> Errand a -- | Update an existing row. update :: Table a => Reference a -> a -> Errand () -- | Delete a row from the table. delete :: Table a => Reference a -> Errand () -- | Generate the query which creates this table inside the database. Use -- mkCreateQuery for convenience. createTableQuery :: Table a => Proxy a -> Query -- | Generate a Query expression which will create the table -- described by the given type. -- -- Example: -- --
--   data Table = Table { myField :: Int }
--   mkTable ''Table []
--   ...
--   query_ $(mkCreateQuery ''Table)
--   
mkCreateQuery :: Name -> Q Exp -- | Implement the type classes QueryTable, Table and -- Result for the given type. -- -- The given type must fulfill these requirements: -- -- -- -- Example: -- --
--   {-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
--   module Movies where
--   
--   ...
--   
--   data Movie = Movie {
--       movieTitle :: String,
--       movieYear  :: Int
--   } deriving Show
--   
--   mkTable ''Movie []
--   
--   data Actor = Actor {
--       actorName :: String,
--       actorAge  :: Int
--   } deriving Show
--   
--   mkTable ''Actor [Unique ['actorName], Check [pgss| actorAge >= 18 |]]
--   
--   data MovieCast = MovieCast {
--       movieCastMovie :: Reference Movie,
--       movieCastActor :: Reference Actor
--   } deriving Show
--   
--   mkTable ''MovieCast [Unique ['movieCastMovie, 'movieCastActor]]
--   
-- -- In this example, Reference takes care of adding the FOREIGN -- KEY constraint, so we don't have to. mkTable :: Name -> [TableConstraint] -> Q [Dec] -- | Options to mkTable. data TableConstraint -- | A combination of fields must be unique. Unique ['name1, 'name2, -- ...] works analogous to the table constraint UNIQUE (name1, -- name2, ...) in SQL. Unique :: [Name] -> TableConstraint -- | The given statement must evaluate to true. Just like CHECK -- (statement) in SQL. Check :: String -> TableConstraint