packages feed

hasql-th 0.4.0.23 → 0.4.1

raw patch · 19 files changed

+1603/−1603 lines, 19 filesdep ~hasqlPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: hasql

API changes (from Hackage documentation)

Files

hasql-th.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: hasql-th-version: 0.4.0.23+version: 0.4.1 category: Hasql, Database, PostgreSQL, Template Haskell synopsis: Template Haskell utilities for Hasql description:@@ -21,10 +21,10 @@  source-repository head   type: git-  location: git://github.com/nikita-volkov/hasql-th.git+  location: https://github.com/nikita-volkov/hasql-th  library-  hs-source-dirs: library+  hs-source-dirs: src/library   default-extensions:     ApplicativeDo     Arrows@@ -83,7 +83,7 @@     containers >=0.6 && <0.8,     contravariant >=1.5.2 && <2,     foldl >=1.4.5 && <2,-    hasql >=1.4 && <1.10,+    hasql >=1.10 && <1.11,     postgresql-syntax >=0.4.1 && <0.5,     template-haskell >=2.8 && <3,     template-haskell-compat-v0208 >=0.1.9 && <2,
− library/Hasql/TH.hs
@@ -1,279 +0,0 @@-module Hasql.TH-  ( -- * Statements--    -- |-    --  Quasiquoters in this category produce Hasql `Statement`s,-    --  checking the correctness of SQL at compile-time.-    ---    --  To extract the information about parameters and results of the statement,-    --  the quoter requires you to explicitly specify the Postgres types for placeholders and results.-    ---    --  Here's an example of how to use it:-    ---    --  >selectUserDetails :: Statement Int32 (Maybe (Text, Text, Maybe Text))-    --  >selectUserDetails =-    --  >  [maybeStatement|-    --  >    select name :: text, email :: text, phone :: text?-    --  >    from "user"-    --  >    where id = $1 :: int4-    --  >    |]-    ---    --  As you can see, it completely eliminates the need to mess with codecs.-    --  The quasiquoters directly produce `Statement`,-    --  which you can then `Data.Profunctor.dimap` over using its `Data.Profunctor.Profunctor` instance to get to your domain types.-    ---    --  == Type mappings-    ---    --  === Primitives-    ---    --  Following is a list of supported Postgres types and their according types on the Haskell end.-    ---    --  - @bool@ - `Bool`-    --  - @int2@ - `Int16`-    --  - @int4@ - `Int32`-    --  - @int8@ - `Int64`-    --  - @float4@ - `Float`-    --  - @float8@ - `Double`-    --  - @numeric@ - `Data.Scientific.Scientific`-    --  - @char@ - `Char`-    --  - @text@ - `Data.Text.Text`-    --  - @bytea@ - `Data.ByteString.ByteString`-    --  - @date@ - `Data.Time.Day`-    --  - @timestamp@ - `Data.Time.LocalTime`-    --  - @timestamptz@ - `Data.Time.UTCTime`-    --  - @time@ - `Data.Time.TimeOfDay`-    --  - @timetz@ - @(`Data.Time.TimeOfDay`, `Data.Time.TimeZone`)@-    --  - @interval@ - `Data.Time.DiffTime`-    --  - @uuid@ - `Data.UUID.UUID`-    --  - @inet@ - @(`Network.IP.Addr.NetAddr` `Network.IP.Addr.IP`)@-    --  - @json@ - `Data.Aeson.Value`-    --  - @jsonb@ - `Data.Aeson.Value`-    ---    --  === Arrays-    ---    --  Array mappings are also supported.-    --  They are specified according to Postgres syntax: by appending one or more @[]@ to the primitive type,-    --  depending on how many dimensions the array has.-    --  On the Haskell end array is mapped to generic `Data.Vector.Generic.Vector`,-    --  allowing you to choose which particular vector implementation to map to.-    ---    --  === Nulls-    ---    --  As you might have noticed in the example,-    --  we introduce one change to the Postgres syntax in the way-    --  the typesignatures are parsed:-    --  we interpret question-marks in them as specification of nullability.-    --  Here's more examples of that:-    ---    --  >>> :t [singletonStatement| select a :: int4? |]-    --  ...-    --    :: Statement () (Maybe Int32)-    ---    --  You can use it to specify the nullability of array elements:-    ---    --  >>> :t [singletonStatement| select a :: int4?[] |]-    --  ...-    --    :: Data.Vector.Generic.Base.Vector v (Maybe Int32) =>-    --       Statement () (v (Maybe Int32))-    ---    --  And of arrays themselves:-    ---    --  >>> :t [singletonStatement| select a :: int4?[]? |]-    --  ...-    --    :: Data.Vector.Generic.Base.Vector v (Maybe Int32) =>-    --       Statement () (Maybe (v (Maybe Int32)))--    -- ** Row-parsing statements-    singletonStatement,-    maybeStatement,-    vectorStatement,-    foldStatement,--    -- ** Row-ignoring statements-    resultlessStatement,-    rowsAffectedStatement,--    -- * SQL ByteStrings--    -- |-    --  ByteString-producing quasiquoters.-    ---    --  For now they perform no compile-time checking.-    uncheckedSql,-    uncheckedSqlFile,-  )-where--import qualified Data.Text as Text-import qualified Data.Text.Encoding as Text-import qualified Hasql.TH.Construction.Exp as Exp-import qualified Hasql.TH.Extraction.Exp as ExpExtraction-import Hasql.TH.Prelude hiding (exp)-import Language.Haskell.TH.Quote-import Language.Haskell.TH.Syntax-import qualified PostgresqlSyntax.Ast as Ast-import qualified PostgresqlSyntax.Parsing as Parsing---- * Helpers--exp :: (String -> Q Exp) -> QuasiQuoter-exp =-  let _unsupported _ = fail "Unsupported"-   in \_exp -> QuasiQuoter _exp _unsupported _unsupported _unsupported--expParser :: (Text -> Either Text Exp) -> QuasiQuoter-expParser _parser =-  exp $ \_inputString -> either (fail . Text.unpack) return $ _parser $ fromString _inputString--expPreparableStmtAstParser :: (Ast.PreparableStmt -> Either Text Exp) -> QuasiQuoter-expPreparableStmtAstParser _parser =-  expParser $ \_input -> do-    _ast <- first fromString $ Parsing.run (Parsing.atEnd Parsing.preparableStmt) _input-    _parser _ast---- * Statement---- |--- @--- :: `Statement` params row--- @------ Statement producing exactly one result row.------ Will cause the running session to fail with the--- `Hasql.Session.UnexpectedAmountOfRows` error if it's any other.------ === __Examples__------ >>> :t [singletonStatement|select 1 :: int2|]--- ... :: Statement () Int16------ >>> :{---   :t [singletonStatement|---        insert into "user" (email, name)---        values ($1 :: text, $2 :: text)---        returning id :: int4---        |]--- :}--- ...--- ... :: Statement (Text, Text) Int32------ Incorrect SQL:------ >>> :t [singletonStatement|elect 1|]--- ...---   |--- 1 | elect 1---   |      ^--- ...-singletonStatement :: QuasiQuoter-singletonStatement = expPreparableStmtAstParser (ExpExtraction.undecodedStatement Exp.singleRowResultDecoder)---- |--- @--- :: `Statement` params (Maybe row)--- @------ Statement producing one row or none.------ === __Examples__------ >>> :t [maybeStatement|select 1 :: int2|]--- ... :: Statement () (Maybe Int16)-maybeStatement :: QuasiQuoter-maybeStatement = expPreparableStmtAstParser (ExpExtraction.undecodedStatement Exp.rowMaybeResultDecoder)---- |--- @--- :: `Statement` params (`Vector` row)--- @------ Statement producing a vector of rows.------ === __Examples__------ >>> :t [vectorStatement|select 1 :: int2|]--- ... :: Statement () (Vector Int16)-vectorStatement :: QuasiQuoter-vectorStatement = expPreparableStmtAstParser (ExpExtraction.undecodedStatement Exp.rowVectorResultDecoder)---- |--- @--- :: `Fold` row folding -> `Statement` params folding--- @------ Function from `Fold` over rows to a statement producing the result of folding.--- Use this when you need to aggregate rows customly.------ === __Examples__------ >>> :t [foldStatement|select 1 :: int2|]--- ... :: Fold Int16 b -> Statement () b-foldStatement :: QuasiQuoter-foldStatement = expPreparableStmtAstParser ExpExtraction.foldStatement---- |--- @--- :: `Statement` params ()--- @------ Statement producing no results.------ === __Examples__------ >>> :t [resultlessStatement|insert into "user" (name, email) values ($1 :: text, $2 :: text)|]--- ...--- ... :: Statement (Text, Text) ()-resultlessStatement :: QuasiQuoter-resultlessStatement = expPreparableStmtAstParser (ExpExtraction.undecodedStatement (const Exp.noResultResultDecoder))---- |--- @--- :: `Statement` params Int64--- @------ Statement counting the rows it affects.------ === __Examples__------ >>> :t [rowsAffectedStatement|delete from "user" where password is null|]--- ...--- ... :: Statement () Int64-rowsAffectedStatement :: QuasiQuoter-rowsAffectedStatement = expPreparableStmtAstParser (ExpExtraction.undecodedStatement (const Exp.rowsAffectedResultDecoder))---- * SQL ByteStrings---- |--- Quoter of a multiline Unicode SQL string,--- which gets converted into a format ready to be used for declaration of statements.-uncheckedSql :: QuasiQuoter-uncheckedSql = exp $ return . Exp.byteString . Text.encodeUtf8 . fromString---- |--- Read an SQL-file, containing multiple statements,--- and produce an expression of type `ByteString`.------ Allows to store plain SQL in external files and read it at compile time.------ E.g.,------ >migration1 :: Hasql.Session.Session ()--- >migration1 = Hasql.Session.sql [uncheckedSqlFile|migrations/1.sql|]-uncheckedSqlFile :: QuasiQuoter-uncheckedSqlFile = quoteFile uncheckedSql---- * Tests---- $--- >>> :t [maybeStatement| select (password = $2 :: bytea) :: bool, id :: int4 from "user" where "email" = $1 :: text |]--- ...--- ... Statement (Text, ByteString) (Maybe (Bool, Int32))------ >>> :t [maybeStatement| select id :: int4 from application where pub_key = $1 :: uuid and sec_key_pt1 = $2 :: int8 and sec_key_pt2 = $3 :: int8 |]--- ...--- ... Statement (UUID, Int64, Int64) (Maybe Int32)------ >>> :t [singletonStatement| select 1 :: int4 from a left join b on b.id = a.id |]--- ...--- ... Statement () Int32
− library/Hasql/TH/Construction/Exp.hs
@@ -1,201 +0,0 @@--- |--- Expression construction.-module Hasql.TH.Construction.Exp where--import qualified Data.ByteString as ByteString-import qualified Data.ByteString.Unsafe as ByteString-import qualified Data.Vector.Generic as Vector-import qualified Hasql.Decoders as Decoders-import qualified Hasql.Encoders as Encoders-import qualified Hasql.Statement as Statement-import Hasql.TH.Prelude hiding (sequence_)-import qualified Hasql.TH.Prelude as Prelude-import Language.Haskell.TH.Syntax-import qualified TemplateHaskell.Compat.V0208 as Compat---- * Helpers--appList :: Exp -> [Exp] -> Exp-appList = foldl' AppE--byteString :: ByteString -> Exp-byteString x =-  appList-    (VarE 'unsafeDupablePerformIO)-    [ appList-        (VarE 'ByteString.unsafePackAddressLen)-        [ LitE (IntegerL (fromIntegral (ByteString.length x))),-          LitE (StringPrimL (ByteString.unpack x))-        ]-    ]--integral :: (Integral a) => a -> Exp-integral x = LitE (IntegerL (fromIntegral x))--list :: (a -> Exp) -> [a] -> Exp-list renderer x = ListE (map renderer x)--string :: String -> Exp-string x = LitE (StringL x)--char :: Char -> Exp-char x = LitE (CharL x)--sequence_ :: [Exp] -> Exp-sequence_ = foldl' andThen pureUnit--pureUnit :: Exp-pureUnit = AppE (VarE 'Prelude.pure) (TupE [])--andThen :: Exp -> Exp -> Exp-andThen exp1 exp2 = AppE (AppE (VarE '(*>)) exp1) exp2--tuple :: Int -> Exp-tuple = ConE . tupleDataName--splitTupleAt :: Int -> Int -> Exp-splitTupleAt arity position =-  let nameByIndex index = Name (OccName ('_' : show index)) NameS-      names = enumFromTo 0 (pred arity) & map nameByIndex-      pats = names & map VarP-      pat = TupP pats-      exps = names & map VarE-      body = splitAt position exps & \(a, b) -> Compat.tupE [Compat.tupE a, Compat.tupE b]-   in LamE [pat] body---- |--- Given a list of divisible functor expressions,--- constructs an expression, which composes them together into--- a single divisible functor, parameterized by a tuple of according arity.-contrazip :: [Exp] -> Exp-contrazip = \case-  _head : [] -> _head-  _head : _tail -> appList (VarE 'divide) [splitTupleAt (succ (length _tail)) 1, _head, contrazip _tail]-  [] ->-    SigE-      (VarE 'conquer)-      ( let _fName = mkName "f"-            _fVar = VarT _fName-         in ForallT-              [Compat.specifiedPlainTV _fName]-              [AppT (ConT ''Divisible) (VarT _fName)]-              (AppT (VarT _fName) (TupleT 0))-      )---- |--- Given a list of applicative functor expressions,--- constructs an expression, which composes them together into--- a single applicative functor, parameterized by a tuple of according arity.------ >>> $(return (cozip [])) :: Maybe ()--- Just ()------ >>> $(return (cozip (fmap (AppE (ConE 'Just) . LitE . IntegerL) [1,2,3]))) :: Maybe (Int, Int, Int)--- Just (1,2,3)-cozip :: [Exp] -> Exp-cozip = \case-  _head : [] -> _head-  _head : _tail ->-    let _length = length _tail + 1-     in foldl'-          (\a b -> AppE (AppE (VarE '(<*>)) a) b)-          (AppE (AppE (VarE 'fmap) (tuple _length)) _head)-          _tail-  [] -> AppE (VarE 'pure) (TupE [])---- |--- Lambda expression, which destructures 'Fold'.-foldLam :: (Exp -> Exp -> Exp -> Exp) -> Exp-foldLam _body =-  let _stepVarName = mkName "progress"-      _initVarName = mkName "start"-      _extractVarName = mkName "finish"-   in LamE-        [ Compat.conP-            'Fold-            [ VarP _stepVarName,-              VarP _initVarName,-              VarP _extractVarName-            ]-        ]-        (_body (VarE _stepVarName) (VarE _initVarName) (VarE _extractVarName))---- * Statement--statement :: Exp -> Exp -> Exp -> Exp-statement _sql _encoder _decoder =-  appList (ConE 'Statement.Statement) [_sql, _encoder, _decoder, ConE 'True]--noResultResultDecoder :: Exp-noResultResultDecoder = VarE 'Decoders.noResult--rowsAffectedResultDecoder :: Exp-rowsAffectedResultDecoder = VarE 'Decoders.rowsAffected--singleRowResultDecoder :: Exp -> Exp-singleRowResultDecoder = 'Decoders.singleRow & VarE & AppE--rowMaybeResultDecoder :: Exp -> Exp-rowMaybeResultDecoder = AppE (VarE 'Decoders.rowMaybe)--rowVectorResultDecoder :: Exp -> Exp-rowVectorResultDecoder = AppE (VarE 'Decoders.rowVector)--foldStatement :: Exp -> Exp -> Exp -> Exp-foldStatement _sql _encoder _rowDecoder =-  foldLam (\_step _init _extract -> statement _sql _encoder (foldResultDecoder _step _init _extract _rowDecoder))--foldResultDecoder :: Exp -> Exp -> Exp -> Exp -> Exp-foldResultDecoder _step _init _extract _rowDecoder =-  appList (VarE 'fmap) [_extract, appList (VarE 'Decoders.foldlRows) [_step, _init, _rowDecoder]]--unidimensionalParamEncoder :: Bool -> Exp -> Exp-unidimensionalParamEncoder nullable =-  applyParamToEncoder . applyNullabilityToEncoder nullable--multidimensionalParamEncoder :: Bool -> Int -> Bool -> Exp -> Exp-multidimensionalParamEncoder nullable dimensionality arrayNull =-  applyParamToEncoder-    . applyNullabilityToEncoder arrayNull-    . AppE (VarE 'Encoders.array)-    . applyArrayDimensionalityToEncoder dimensionality-    . applyNullabilityToEncoder nullable--applyParamToEncoder :: Exp -> Exp-applyParamToEncoder = AppE (VarE 'Encoders.param)--applyNullabilityToEncoder :: Bool -> Exp -> Exp-applyNullabilityToEncoder nullable = AppE (VarE (if nullable then 'Encoders.nullable else 'Encoders.nonNullable))--applyArrayDimensionalityToEncoder :: Int -> Exp -> Exp-applyArrayDimensionalityToEncoder levels =-  if levels > 0-    then AppE (AppE (VarE 'Encoders.dimension) (VarE 'Vector.foldl')) . applyArrayDimensionalityToEncoder (pred levels)-    else AppE (VarE 'Encoders.element)--rowDecoder :: [Exp] -> Exp-rowDecoder = cozip--unidimensionalColumnDecoder :: Bool -> Exp -> Exp-unidimensionalColumnDecoder nullable =-  applyColumnToDecoder . applyNullabilityToDecoder nullable--multidimensionalColumnDecoder :: Bool -> Int -> Bool -> Exp -> Exp-multidimensionalColumnDecoder nullable dimensionality arrayNull =-  applyColumnToDecoder-    . applyNullabilityToDecoder arrayNull-    . AppE (VarE 'Decoders.array)-    . applyArrayDimensionalityToDecoder dimensionality-    . applyNullabilityToDecoder nullable--applyColumnToDecoder :: Exp -> Exp-applyColumnToDecoder = AppE (VarE 'Decoders.column)--applyNullabilityToDecoder :: Bool -> Exp -> Exp-applyNullabilityToDecoder nullable = AppE (VarE (if nullable then 'Decoders.nullable else 'Decoders.nonNullable))--applyArrayDimensionalityToDecoder :: Int -> Exp -> Exp-applyArrayDimensionalityToDecoder levels =-  if levels > 0-    then AppE (AppE (VarE 'Decoders.dimension) (VarE 'Vector.replicateM)) . applyArrayDimensionalityToDecoder (pred levels)-    else AppE (VarE 'Decoders.element)
− library/Hasql/TH/Extraction/ChildExprList.hs
@@ -1,611 +0,0 @@-{-# OPTIONS_GHC -Wno-missing-signatures #-}--module Hasql.TH.Extraction.ChildExprList where--import Hasql.TH.Prelude hiding (bit, fromList, sortBy)-import PostgresqlSyntax.Ast---- * Types--data ChildExpr = AChildExpr AExpr | BChildExpr BExpr | CChildExpr CExpr-  deriving (Show, Eq, Ord)---- |--- Dives one level of recursion.-childExpr = \case-  AChildExpr a -> aChildExpr a-  BChildExpr a -> bChildExpr a-  CChildExpr a -> cChildExpr a--aChildExpr = \case-  CExprAExpr a -> cChildExpr a-  TypecastAExpr a b -> aExpr a <> typename b-  CollateAExpr a b -> aExpr a <> anyName b-  AtTimeZoneAExpr a b -> aExpr a <> aExpr b-  PlusAExpr a -> aExpr a-  MinusAExpr a -> aExpr a-  SymbolicBinOpAExpr a b c -> aExpr a <> symbolicExprBinOp b <> aExpr c-  PrefixQualOpAExpr a b -> qualOp a <> aExpr b-  SuffixQualOpAExpr a b -> aExpr a <> qualOp b-  AndAExpr a b -> aExpr a <> aExpr b-  OrAExpr a b -> aExpr a <> aExpr b-  NotAExpr a -> aExpr a-  VerbalExprBinOpAExpr a b c d e -> aExpr a <> verbalExprBinOp c <> aExpr d <> foldMap aExpr e-  ReversableOpAExpr a b c -> aExpr a <> aExprReversableOp c-  IsnullAExpr a -> aExpr a-  NotnullAExpr a -> aExpr a-  OverlapsAExpr a b -> row a <> row b-  SubqueryAExpr a b c d -> aExpr a <> subqueryOp b <> subType c <> either selectWithParens aExpr d-  UniqueAExpr a -> selectWithParens a-  DefaultAExpr -> []--bChildExpr = \case-  CExprBExpr a -> cChildExpr a-  TypecastBExpr a b -> bExpr a <> typename b-  PlusBExpr a -> bExpr a-  MinusBExpr a -> bExpr a-  SymbolicBinOpBExpr a b c -> bExpr a <> symbolicExprBinOp b <> bExpr c-  QualOpBExpr a b -> qualOp a <> bExpr b-  IsOpBExpr a b c -> bExpr a <> bExprIsOp c--cChildExpr = \case-  ColumnrefCExpr a -> columnref a-  AexprConstCExpr a -> aexprConst a-  ParamCExpr a b -> foldMap indirection b-  InParensCExpr a b -> aExpr a <> foldMap indirection b-  CaseCExpr a -> caseExpr a-  FuncCExpr a -> funcExpr a-  SelectWithParensCExpr a b -> selectWithParens a <> foldMap indirection b-  ExistsCExpr a -> selectWithParens a-  ArrayCExpr a -> either selectWithParens arrayExpr a-  ExplicitRowCExpr a -> explicitRow a-  ImplicitRowCExpr a -> implicitRow a-  GroupingCExpr a -> exprList a--preparableStmt = \case-  SelectPreparableStmt a -> selectStmt a-  InsertPreparableStmt a -> insertStmt a-  UpdatePreparableStmt a -> updateStmt a-  DeletePreparableStmt a -> deleteStmt a-  CallPreparableStmt a -> callStmt a---- * Call--callStmt (CallStmt a) = funcApplication a---- * Insert--insertStmt (InsertStmt a b c d e) =-  foldMap withClause a-    <> insertTarget b-    <> insertRest c-    <> foldMap onConflict d-    <> foldMap returningClause e--insertTarget (InsertTarget a b) = qualifiedName a <> colId b--insertRest = \case-  SelectInsertRest a b c -> foldMap insertColumnList a <> foldMap overrideKind b <> selectStmt c-  DefaultValuesInsertRest -> []--overrideKind _ = []--insertColumnList = foldMap insertColumnItem--insertColumnItem (InsertColumnItem a b) = colId a <> foldMap indirection b--onConflict (OnConflict a b) = foldMap confExpr a <> onConflictDo b--onConflictDo = \case-  UpdateOnConflictDo b c -> setClauseList b <> foldMap whereClause c-  NothingOnConflictDo -> []--confExpr = \case-  WhereConfExpr a b -> indexParams a <> foldMap whereClause b-  ConstraintConfExpr a -> name a--returningClause = targetList---- * Update--updateStmt (UpdateStmt a b c d e f) =-  foldMap withClause a-    <> relationExprOptAlias b-    <> setClauseList c-    <> foldMap fromClause d-    <> foldMap whereOrCurrentClause e-    <> foldMap returningClause f--setClauseList = foldMap setClause--setClause = \case-  TargetSetClause a b -> setTarget a <> aExpr b-  TargetListSetClause a b -> setTargetList a <> aExpr b--setTarget (SetTarget a b) = colId a <> foldMap indirection b--setTargetList = foldMap setTarget---- * Delete--deleteStmt (DeleteStmt a b c d e) =-  foldMap withClause a-    <> relationExprOptAlias b-    <> foldMap usingClause c-    <> foldMap whereOrCurrentClause d-    <> foldMap returningClause e--usingClause = fromList---- * Select--selectStmt = \case-  Left a -> selectNoParens a-  Right a -> selectWithParens a--selectNoParens (SelectNoParens a b c d e) =-  foldMap withClause a-    <> selectClause b-    <> foldMap sortClause c-    <> foldMap selectLimit d-    <> foldMap forLockingClause e--selectWithParens = \case-  NoParensSelectWithParens a -> selectNoParens a-  WithParensSelectWithParens a -> selectWithParens a--withClause (WithClause _ a) = foldMap commonTableExpr a--commonTableExpr (CommonTableExpr a b c d) = preparableStmt d--selectLimit = \case-  LimitOffsetSelectLimit a b -> limitClause a <> offsetClause b-  OffsetLimitSelectLimit a b -> offsetClause a <> limitClause b-  LimitSelectLimit a -> limitClause a-  OffsetSelectLimit a -> offsetClause a--limitClause = \case-  LimitLimitClause a b -> selectLimitValue a <> exprList b-  FetchOnlyLimitClause a b c -> foldMap selectFetchFirstValue b--offsetClause = \case-  ExprOffsetClause a -> aExpr a-  FetchFirstOffsetClause a b -> selectFetchFirstValue a--selectFetchFirstValue = \case-  ExprSelectFetchFirstValue a -> cExpr a-  NumSelectFetchFirstValue _ _ -> []--selectLimitValue = \case-  ExprSelectLimitValue a -> aExpr a-  AllSelectLimitValue -> []--forLockingClause = \case-  ItemsForLockingClause a -> foldMap forLockingItem a-  ReadOnlyForLockingClause -> []--forLockingItem (ForLockingItem a b c) =-  foldMap (foldMap qualifiedName) b--selectClause = either simpleSelect selectWithParens--simpleSelect = \case-  NormalSimpleSelect a b c d e f g ->-    foldMap targeting a-      <> foldMap intoClause b-      <> foldMap fromClause c-      <> foldMap whereClause d-      <> foldMap groupClause e-      <> foldMap havingClause f-      <> foldMap windowClause g-  ValuesSimpleSelect a -> valuesClause a-  TableSimpleSelect a -> relationExpr a-  BinSimpleSelect _ a _ b -> selectClause a <> selectClause b--targeting = \case-  NormalTargeting a -> foldMap targetEl a-  AllTargeting a -> foldMap (foldMap targetEl) a-  DistinctTargeting a b -> foldMap exprList a <> foldMap targetEl b--targetList = foldMap targetEl--targetEl = \case-  AliasedExprTargetEl a _ -> aExpr a-  ImplicitlyAliasedExprTargetEl a _ -> aExpr a-  ExprTargetEl a -> aExpr a-  AsteriskTargetEl -> []--intoClause = optTempTableName--fromClause = fromList--fromList = foldMap tableRef--whereClause = aExpr--whereOrCurrentClause = \case-  ExprWhereOrCurrentClause a -> aExpr a-  CursorWhereOrCurrentClause a -> cursorName a--groupClause = foldMap groupByItem--havingClause = aExpr--windowClause = foldMap windowDefinition--valuesClause = foldMap exprList--optTempTableName _ = []--groupByItem = \case-  ExprGroupByItem a -> aExpr a-  EmptyGroupingSetGroupByItem -> []-  RollupGroupByItem a -> exprList a-  CubeGroupByItem a -> exprList a-  GroupingSetsGroupByItem a -> foldMap groupByItem a--windowDefinition (WindowDefinition _ a) = windowSpecification a--windowSpecification (WindowSpecification _ a b c) = foldMap (foldMap aExpr) a <> foldMap sortClause b <> foldMap frameClause c--frameClause (FrameClause _ a _) = frameExtent a--frameExtent = \case-  SingularFrameExtent a -> frameBound a-  BetweenFrameExtent a b -> frameBound a <> frameBound b--frameBound = \case-  UnboundedPrecedingFrameBound -> []-  UnboundedFollowingFrameBound -> []-  CurrentRowFrameBound -> []-  PrecedingFrameBound a -> aExpr a-  FollowingFrameBound a -> aExpr a--sortClause = foldMap sortBy--sortBy = \case-  UsingSortBy a b c -> aExpr a <> qualAllOp b <> foldMap nullsOrder c-  AscDescSortBy a b c -> aExpr a <> foldMap ascDesc b <> foldMap nullsOrder c---- * Table refs--tableRef = \case-  RelationExprTableRef a b c -> relationExpr a <> foldMap aliasClause b <> foldMap tablesampleClause c-  FuncTableRef a b c -> funcTable b <> foldMap funcAliasClause c-  SelectTableRef _ a _ -> selectWithParens a-  JoinTableRef a _ -> joinedTable a--relationExpr = \case-  SimpleRelationExpr a _ -> qualifiedName a-  OnlyRelationExpr a _ -> qualifiedName a--relationExprOptAlias (RelationExprOptAlias a b) = relationExpr a <> foldMap (colId . snd) b--tablesampleClause (TablesampleClause a b c) = funcName a <> exprList b <> foldMap repeatableClause c--repeatableClause = aExpr--funcTable = \case-  FuncExprFuncTable a b -> funcExprWindowless a <> optOrdinality b-  RowsFromFuncTable a b -> rowsfromList a <> optOrdinality b--rowsfromItem (RowsfromItem a b) = funcExprWindowless a <> foldMap colDefList b--rowsfromList = foldMap rowsfromItem--colDefList = tableFuncElementList--optOrdinality = const []--tableFuncElementList = foldMap tableFuncElement--tableFuncElement (TableFuncElement a b c) = colId a <> typename b <> foldMap collateClause c--collateClause = anyName--aliasClause = const []--funcAliasClause = \case-  AliasFuncAliasClause a -> aliasClause a-  AsFuncAliasClause a -> tableFuncElementList a-  AsColIdFuncAliasClause a b -> colId a <> tableFuncElementList b-  ColIdFuncAliasClause a b -> colId a <> tableFuncElementList b--joinedTable = \case-  InParensJoinedTable a -> joinedTable a-  MethJoinedTable a b c -> joinMeth a <> tableRef b <> tableRef c--joinMeth = \case-  CrossJoinMeth -> []-  QualJoinMeth _ a -> joinQual a-  NaturalJoinMeth _ -> []--joinQual = \case-  UsingJoinQual _ -> []-  OnJoinQual a -> aExpr a--exprList = fmap AChildExpr . toList--aExpr = pure . AChildExpr--bExpr = pure . BChildExpr--cExpr = pure . CChildExpr--funcExpr = \case-  ApplicationFuncExpr a b c d -> funcApplication a <> foldMap withinGroupClause b <> foldMap filterClause c <> foldMap overClause d-  SubexprFuncExpr a -> funcExprCommonSubexpr a--funcExprWindowless = \case-  ApplicationFuncExprWindowless a -> funcApplication a-  CommonSubexprFuncExprWindowless a -> funcExprCommonSubexpr a--withinGroupClause = sortClause--filterClause a = aExpr a--overClause = \case-  WindowOverClause a -> windowSpecification a-  ColIdOverClause _ -> []--funcExprCommonSubexpr = \case-  CollationForFuncExprCommonSubexpr a -> aExpr a-  CurrentDateFuncExprCommonSubexpr -> []-  CurrentTimeFuncExprCommonSubexpr _ -> []-  CurrentTimestampFuncExprCommonSubexpr _ -> []-  LocalTimeFuncExprCommonSubexpr _ -> []-  LocalTimestampFuncExprCommonSubexpr _ -> []-  CurrentRoleFuncExprCommonSubexpr -> []-  CurrentUserFuncExprCommonSubexpr -> []-  SessionUserFuncExprCommonSubexpr -> []-  UserFuncExprCommonSubexpr -> []-  CurrentCatalogFuncExprCommonSubexpr -> []-  CurrentSchemaFuncExprCommonSubexpr -> []-  CastFuncExprCommonSubexpr a b -> aExpr a <> typename b-  ExtractFuncExprCommonSubexpr a -> foldMap extractList a-  OverlayFuncExprCommonSubexpr a -> overlayList a-  PositionFuncExprCommonSubexpr a -> foldMap positionList a-  SubstringFuncExprCommonSubexpr a -> foldMap substrList a-  TreatFuncExprCommonSubexpr a b -> aExpr a <> typename b-  TrimFuncExprCommonSubexpr a b -> foldMap trimModifier a <> trimList b-  NullIfFuncExprCommonSubexpr a b -> aExpr a <> aExpr b-  CoalesceFuncExprCommonSubexpr a -> exprList a-  GreatestFuncExprCommonSubexpr a -> exprList a-  LeastFuncExprCommonSubexpr a -> exprList a--extractList (ExtractList a b) = extractArg a <> aExpr b--extractArg _ = []--overlayList (OverlayList a b c d) = foldMap aExpr ([a, b, c] <> toList d)--positionList (PositionList a b) = bExpr a <> bExpr b--substrList = \case-  ExprSubstrList a b -> aExpr a <> substrListFromFor b-  ExprListSubstrList a -> exprList a--substrListFromFor = \case-  FromForSubstrListFromFor a b -> aExpr a <> aExpr b-  ForFromSubstrListFromFor a b -> aExpr a <> aExpr b-  FromSubstrListFromFor a -> aExpr a-  ForSubstrListFromFor a -> aExpr a--trimModifier _ = []--trimList = \case-  ExprFromExprListTrimList a b -> aExpr a <> exprList b-  FromExprListTrimList a -> exprList a-  ExprListTrimList a -> exprList a--whenClause (WhenClause a b) = aExpr a <> aExpr b--funcApplication (FuncApplication a b) = funcName a <> foldMap funcApplicationParams b--funcApplicationParams = \case-  NormalFuncApplicationParams _ a b -> foldMap funcArgExpr a <> foldMap (foldMap sortBy) b-  VariadicFuncApplicationParams a b c -> foldMap (foldMap funcArgExpr) a <> funcArgExpr b <> foldMap (foldMap sortBy) c-  StarFuncApplicationParams -> []--funcArgExpr = \case-  ExprFuncArgExpr a -> aExpr a-  ColonEqualsFuncArgExpr _ a -> aExpr a-  EqualsGreaterFuncArgExpr _ a -> aExpr a--caseExpr (CaseExpr a b c) = foldMap aExpr a <> whenClauseList b <> foldMap aExpr c--whenClauseList = foldMap whenClause--arrayExpr = \case-  ExprListArrayExpr a -> exprList a-  ArrayExprListArrayExpr a -> arrayExprList a-  EmptyArrayExpr -> []--arrayExprList = foldMap arrayExpr--inExpr = \case-  SelectInExpr a -> selectWithParens a-  ExprListInExpr a -> exprList a---- * Operators--symbolicExprBinOp = \case-  MathSymbolicExprBinOp a -> mathOp a-  QualSymbolicExprBinOp a -> qualOp a--qualOp = \case-  OpQualOp a -> op a-  OperatorQualOp a -> anyOperator a--qualAllOp = \case-  AllQualAllOp a -> allOp a-  AnyQualAllOp a -> anyOperator a--verbalExprBinOp = const []--aExprReversableOp = \case-  NullAExprReversableOp -> []-  TrueAExprReversableOp -> []-  FalseAExprReversableOp -> []-  UnknownAExprReversableOp -> []-  DistinctFromAExprReversableOp a -> aExpr a-  OfAExprReversableOp a -> typeList a-  BetweenAExprReversableOp a b c -> bExpr b <> aExpr c-  BetweenSymmetricAExprReversableOp a b -> bExpr a <> aExpr b-  InAExprReversableOp a -> inExpr a-  DocumentAExprReversableOp -> []--subqueryOp = \case-  AllSubqueryOp a -> allOp a-  AnySubqueryOp a -> anyOperator a-  LikeSubqueryOp _ -> []-  IlikeSubqueryOp _ -> []--bExprIsOp = \case-  DistinctFromBExprIsOp a -> bExpr a-  OfBExprIsOp a -> typeList a-  DocumentBExprIsOp -> []--allOp = \case-  OpAllOp a -> op a-  MathAllOp a -> mathOp a--anyOperator = \case-  AllOpAnyOperator a -> allOp a-  QualifiedAnyOperator a b -> colId a <> anyOperator b--op = const []--mathOp = const []---- * Rows--row = \case-  ExplicitRowRow a -> explicitRow a-  ImplicitRowRow a -> implicitRow a--explicitRow = foldMap exprList--implicitRow (ImplicitRow a b) = exprList a <> aExpr b---- * Constants--aexprConst = \case-  IAexprConst _ -> []-  FAexprConst _ -> []-  SAexprConst _ -> []-  BAexprConst _ -> []-  XAexprConst _ -> []-  FuncAexprConst a b _ -> funcName a <> foldMap funcConstArgs b-  ConstTypenameAexprConst a _ -> constTypename a-  StringIntervalAexprConst _ a -> foldMap interval a-  IntIntervalAexprConst _ _ -> []-  BoolAexprConst _ -> []-  NullAexprConst -> []--funcConstArgs (FuncConstArgs a b) = foldMap funcArgExpr a <> foldMap sortClause b--constTypename = \case-  NumericConstTypename a -> numeric a-  ConstBitConstTypename a -> constBit a-  ConstCharacterConstTypename a -> constCharacter a-  ConstDatetimeConstTypename a -> constDatetime a--numeric = \case-  IntNumeric -> []-  IntegerNumeric -> []-  SmallintNumeric -> []-  BigintNumeric -> []-  RealNumeric -> []-  FloatNumeric _ -> []-  DoublePrecisionNumeric -> []-  DecimalNumeric a -> foldMap exprList a-  DecNumeric a -> foldMap exprList a-  NumericNumeric a -> foldMap exprList a-  BooleanNumeric -> []--bit (Bit _ a) = foldMap exprList a--constBit = bit--constCharacter (ConstCharacter _ _) = []--constDatetime _ = []--interval _ = []---- * Names--ident _ = []--colId = ident--name = colId--cursorName = name--anyName (AnyName a b) = colId a <> foldMap attrs b--columnref (Columnref a b) = colId a <> foldMap indirection b--funcName = \case-  TypeFuncName a -> typeFunctionName a-  IndirectedFuncName a b -> colId a <> indirection b--qualifiedName = \case-  SimpleQualifiedName _ -> []-  IndirectedQualifiedName _ a -> indirection a--indirection = foldMap indirectionEl--indirectionEl = \case-  AttrNameIndirectionEl _ -> []-  AllIndirectionEl -> []-  ExprIndirectionEl a -> aExpr a-  SliceIndirectionEl a b -> exprList a <> exprList b---- * Types--typeList = foldMap typename--typename (Typename a b c d) =-  simpleTypename b--simpleTypename = \case-  GenericTypeSimpleTypename a -> genericType a-  NumericSimpleTypename a -> numeric a-  BitSimpleTypename a -> bit a-  CharacterSimpleTypename a -> character a-  ConstDatetimeSimpleTypename a -> constDatetime a-  ConstIntervalSimpleTypename a -> either (foldMap interval) (const []) a--arrayBounds _ = []--genericType (GenericType a b c) = typeFunctionName a <> foldMap attrs b <> foldMap typeModifiers c--typeFunctionName = ident--attrs = foldMap attrName--attrName _ = []--typeModifiers = exprList--character _ = []--subType _ = []---- * Indexes--indexParams = foldMap indexElem--indexElem (IndexElem a b c d e) = indexElemDef a <> foldMap anyName b <> foldMap anyName c--indexElemDef = \case-  IdIndexElemDef a -> colId a-  FuncIndexElemDef a -> funcExprWindowless a-  ExprIndexElemDef a -> aExpr a--ascDesc = const []--nullsOrder = const []
− library/Hasql/TH/Extraction/Exp.hs
@@ -1,112 +0,0 @@-module Hasql.TH.Extraction.Exp where--import qualified Hasql.Decoders as Decoders-import qualified Hasql.Encoders as Encoders-import qualified Hasql.TH.Construction.Exp as Exp-import qualified Hasql.TH.Extraction.InputTypeList as InputTypeList-import qualified Hasql.TH.Extraction.OutputTypeList as OutputTypeList-import qualified Hasql.TH.Extraction.PrimitiveType as PrimitiveType-import Hasql.TH.Prelude-import Language.Haskell.TH-import qualified PostgresqlSyntax.Ast as Ast-import qualified PostgresqlSyntax.Rendering as Rendering--undecodedStatement :: (Exp -> Exp) -> Ast.PreparableStmt -> Either Text Exp-undecodedStatement _decoderProj _ast =-  let _sql = (Exp.byteString . Rendering.toByteString . Rendering.preparableStmt) _ast-   in do-        _encoder <- paramsEncoder _ast-        _rowDecoder <- rowDecoder _ast-        return (Exp.statement _sql _encoder (_decoderProj _rowDecoder))--foldStatement :: Ast.PreparableStmt -> Either Text Exp-foldStatement _ast =-  let _sql = (Exp.byteString . Rendering.toByteString . Rendering.preparableStmt) _ast-   in do-        _encoder <- paramsEncoder _ast-        _rowDecoder <- rowDecoder _ast-        return (Exp.foldStatement _sql _encoder _rowDecoder)--paramsEncoder :: Ast.PreparableStmt -> Either Text Exp-paramsEncoder a = do-  b <- InputTypeList.preparableStmt a-  c <- traverse paramEncoder b-  return (Exp.contrazip c)--rowDecoder :: Ast.PreparableStmt -> Either Text Exp-rowDecoder a = do-  b <- OutputTypeList.preparableStmt a-  c <- traverse columnDecoder b-  return (Exp.cozip c)--paramEncoder :: Ast.Typename -> Either Text Exp-paramEncoder =-  byTypename-    (\a b -> valueEncoder a & fmap (Exp.unidimensionalParamEncoder b))-    (\a b c d -> valueEncoder a & fmap (Exp.multidimensionalParamEncoder b c d))--columnDecoder :: Ast.Typename -> Either Text Exp-columnDecoder =-  byTypename-    (\a b -> valueDecoder a & fmap (Exp.unidimensionalColumnDecoder b))-    (\a b c d -> valueDecoder a & fmap (Exp.multidimensionalColumnDecoder b c d))--byTypename :: (PrimitiveType.PrimitiveType -> Bool -> Either Text Exp) -> (PrimitiveType.PrimitiveType -> Bool -> Int -> Bool -> Either Text Exp) -> Ast.Typename -> Either Text Exp-byTypename unidimensional multidimensional (Ast.Typename a b c d) =-  if a-    then Left "SETOF is not supported"-    else do-      e <- PrimitiveType.simpleTypename b-      case d of-        Nothing -> unidimensional e c-        Just (f, g) -> case f of-          Ast.BoundsTypenameArrayDimensions h -> multidimensional e c (length h) g-          Ast.ExplicitTypenameArrayDimensions _ -> multidimensional e c 1 g--valueEncoder :: PrimitiveType.PrimitiveType -> Either Text Exp-valueEncoder =-  Right . VarE . \case-    PrimitiveType.BoolPrimitiveType -> 'Encoders.bool-    PrimitiveType.Int2PrimitiveType -> 'Encoders.int2-    PrimitiveType.Int4PrimitiveType -> 'Encoders.int4-    PrimitiveType.Int8PrimitiveType -> 'Encoders.int8-    PrimitiveType.Float4PrimitiveType -> 'Encoders.float4-    PrimitiveType.Float8PrimitiveType -> 'Encoders.float8-    PrimitiveType.NumericPrimitiveType -> 'Encoders.numeric-    PrimitiveType.CharPrimitiveType -> 'Encoders.char-    PrimitiveType.TextPrimitiveType -> 'Encoders.text-    PrimitiveType.ByteaPrimitiveType -> 'Encoders.bytea-    PrimitiveType.DatePrimitiveType -> 'Encoders.date-    PrimitiveType.TimestampPrimitiveType -> 'Encoders.timestamp-    PrimitiveType.TimestamptzPrimitiveType -> 'Encoders.timestamptz-    PrimitiveType.TimePrimitiveType -> 'Encoders.time-    PrimitiveType.TimetzPrimitiveType -> 'Encoders.timetz-    PrimitiveType.IntervalPrimitiveType -> 'Encoders.interval-    PrimitiveType.UuidPrimitiveType -> 'Encoders.uuid-    PrimitiveType.InetPrimitiveType -> 'Encoders.inet-    PrimitiveType.JsonPrimitiveType -> 'Encoders.json-    PrimitiveType.JsonbPrimitiveType -> 'Encoders.jsonb--valueDecoder :: PrimitiveType.PrimitiveType -> Either Text Exp-valueDecoder =-  Right . VarE . \case-    PrimitiveType.BoolPrimitiveType -> 'Decoders.bool-    PrimitiveType.Int2PrimitiveType -> 'Decoders.int2-    PrimitiveType.Int4PrimitiveType -> 'Decoders.int4-    PrimitiveType.Int8PrimitiveType -> 'Decoders.int8-    PrimitiveType.Float4PrimitiveType -> 'Decoders.float4-    PrimitiveType.Float8PrimitiveType -> 'Decoders.float8-    PrimitiveType.NumericPrimitiveType -> 'Decoders.numeric-    PrimitiveType.CharPrimitiveType -> 'Decoders.char-    PrimitiveType.TextPrimitiveType -> 'Decoders.text-    PrimitiveType.ByteaPrimitiveType -> 'Decoders.bytea-    PrimitiveType.DatePrimitiveType -> 'Decoders.date-    PrimitiveType.TimestampPrimitiveType -> 'Decoders.timestamp-    PrimitiveType.TimestamptzPrimitiveType -> 'Decoders.timestamptz-    PrimitiveType.TimePrimitiveType -> 'Decoders.time-    PrimitiveType.TimetzPrimitiveType -> 'Decoders.timetz-    PrimitiveType.IntervalPrimitiveType -> 'Decoders.interval-    PrimitiveType.UuidPrimitiveType -> 'Decoders.uuid-    PrimitiveType.InetPrimitiveType -> 'Decoders.inet-    PrimitiveType.JsonPrimitiveType -> 'Decoders.json-    PrimitiveType.JsonbPrimitiveType -> 'Decoders.jsonb
− library/Hasql/TH/Extraction/InputTypeList.hs
@@ -1,52 +0,0 @@--- |--- AST traversal extracting input types.-module Hasql.TH.Extraction.InputTypeList where--import qualified Data.IntMap.Strict as IntMap-import qualified Hasql.TH.Extraction.PlaceholderTypeMap as PlaceholderTypeMap-import Hasql.TH.Prelude-import PostgresqlSyntax.Ast---- |--- >>> import qualified PostgresqlSyntax.Parsing as P--- >>> test = either fail (return . preparableStmt) . P.run P.preparableStmt------ >>> test "select $1 :: INT"--- Right [Typename False (NumericSimpleTypename IntNumeric) False Nothing]------ >>> test "select $1 :: INT, a + $2 :: INTEGER"--- Right [Typename False (NumericSimpleTypename IntNumeric) False Nothing,Typename False (NumericSimpleTypename IntegerNumeric) False Nothing]------ >>> test "select $1 :: INT4"--- Right [Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "int4") Nothing Nothing)) False Nothing]------ >>> test "select $1 :: text[]?"--- Right [Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "text") Nothing Nothing)) False (Just (BoundsTypenameArrayDimensions (Nothing :| []),True))]------ >>> test "select $1 :: text?[]?"--- Right [Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "text") Nothing Nothing)) True (Just (BoundsTypenameArrayDimensions (Nothing :| []),True))]------ >>> test "select $1"--- Left "Placeholder $1 misses an explicit typecast"------ >>> test "select $2 :: int4, $1 :: int4, $2 :: int4"--- Right [Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "int4") Nothing Nothing)) False Nothing,Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "int4") Nothing Nothing)) False Nothing]------ >>> test "select $1 :: int4, $1 :: text"--- Left "Placeholder $1 has conflicting type annotations"------ >>> test "select $2 :: int4, $2 :: text"--- Left "Placeholder $2 has conflicting type annotations"------ >>> test "select $3 :: int4, $1 :: int4"--- Left "You've missed placeholder $2"-preparableStmt :: PreparableStmt -> Either Text [Typename]-preparableStmt = placeholderTypeMap <=< PlaceholderTypeMap.preparableStmt--placeholderTypeMap :: IntMap Typename -> Either Text [Typename]-placeholderTypeMap a = do-  zipWithM-    (\a b -> if a == b then Right () else Left ("You've missed placeholder $" <> showAsText b))-    (IntMap.keys a)-    [1 ..]-  return (IntMap.elems a)
− library/Hasql/TH/Extraction/OutputTypeList.hs
@@ -1,90 +0,0 @@-{-# OPTIONS_GHC -Wno-missing-signatures #-}---- |--- AST traversal extracting output types.-module Hasql.TH.Extraction.OutputTypeList where--import Hasql.TH.Prelude-import PostgresqlSyntax.Ast--foldable :: (Foldable f) => (a -> Either Text [Typename]) -> f a -> Either Text [Typename]-foldable fn = fmap join . traverse fn . toList--preparableStmt = \case-  SelectPreparableStmt a -> selectStmt a-  InsertPreparableStmt a -> insertStmt a-  UpdatePreparableStmt a -> updateStmt a-  DeletePreparableStmt a -> deleteStmt a-  CallPreparableStmt a -> callStmt a---- * Call--callStmt (CallStmt a) =-  Right []---- * Insert--insertStmt (InsertStmt a b c d e) = foldable returningClause e--returningClause = targetList---- * Update--updateStmt (UpdateStmt _ _ _ _ _ a) = foldable returningClause a---- * Delete--deleteStmt (DeleteStmt _ _ _ _ a) = foldable returningClause a---- * Select--selectStmt = \case-  Left a -> selectNoParens a-  Right a -> selectWithParens a--selectNoParens (SelectNoParens _ a _ _ _) = selectClause a--selectWithParens = \case-  NoParensSelectWithParens a -> selectNoParens a-  WithParensSelectWithParens a -> selectWithParens a--selectClause = either simpleSelect selectWithParens--simpleSelect = \case-  NormalSimpleSelect a _ _ _ _ _ _ -> foldable targeting a-  ValuesSimpleSelect a -> valuesClause a-  TableSimpleSelect _ -> Left "TABLE cannot be used as a final statement, since it's impossible to specify the output types"-  BinSimpleSelect _ a _ b -> do-    c <- selectClause a-    d <- selectClause b-    if c == d-      then return c-      else Left "Merged queries produce results of incompatible types"--targeting = \case-  NormalTargeting a -> targetList a-  AllTargeting a -> foldable targetList a-  DistinctTargeting _ b -> targetList b--targetList = foldable targetEl--targetEl = \case-  AliasedExprTargetEl a _ -> aExpr a-  ImplicitlyAliasedExprTargetEl a _ -> aExpr a-  ExprTargetEl a -> aExpr a-  AsteriskTargetEl ->-    Left-      "Target of all fields is not allowed, \-      \because it leaves the output types unspecified. \-      \You have to be specific."--valuesClause = foldable (foldable aExpr)--aExpr = \case-  CExprAExpr a -> cExpr a-  TypecastAExpr _ a -> Right [a]-  a -> Left "Result expression is missing a typecast"--cExpr = \case-  InParensCExpr a Nothing -> aExpr a-  a -> Left "Result expression is missing a typecast"
− library/Hasql/TH/Extraction/PlaceholderTypeMap.hs
@@ -1,58 +0,0 @@-{-# OPTIONS_GHC -Wno-missing-signatures #-}--module Hasql.TH.Extraction.PlaceholderTypeMap where--import qualified Data.IntMap.Strict as IntMap-import Hasql.TH.Extraction.ChildExprList (ChildExpr (..))-import qualified Hasql.TH.Extraction.ChildExprList as ChildExprList-import Hasql.TH.Prelude hiding (union)-import PostgresqlSyntax.Ast--preparableStmt :: PreparableStmt -> Either Text (IntMap Typename)-preparableStmt = childExprList . ChildExprList.preparableStmt--childExprList :: [ChildExpr] -> Either Text (IntMap Typename)-childExprList = foldM union IntMap.empty <=< traverse childExpr--union :: IntMap Typename -> IntMap Typename -> Either Text (IntMap Typename)-union a b = IntMap.mergeWithKey merge (fmap Right) (fmap Right) a b & sequence-  where-    merge index a b =-      if a == b-        then Just (Right a)-        else Just (Left ("Placeholder $" <> (fromString . show) index <> " has conflicting type annotations"))--childExpr :: ChildExpr -> Either Text (IntMap Typename)-childExpr = \case-  AChildExpr a -> aExpr a-  BChildExpr a -> bExpr a-  CChildExpr a -> cExpr a--aExpr = \case-  CExprAExpr a -> cExpr a-  TypecastAExpr a b -> castedAExpr b a-  a -> childExprList (ChildExprList.aChildExpr a)--bExpr = \case-  CExprBExpr a -> cExpr a-  TypecastBExpr a b -> castedBExpr b a-  a -> childExprList (ChildExprList.bChildExpr a)--cExpr = \case-  ParamCExpr a _ -> Left ("Placeholder $" <> (fromString . show) a <> " misses an explicit typecast")-  a -> childExprList (ChildExprList.cChildExpr a)--castedAExpr a = \case-  CExprAExpr b -> castedCExpr a b-  TypecastAExpr b c -> castedAExpr c b-  b -> aExpr b--castedBExpr a = \case-  CExprBExpr b -> castedCExpr a b-  TypecastBExpr b c -> castedBExpr c b-  b -> bExpr b--castedCExpr a = \case-  ParamCExpr b _ -> Right (IntMap.singleton b a)-  InParensCExpr b _ -> castedAExpr a b-  b -> cExpr b
− library/Hasql/TH/Extraction/PrimitiveType.hs
@@ -1,102 +0,0 @@-{-# OPTIONS_GHC -Wno-missing-signatures #-}--module Hasql.TH.Extraction.PrimitiveType where--import Hasql.TH.Prelude hiding (bit, fromList, sortBy)-import PostgresqlSyntax.Ast--data PrimitiveType-  = BoolPrimitiveType-  | Int2PrimitiveType-  | Int4PrimitiveType-  | Int8PrimitiveType-  | Float4PrimitiveType-  | Float8PrimitiveType-  | NumericPrimitiveType-  | CharPrimitiveType-  | TextPrimitiveType-  | ByteaPrimitiveType-  | DatePrimitiveType-  | TimestampPrimitiveType-  | TimestamptzPrimitiveType-  | TimePrimitiveType-  | TimetzPrimitiveType-  | IntervalPrimitiveType-  | UuidPrimitiveType-  | InetPrimitiveType-  | JsonPrimitiveType-  | JsonbPrimitiveType--simpleTypename = \case-  GenericTypeSimpleTypename a -> genericType a-  NumericSimpleTypename a -> numeric a-  BitSimpleTypename a -> bit a-  CharacterSimpleTypename a -> character a-  ConstDatetimeSimpleTypename a -> constDatetime a-  ConstIntervalSimpleTypename a -> Right IntervalPrimitiveType--genericType (GenericType a b c) = case b of-  Just _ -> Left "Type attributes are not supported"-  Nothing -> case c of-    Just _ -> Left "Type modifiers are not supported"-    Nothing -> ident a--numeric = \case-  IntNumeric -> Right Int4PrimitiveType-  IntegerNumeric -> Right Int4PrimitiveType-  SmallintNumeric -> Right Int2PrimitiveType-  BigintNumeric -> Right Int8PrimitiveType-  RealNumeric -> Right Float4PrimitiveType-  FloatNumeric a -> case a of-    Just _ -> Left "Modifier on FLOAT is not supported"-    Nothing -> Right Float4PrimitiveType-  DoublePrecisionNumeric -> Right Float8PrimitiveType-  DecimalNumeric a -> case a of-    Just _ -> Left "Modifiers on DECIMAL are not supported"-    Nothing -> Right NumericPrimitiveType-  DecNumeric a -> case a of-    Just _ -> Left "Modifiers on DEC are not supported"-    Nothing -> Right NumericPrimitiveType-  NumericNumeric a -> case a of-    Just _ -> Left "Modifiers on NUMERIC are not supported"-    Nothing -> Right NumericPrimitiveType-  BooleanNumeric -> Right BoolPrimitiveType--bit _ = Left "Bit codec is not supported"--character _ = Right CharPrimitiveType--constDatetime = \case-  TimestampConstDatetime _ a -> if tz a then Right TimestamptzPrimitiveType else Right TimestampPrimitiveType-  TimeConstDatetime _ a -> if tz a then Right TimetzPrimitiveType else Right TimePrimitiveType-  where-    tz = \case-      Just a -> a-      Nothing -> False--ident = \case-  QuotedIdent a -> name a-  UnquotedIdent a -> name a--name = \case-  "bool" -> Right BoolPrimitiveType-  "int2" -> Right Int2PrimitiveType-  "int4" -> Right Int4PrimitiveType-  "int8" -> Right Int8PrimitiveType-  "float4" -> Right Float4PrimitiveType-  "float8" -> Right Float8PrimitiveType-  "numeric" -> Right NumericPrimitiveType-  "char" -> Right CharPrimitiveType-  "text" -> Right TextPrimitiveType-  "bytea" -> Right ByteaPrimitiveType-  "date" -> Right DatePrimitiveType-  "timestamp" -> Right TimestampPrimitiveType-  "timestamptz" -> Right TimestamptzPrimitiveType-  "time" -> Right TimePrimitiveType-  "timetz" -> Right TimetzPrimitiveType-  "interval" -> Right IntervalPrimitiveType-  "uuid" -> Right UuidPrimitiveType-  "inet" -> Right InetPrimitiveType-  "json" -> Right JsonPrimitiveType-  "jsonb" -> Right JsonbPrimitiveType-  name -> Left ("No codec exists for type: " <> name)
− library/Hasql/TH/Prelude.hs
@@ -1,94 +0,0 @@-module Hasql.TH.Prelude-  ( module Exports,-    showAsText,-    suffixRec,-  )-where--import Control.Applicative as Exports-import Control.Arrow as Exports hiding (first, second)-import Control.Category as Exports-import Control.Concurrent as Exports-import Control.Exception as Exports-import Control.Foldl as Exports (Fold (..))-import Control.Monad as Exports hiding (fail, forM, forM_, mapM, mapM_, msum, sequence, sequence_)-import Control.Monad.Fail as Exports-import Control.Monad.Fix as Exports hiding (fix)-import Control.Monad.IO.Class as Exports-import Control.Monad.ST as Exports-import Data.Bifunctor as Exports-import Data.Bits as Exports-import Data.Bool as Exports-import Data.ByteString as Exports (ByteString)-import Data.Char as Exports-import Data.Coerce as Exports-import Data.Complex as Exports-import Data.Data as Exports-import Data.Dynamic as Exports-import Data.Either as Exports-import Data.Fixed as Exports-import Data.Foldable as Exports-import Data.Function as Exports hiding (id, (.))-import Data.Functor as Exports hiding (unzip)-import Data.Functor.Contravariant as Exports-import Data.Functor.Contravariant.Divisible as Exports-import Data.Functor.Identity as Exports-import Data.IORef as Exports-import Data.Int as Exports-import Data.IntMap.Strict as Exports (IntMap)-import Data.IntSet as Exports (IntSet)-import Data.Ix as Exports-import Data.List as Exports hiding (all, and, any, concat, concatMap, elem, find, foldl, foldl', foldl1, foldr, foldr1, isSubsequenceOf, mapAccumL, mapAccumR, maximum, maximumBy, minimum, minimumBy, notElem, or, product, sortOn, sum, uncons)-import Data.List.NonEmpty as Exports (NonEmpty (..))-import Data.Map.Strict as Exports (Map)-import Data.Maybe as Exports-import Data.Monoid as Exports hiding (First (..), Last (..), (<>))-import Data.Ord as Exports-import Data.Proxy as Exports-import Data.Ratio as Exports-import Data.STRef as Exports-import Data.Semigroup as Exports-import Data.Sequence as Exports (Seq)-import Data.Set as Exports (Set)-import Data.String as Exports-import Data.Text as Exports (Text)-import Data.Traversable as Exports-import Data.Tuple as Exports-import Data.UUID as Exports (UUID)-import Data.Unique as Exports-import Data.Version as Exports-import Data.Void as Exports-import Data.Word as Exports-import Debug.Trace as Exports-import Foreign.ForeignPtr as Exports-import Foreign.Ptr as Exports-import Foreign.StablePtr as Exports-import Foreign.Storable as Exports hiding (alignment, sizeOf)-import GHC.Conc as Exports hiding (orElse, threadWaitRead, threadWaitReadSTM, threadWaitWrite, threadWaitWriteSTM, withMVar)-import GHC.Exts as Exports (IsList (Item, fromList), groupWith, inline, lazy, sortWith)-import GHC.Generics as Exports (Generic, Generic1)-import GHC.IO.Exception as Exports-import Numeric as Exports-import System.Environment as Exports-import System.Exit as Exports-import System.IO as Exports-import System.IO.Error as Exports-import System.IO.Unsafe as Exports-import System.Mem as Exports-import System.Mem.StableName as Exports-import System.Timeout as Exports-import Text.Printf as Exports (hPrintf, printf)-import Text.Read as Exports (Read (..), readEither, readMaybe)-import Unsafe.Coerce as Exports-import Prelude as Exports hiding (all, and, any, concat, concatMap, elem, fail, foldl, foldl1, foldr, foldr1, id, mapM, mapM_, maximum, minimum, notElem, or, product, sequence, sequence_, sum, (.))--showAsText :: (Show a) => a -> Text-showAsText = show >>> fromString---- |--- Compose a monad, which attempts to extend a value, based on the following input.--- It does that recursively until the suffix alternative fails.-suffixRec :: (Monad m, Alternative m) => m a -> (a -> m a) -> m a-suffixRec base suffix = do-  _base <- base-  suffixRec (suffix _base) suffix <|> pure _base
+ src/library/Hasql/TH.hs view
@@ -0,0 +1,279 @@+module Hasql.TH+  ( -- * Statements++    -- |+    --  Quasiquoters in this category produce Hasql `Statement`s,+    --  checking the correctness of SQL at compile-time.+    --+    --  To extract the information about parameters and results of the statement,+    --  the quoter requires you to explicitly specify the Postgres types for placeholders and results.+    --+    --  Here's an example of how to use it:+    --+    --  >selectUserDetails :: Statement Int32 (Maybe (Text, Text, Maybe Text))+    --  >selectUserDetails =+    --  >  [maybeStatement|+    --  >    select name :: text, email :: text, phone :: text?+    --  >    from "user"+    --  >    where id = $1 :: int4+    --  >    |]+    --+    --  As you can see, it completely eliminates the need to mess with codecs.+    --  The quasiquoters directly produce `Statement`,+    --  which you can then `Data.Profunctor.dimap` over using its `Data.Profunctor.Profunctor` instance to get to your domain types.+    --+    --  == Type mappings+    --+    --  === Primitives+    --+    --  Following is a list of supported Postgres types and their according types on the Haskell end.+    --+    --  - @bool@ - `Bool`+    --  - @int2@ - `Int16`+    --  - @int4@ - `Int32`+    --  - @int8@ - `Int64`+    --  - @float4@ - `Float`+    --  - @float8@ - `Double`+    --  - @numeric@ - `Data.Scientific.Scientific`+    --  - @char@ - `Char`+    --  - @text@ - `Data.Text.Text`+    --  - @bytea@ - `Data.ByteString.ByteString`+    --  - @date@ - `Data.Time.Day`+    --  - @timestamp@ - `Data.Time.LocalTime`+    --  - @timestamptz@ - `Data.Time.UTCTime`+    --  - @time@ - `Data.Time.TimeOfDay`+    --  - @timetz@ - @(`Data.Time.TimeOfDay`, `Data.Time.TimeZone`)@+    --  - @interval@ - `Data.Time.DiffTime`+    --  - @uuid@ - `Data.UUID.UUID`+    --  - @inet@ - @(`Network.IP.Addr.NetAddr` `Network.IP.Addr.IP`)@+    --  - @json@ - `Data.Aeson.Value`+    --  - @jsonb@ - `Data.Aeson.Value`+    --+    --  === Arrays+    --+    --  Array mappings are also supported.+    --  They are specified according to Postgres syntax: by appending one or more @[]@ to the primitive type,+    --  depending on how many dimensions the array has.+    --  On the Haskell end array is mapped to generic `Data.Vector.Generic.Vector`,+    --  allowing you to choose which particular vector implementation to map to.+    --+    --  === Nulls+    --+    --  As you might have noticed in the example,+    --  we introduce one change to the Postgres syntax in the way+    --  the typesignatures are parsed:+    --  we interpret question-marks in them as specification of nullability.+    --  Here's more examples of that:+    --+    --  >>> :t [singletonStatement| select a :: int4? |]+    --  ...+    --    :: Statement () (Maybe Int32)+    --+    --  You can use it to specify the nullability of array elements:+    --+    --  >>> :t [singletonStatement| select a :: int4?[] |]+    --  ...+    --    :: Data.Vector.Generic.Base.Vector v (Maybe Int32) =>+    --       Statement () (v (Maybe Int32))+    --+    --  And of arrays themselves:+    --+    --  >>> :t [singletonStatement| select a :: int4?[]? |]+    --  ...+    --    :: Data.Vector.Generic.Base.Vector v (Maybe Int32) =>+    --       Statement () (Maybe (v (Maybe Int32)))++    -- ** Row-parsing statements+    singletonStatement,+    maybeStatement,+    vectorStatement,+    foldStatement,++    -- ** Row-ignoring statements+    resultlessStatement,+    rowsAffectedStatement,++    -- * SQL ByteStrings++    -- |+    --  ByteString-producing quasiquoters.+    --+    --  For now they perform no compile-time checking.+    uncheckedSql,+    uncheckedSqlFile,+  )+where++import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Hasql.TH.Construction.Exp as Exp+import qualified Hasql.TH.Extraction.Exp as ExpExtraction+import Hasql.TH.Prelude hiding (exp)+import Language.Haskell.TH.Quote+import Language.Haskell.TH.Syntax+import qualified PostgresqlSyntax.Ast as Ast+import qualified PostgresqlSyntax.Parsing as Parsing++-- * Helpers++exp :: (String -> Q Exp) -> QuasiQuoter+exp =+  let _unsupported _ = fail "Unsupported"+   in \_exp -> QuasiQuoter _exp _unsupported _unsupported _unsupported++expParser :: (Text -> Either Text Exp) -> QuasiQuoter+expParser _parser =+  exp $ \_inputString -> either (fail . Text.unpack) return $ _parser $ fromString _inputString++expPreparableStmtAstParser :: (Ast.PreparableStmt -> Either Text Exp) -> QuasiQuoter+expPreparableStmtAstParser _parser =+  expParser $ \_input -> do+    _ast <- first fromString $ Parsing.run (Parsing.atEnd Parsing.preparableStmt) _input+    _parser _ast++-- * Statement++-- |+-- @+-- :: `Statement` params row+-- @+--+-- Statement producing exactly one result row.+--+-- Will cause the running session to fail with the+-- `Hasql.Session.UnexpectedAmountOfRows` error if it's any other.+--+-- === __Examples__+--+-- >>> :t [singletonStatement|select 1 :: int2|]+-- ... :: Statement () Int16+--+-- >>> :{+--   :t [singletonStatement|+--        insert into "user" (email, name)+--        values ($1 :: text, $2 :: text)+--        returning id :: int4+--        |]+-- :}+-- ...+-- ... :: Statement (Text, Text) Int32+--+-- Incorrect SQL:+--+-- >>> :t [singletonStatement|elect 1|]+-- ...+--   |+-- 1 | elect 1+--   |      ^+-- ...+singletonStatement :: QuasiQuoter+singletonStatement = expPreparableStmtAstParser (ExpExtraction.undecodedStatement Exp.singleRowResultDecoder)++-- |+-- @+-- :: `Statement` params (Maybe row)+-- @+--+-- Statement producing one row or none.+--+-- === __Examples__+--+-- >>> :t [maybeStatement|select 1 :: int2|]+-- ... :: Statement () (Maybe Int16)+maybeStatement :: QuasiQuoter+maybeStatement = expPreparableStmtAstParser (ExpExtraction.undecodedStatement Exp.rowMaybeResultDecoder)++-- |+-- @+-- :: `Statement` params (`Vector` row)+-- @+--+-- Statement producing a vector of rows.+--+-- === __Examples__+--+-- >>> :t [vectorStatement|select 1 :: int2|]+-- ... :: Statement () (Vector Int16)+vectorStatement :: QuasiQuoter+vectorStatement = expPreparableStmtAstParser (ExpExtraction.undecodedStatement Exp.rowVectorResultDecoder)++-- |+-- @+-- :: `Fold` row folding -> `Statement` params folding+-- @+--+-- Function from `Fold` over rows to a statement producing the result of folding.+-- Use this when you need to aggregate rows customly.+--+-- === __Examples__+--+-- >>> :t [foldStatement|select 1 :: int2|]+-- ... :: Fold Int16 b -> Statement () b+foldStatement :: QuasiQuoter+foldStatement = expPreparableStmtAstParser ExpExtraction.foldStatement++-- |+-- @+-- :: `Statement` params ()+-- @+--+-- Statement producing no results.+--+-- === __Examples__+--+-- >>> :t [resultlessStatement|insert into "user" (name, email) values ($1 :: text, $2 :: text)|]+-- ...+-- ... :: Statement (Text, Text) ()+resultlessStatement :: QuasiQuoter+resultlessStatement = expPreparableStmtAstParser (ExpExtraction.undecodedStatement (const Exp.noResultResultDecoder))++-- |+-- @+-- :: `Statement` params Int64+-- @+--+-- Statement counting the rows it affects.+--+-- === __Examples__+--+-- >>> :t [rowsAffectedStatement|delete from "user" where password is null|]+-- ...+-- ... :: Statement () Int64+rowsAffectedStatement :: QuasiQuoter+rowsAffectedStatement = expPreparableStmtAstParser (ExpExtraction.undecodedStatement (const Exp.rowsAffectedResultDecoder))++-- * SQL ByteStrings++-- |+-- Quoter of a multiline Unicode SQL string,+-- which gets converted into a format ready to be used for declaration of statements.+uncheckedSql :: QuasiQuoter+uncheckedSql = exp $ return . Exp.byteString . Text.encodeUtf8 . fromString++-- |+-- Read an SQL-file, containing multiple statements,+-- and produce an expression of type `ByteString`.+--+-- Allows to store plain SQL in external files and read it at compile time.+--+-- E.g.,+--+-- >migration1 :: Hasql.Session.Session ()+-- >migration1 = Hasql.Session.sql [uncheckedSqlFile|migrations/1.sql|]+uncheckedSqlFile :: QuasiQuoter+uncheckedSqlFile = quoteFile uncheckedSql++-- * Tests++-- $+-- >>> :t [maybeStatement| select (password = $2 :: bytea) :: bool, id :: int4 from "user" where "email" = $1 :: text |]+-- ...+-- ... Statement (Text, ByteString) (Maybe (Bool, Int32))+--+-- >>> :t [maybeStatement| select id :: int4 from application where pub_key = $1 :: uuid and sec_key_pt1 = $2 :: int8 and sec_key_pt2 = $3 :: int8 |]+-- ...+-- ... Statement (UUID, Int64, Int64) (Maybe Int32)+--+-- >>> :t [singletonStatement| select 1 :: int4 from a left join b on b.id = a.id |]+-- ...+-- ... Statement () Int32
+ src/library/Hasql/TH/Construction/Exp.hs view
@@ -0,0 +1,201 @@+-- |+-- Expression construction.+module Hasql.TH.Construction.Exp where++import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Unsafe as ByteString+import qualified Data.Vector.Generic as Vector+import qualified Hasql.Decoders as Decoders+import qualified Hasql.Encoders as Encoders+import qualified Hasql.Statement as Statement+import Hasql.TH.Prelude hiding (sequence_)+import qualified Hasql.TH.Prelude as Prelude+import Language.Haskell.TH.Syntax+import qualified TemplateHaskell.Compat.V0208 as Compat++-- * Helpers++appList :: Exp -> [Exp] -> Exp+appList = foldl' AppE++byteString :: ByteString -> Exp+byteString x =+  appList+    (VarE 'unsafeDupablePerformIO)+    [ appList+        (VarE 'ByteString.unsafePackAddressLen)+        [ LitE (IntegerL (fromIntegral (ByteString.length x))),+          LitE (StringPrimL (ByteString.unpack x))+        ]+    ]++integral :: (Integral a) => a -> Exp+integral x = LitE (IntegerL (fromIntegral x))++list :: (a -> Exp) -> [a] -> Exp+list renderer x = ListE (map renderer x)++string :: String -> Exp+string x = LitE (StringL x)++char :: Char -> Exp+char x = LitE (CharL x)++sequence_ :: [Exp] -> Exp+sequence_ = foldl' andThen pureUnit++pureUnit :: Exp+pureUnit = AppE (VarE 'Prelude.pure) (TupE [])++andThen :: Exp -> Exp -> Exp+andThen exp1 exp2 = AppE (AppE (VarE '(*>)) exp1) exp2++tuple :: Int -> Exp+tuple = ConE . tupleDataName++splitTupleAt :: Int -> Int -> Exp+splitTupleAt arity position =+  let nameByIndex index = Name (OccName ('_' : show index)) NameS+      names = enumFromTo 0 (pred arity) & map nameByIndex+      pats = names & map VarP+      pat = TupP pats+      exps = names & map VarE+      body = splitAt position exps & \(a, b) -> Compat.tupE [Compat.tupE a, Compat.tupE b]+   in LamE [pat] body++-- |+-- Given a list of divisible functor expressions,+-- constructs an expression, which composes them together into+-- a single divisible functor, parameterized by a tuple of according arity.+contrazip :: [Exp] -> Exp+contrazip = \case+  _head : [] -> _head+  _head : _tail -> appList (VarE 'divide) [splitTupleAt (succ (length _tail)) 1, _head, contrazip _tail]+  [] ->+    SigE+      (VarE 'conquer)+      ( let _fName = mkName "f"+            _fVar = VarT _fName+         in ForallT+              [Compat.specifiedPlainTV _fName]+              [AppT (ConT ''Divisible) (VarT _fName)]+              (AppT (VarT _fName) (TupleT 0))+      )++-- |+-- Given a list of applicative functor expressions,+-- constructs an expression, which composes them together into+-- a single applicative functor, parameterized by a tuple of according arity.+--+-- >>> $(return (cozip [])) :: Maybe ()+-- Just ()+--+-- >>> $(return (cozip (fmap (AppE (ConE 'Just) . LitE . IntegerL) [1,2,3]))) :: Maybe (Int, Int, Int)+-- Just (1,2,3)+cozip :: [Exp] -> Exp+cozip = \case+  _head : [] -> _head+  _head : _tail ->+    let _length = length _tail + 1+     in foldl'+          (\a b -> AppE (AppE (VarE '(<*>)) a) b)+          (AppE (AppE (VarE 'fmap) (tuple _length)) _head)+          _tail+  [] -> AppE (VarE 'pure) (TupE [])++-- |+-- Lambda expression, which destructures 'Fold'.+foldLam :: (Exp -> Exp -> Exp -> Exp) -> Exp+foldLam _body =+  let _stepVarName = mkName "progress"+      _initVarName = mkName "start"+      _extractVarName = mkName "finish"+   in LamE+        [ Compat.conP+            'Fold+            [ VarP _stepVarName,+              VarP _initVarName,+              VarP _extractVarName+            ]+        ]+        (_body (VarE _stepVarName) (VarE _initVarName) (VarE _extractVarName))++-- * Statement++statement :: Exp -> Exp -> Exp -> Exp+statement _sql _encoder _decoder =+  appList (VarE 'Statement.preparable) [_sql, _encoder, _decoder]++noResultResultDecoder :: Exp+noResultResultDecoder = VarE 'Decoders.noResult++rowsAffectedResultDecoder :: Exp+rowsAffectedResultDecoder = VarE 'Decoders.rowsAffected++singleRowResultDecoder :: Exp -> Exp+singleRowResultDecoder = 'Decoders.singleRow & VarE & AppE++rowMaybeResultDecoder :: Exp -> Exp+rowMaybeResultDecoder = AppE (VarE 'Decoders.rowMaybe)++rowVectorResultDecoder :: Exp -> Exp+rowVectorResultDecoder = AppE (VarE 'Decoders.rowVector)++foldStatement :: Exp -> Exp -> Exp -> Exp+foldStatement _sql _encoder _rowDecoder =+  foldLam (\_step _init _extract -> statement _sql _encoder (foldResultDecoder _step _init _extract _rowDecoder))++foldResultDecoder :: Exp -> Exp -> Exp -> Exp -> Exp+foldResultDecoder _step _init _extract _rowDecoder =+  appList (VarE 'fmap) [_extract, appList (VarE 'Decoders.foldlRows) [_step, _init, _rowDecoder]]++unidimensionalParamEncoder :: Bool -> Exp -> Exp+unidimensionalParamEncoder nullable =+  applyParamToEncoder . applyNullabilityToEncoder nullable++multidimensionalParamEncoder :: Bool -> Int -> Bool -> Exp -> Exp+multidimensionalParamEncoder nullable dimensionality arrayNull =+  applyParamToEncoder+    . applyNullabilityToEncoder arrayNull+    . AppE (VarE 'Encoders.array)+    . applyArrayDimensionalityToEncoder dimensionality+    . applyNullabilityToEncoder nullable++applyParamToEncoder :: Exp -> Exp+applyParamToEncoder = AppE (VarE 'Encoders.param)++applyNullabilityToEncoder :: Bool -> Exp -> Exp+applyNullabilityToEncoder nullable = AppE (VarE (if nullable then 'Encoders.nullable else 'Encoders.nonNullable))++applyArrayDimensionalityToEncoder :: Int -> Exp -> Exp+applyArrayDimensionalityToEncoder levels =+  if levels > 0+    then AppE (AppE (VarE 'Encoders.dimension) (VarE 'Vector.foldl')) . applyArrayDimensionalityToEncoder (pred levels)+    else AppE (VarE 'Encoders.element)++rowDecoder :: [Exp] -> Exp+rowDecoder = cozip++unidimensionalColumnDecoder :: Bool -> Exp -> Exp+unidimensionalColumnDecoder nullable =+  applyColumnToDecoder . applyNullabilityToDecoder nullable++multidimensionalColumnDecoder :: Bool -> Int -> Bool -> Exp -> Exp+multidimensionalColumnDecoder nullable dimensionality arrayNull =+  applyColumnToDecoder+    . applyNullabilityToDecoder arrayNull+    . AppE (VarE 'Decoders.array)+    . applyArrayDimensionalityToDecoder dimensionality+    . applyNullabilityToDecoder nullable++applyColumnToDecoder :: Exp -> Exp+applyColumnToDecoder = AppE (VarE 'Decoders.column)++applyNullabilityToDecoder :: Bool -> Exp -> Exp+applyNullabilityToDecoder nullable = AppE (VarE (if nullable then 'Decoders.nullable else 'Decoders.nonNullable))++applyArrayDimensionalityToDecoder :: Int -> Exp -> Exp+applyArrayDimensionalityToDecoder levels =+  if levels > 0+    then AppE (AppE (VarE 'Decoders.dimension) (VarE 'Vector.replicateM)) . applyArrayDimensionalityToDecoder (pred levels)+    else AppE (VarE 'Decoders.element)
+ src/library/Hasql/TH/Extraction/ChildExprList.hs view
@@ -0,0 +1,611 @@+{-# OPTIONS_GHC -Wno-unused-binds -Wno-unused-imports -Wno-name-shadowing -Wno-incomplete-patterns -Wno-unused-matches -Wno-missing-methods -Wno-unused-record-wildcards -Wno-redundant-constraints -Wno-deprecations -Wno-missing-signatures #-}++module Hasql.TH.Extraction.ChildExprList where++import Hasql.TH.Prelude hiding (bit, fromList, sortBy)+import PostgresqlSyntax.Ast++-- * Types++data ChildExpr = AChildExpr AExpr | BChildExpr BExpr | CChildExpr CExpr+  deriving (Show, Eq, Ord)++-- |+-- Dives one level of recursion.+childExpr = \case+  AChildExpr a -> aChildExpr a+  BChildExpr a -> bChildExpr a+  CChildExpr a -> cChildExpr a++aChildExpr = \case+  CExprAExpr a -> cChildExpr a+  TypecastAExpr a b -> aExpr a <> typename b+  CollateAExpr a b -> aExpr a <> anyName b+  AtTimeZoneAExpr a b -> aExpr a <> aExpr b+  PlusAExpr a -> aExpr a+  MinusAExpr a -> aExpr a+  SymbolicBinOpAExpr a b c -> aExpr a <> symbolicExprBinOp b <> aExpr c+  PrefixQualOpAExpr a b -> qualOp a <> aExpr b+  SuffixQualOpAExpr a b -> aExpr a <> qualOp b+  AndAExpr a b -> aExpr a <> aExpr b+  OrAExpr a b -> aExpr a <> aExpr b+  NotAExpr a -> aExpr a+  VerbalExprBinOpAExpr a b c d e -> aExpr a <> verbalExprBinOp c <> aExpr d <> foldMap aExpr e+  ReversableOpAExpr a b c -> aExpr a <> aExprReversableOp c+  IsnullAExpr a -> aExpr a+  NotnullAExpr a -> aExpr a+  OverlapsAExpr a b -> row a <> row b+  SubqueryAExpr a b c d -> aExpr a <> subqueryOp b <> subType c <> either selectWithParens aExpr d+  UniqueAExpr a -> selectWithParens a+  DefaultAExpr -> []++bChildExpr = \case+  CExprBExpr a -> cChildExpr a+  TypecastBExpr a b -> bExpr a <> typename b+  PlusBExpr a -> bExpr a+  MinusBExpr a -> bExpr a+  SymbolicBinOpBExpr a b c -> bExpr a <> symbolicExprBinOp b <> bExpr c+  QualOpBExpr a b -> qualOp a <> bExpr b+  IsOpBExpr a b c -> bExpr a <> bExprIsOp c++cChildExpr = \case+  ColumnrefCExpr a -> columnref a+  AexprConstCExpr a -> aexprConst a+  ParamCExpr a b -> foldMap indirection b+  InParensCExpr a b -> aExpr a <> foldMap indirection b+  CaseCExpr a -> caseExpr a+  FuncCExpr a -> funcExpr a+  SelectWithParensCExpr a b -> selectWithParens a <> foldMap indirection b+  ExistsCExpr a -> selectWithParens a+  ArrayCExpr a -> either selectWithParens arrayExpr a+  ExplicitRowCExpr a -> explicitRow a+  ImplicitRowCExpr a -> implicitRow a+  GroupingCExpr a -> exprList a++preparableStmt = \case+  SelectPreparableStmt a -> selectStmt a+  InsertPreparableStmt a -> insertStmt a+  UpdatePreparableStmt a -> updateStmt a+  DeletePreparableStmt a -> deleteStmt a+  CallPreparableStmt a -> callStmt a++-- * Call++callStmt (CallStmt a) = funcApplication a++-- * Insert++insertStmt (InsertStmt a b c d e) =+  foldMap withClause a+    <> insertTarget b+    <> insertRest c+    <> foldMap onConflict d+    <> foldMap returningClause e++insertTarget (InsertTarget a b) = qualifiedName a <> colId b++insertRest = \case+  SelectInsertRest a b c -> foldMap insertColumnList a <> foldMap overrideKind b <> selectStmt c+  DefaultValuesInsertRest -> []++overrideKind _ = []++insertColumnList = foldMap insertColumnItem++insertColumnItem (InsertColumnItem a b) = colId a <> foldMap indirection b++onConflict (OnConflict a b) = foldMap confExpr a <> onConflictDo b++onConflictDo = \case+  UpdateOnConflictDo b c -> setClauseList b <> foldMap whereClause c+  NothingOnConflictDo -> []++confExpr = \case+  WhereConfExpr a b -> indexParams a <> foldMap whereClause b+  ConstraintConfExpr a -> name a++returningClause = targetList++-- * Update++updateStmt (UpdateStmt a b c d e f) =+  foldMap withClause a+    <> relationExprOptAlias b+    <> setClauseList c+    <> foldMap fromClause d+    <> foldMap whereOrCurrentClause e+    <> foldMap returningClause f++setClauseList = foldMap setClause++setClause = \case+  TargetSetClause a b -> setTarget a <> aExpr b+  TargetListSetClause a b -> setTargetList a <> aExpr b++setTarget (SetTarget a b) = colId a <> foldMap indirection b++setTargetList = foldMap setTarget++-- * Delete++deleteStmt (DeleteStmt a b c d e) =+  foldMap withClause a+    <> relationExprOptAlias b+    <> foldMap usingClause c+    <> foldMap whereOrCurrentClause d+    <> foldMap returningClause e++usingClause = fromList++-- * Select++selectStmt = \case+  Left a -> selectNoParens a+  Right a -> selectWithParens a++selectNoParens (SelectNoParens a b c d e) =+  foldMap withClause a+    <> selectClause b+    <> foldMap sortClause c+    <> foldMap selectLimit d+    <> foldMap forLockingClause e++selectWithParens = \case+  NoParensSelectWithParens a -> selectNoParens a+  WithParensSelectWithParens a -> selectWithParens a++withClause (WithClause _ a) = foldMap commonTableExpr a++commonTableExpr (CommonTableExpr a b c d) = preparableStmt d++selectLimit = \case+  LimitOffsetSelectLimit a b -> limitClause a <> offsetClause b+  OffsetLimitSelectLimit a b -> offsetClause a <> limitClause b+  LimitSelectLimit a -> limitClause a+  OffsetSelectLimit a -> offsetClause a++limitClause = \case+  LimitLimitClause a b -> selectLimitValue a <> exprList b+  FetchOnlyLimitClause a b c -> foldMap selectFetchFirstValue b++offsetClause = \case+  ExprOffsetClause a -> aExpr a+  FetchFirstOffsetClause a b -> selectFetchFirstValue a++selectFetchFirstValue = \case+  ExprSelectFetchFirstValue a -> cExpr a+  NumSelectFetchFirstValue _ _ -> []++selectLimitValue = \case+  ExprSelectLimitValue a -> aExpr a+  AllSelectLimitValue -> []++forLockingClause = \case+  ItemsForLockingClause a -> foldMap forLockingItem a+  ReadOnlyForLockingClause -> []++forLockingItem (ForLockingItem a b c) =+  foldMap (foldMap qualifiedName) b++selectClause = either simpleSelect selectWithParens++simpleSelect = \case+  NormalSimpleSelect a b c d e f g ->+    foldMap targeting a+      <> foldMap intoClause b+      <> foldMap fromClause c+      <> foldMap whereClause d+      <> foldMap groupClause e+      <> foldMap havingClause f+      <> foldMap windowClause g+  ValuesSimpleSelect a -> valuesClause a+  TableSimpleSelect a -> relationExpr a+  BinSimpleSelect _ a _ b -> selectClause a <> selectClause b++targeting = \case+  NormalTargeting a -> foldMap targetEl a+  AllTargeting a -> foldMap (foldMap targetEl) a+  DistinctTargeting a b -> foldMap exprList a <> foldMap targetEl b++targetList = foldMap targetEl++targetEl = \case+  AliasedExprTargetEl a _ -> aExpr a+  ImplicitlyAliasedExprTargetEl a _ -> aExpr a+  ExprTargetEl a -> aExpr a+  AsteriskTargetEl -> []++intoClause = optTempTableName++fromClause = fromList++fromList = foldMap tableRef++whereClause = aExpr++whereOrCurrentClause = \case+  ExprWhereOrCurrentClause a -> aExpr a+  CursorWhereOrCurrentClause a -> cursorName a++groupClause = foldMap groupByItem++havingClause = aExpr++windowClause = foldMap windowDefinition++valuesClause = foldMap exprList++optTempTableName _ = []++groupByItem = \case+  ExprGroupByItem a -> aExpr a+  EmptyGroupingSetGroupByItem -> []+  RollupGroupByItem a -> exprList a+  CubeGroupByItem a -> exprList a+  GroupingSetsGroupByItem a -> foldMap groupByItem a++windowDefinition (WindowDefinition _ a) = windowSpecification a++windowSpecification (WindowSpecification _ a b c) = foldMap (foldMap aExpr) a <> foldMap sortClause b <> foldMap frameClause c++frameClause (FrameClause _ a _) = frameExtent a++frameExtent = \case+  SingularFrameExtent a -> frameBound a+  BetweenFrameExtent a b -> frameBound a <> frameBound b++frameBound = \case+  UnboundedPrecedingFrameBound -> []+  UnboundedFollowingFrameBound -> []+  CurrentRowFrameBound -> []+  PrecedingFrameBound a -> aExpr a+  FollowingFrameBound a -> aExpr a++sortClause = foldMap sortBy++sortBy = \case+  UsingSortBy a b c -> aExpr a <> qualAllOp b <> foldMap nullsOrder c+  AscDescSortBy a b c -> aExpr a <> foldMap ascDesc b <> foldMap nullsOrder c++-- * Table refs++tableRef = \case+  RelationExprTableRef a b c -> relationExpr a <> foldMap aliasClause b <> foldMap tablesampleClause c+  FuncTableRef a b c -> funcTable b <> foldMap funcAliasClause c+  SelectTableRef _ a _ -> selectWithParens a+  JoinTableRef a _ -> joinedTable a++relationExpr = \case+  SimpleRelationExpr a _ -> qualifiedName a+  OnlyRelationExpr a _ -> qualifiedName a++relationExprOptAlias (RelationExprOptAlias a b) = relationExpr a <> foldMap (colId . snd) b++tablesampleClause (TablesampleClause a b c) = funcName a <> exprList b <> foldMap repeatableClause c++repeatableClause = aExpr++funcTable = \case+  FuncExprFuncTable a b -> funcExprWindowless a <> optOrdinality b+  RowsFromFuncTable a b -> rowsfromList a <> optOrdinality b++rowsfromItem (RowsfromItem a b) = funcExprWindowless a <> foldMap colDefList b++rowsfromList = foldMap rowsfromItem++colDefList = tableFuncElementList++optOrdinality = const []++tableFuncElementList = foldMap tableFuncElement++tableFuncElement (TableFuncElement a b c) = colId a <> typename b <> foldMap collateClause c++collateClause = anyName++aliasClause = const []++funcAliasClause = \case+  AliasFuncAliasClause a -> aliasClause a+  AsFuncAliasClause a -> tableFuncElementList a+  AsColIdFuncAliasClause a b -> colId a <> tableFuncElementList b+  ColIdFuncAliasClause a b -> colId a <> tableFuncElementList b++joinedTable = \case+  InParensJoinedTable a -> joinedTable a+  MethJoinedTable a b c -> joinMeth a <> tableRef b <> tableRef c++joinMeth = \case+  CrossJoinMeth -> []+  QualJoinMeth _ a -> joinQual a+  NaturalJoinMeth _ -> []++joinQual = \case+  UsingJoinQual _ -> []+  OnJoinQual a -> aExpr a++exprList = fmap AChildExpr . toList++aExpr = pure . AChildExpr++bExpr = pure . BChildExpr++cExpr = pure . CChildExpr++funcExpr = \case+  ApplicationFuncExpr a b c d -> funcApplication a <> foldMap withinGroupClause b <> foldMap filterClause c <> foldMap overClause d+  SubexprFuncExpr a -> funcExprCommonSubexpr a++funcExprWindowless = \case+  ApplicationFuncExprWindowless a -> funcApplication a+  CommonSubexprFuncExprWindowless a -> funcExprCommonSubexpr a++withinGroupClause = sortClause++filterClause a = aExpr a++overClause = \case+  WindowOverClause a -> windowSpecification a+  ColIdOverClause _ -> []++funcExprCommonSubexpr = \case+  CollationForFuncExprCommonSubexpr a -> aExpr a+  CurrentDateFuncExprCommonSubexpr -> []+  CurrentTimeFuncExprCommonSubexpr _ -> []+  CurrentTimestampFuncExprCommonSubexpr _ -> []+  LocalTimeFuncExprCommonSubexpr _ -> []+  LocalTimestampFuncExprCommonSubexpr _ -> []+  CurrentRoleFuncExprCommonSubexpr -> []+  CurrentUserFuncExprCommonSubexpr -> []+  SessionUserFuncExprCommonSubexpr -> []+  UserFuncExprCommonSubexpr -> []+  CurrentCatalogFuncExprCommonSubexpr -> []+  CurrentSchemaFuncExprCommonSubexpr -> []+  CastFuncExprCommonSubexpr a b -> aExpr a <> typename b+  ExtractFuncExprCommonSubexpr a -> foldMap extractList a+  OverlayFuncExprCommonSubexpr a -> overlayList a+  PositionFuncExprCommonSubexpr a -> foldMap positionList a+  SubstringFuncExprCommonSubexpr a -> foldMap substrList a+  TreatFuncExprCommonSubexpr a b -> aExpr a <> typename b+  TrimFuncExprCommonSubexpr a b -> foldMap trimModifier a <> trimList b+  NullIfFuncExprCommonSubexpr a b -> aExpr a <> aExpr b+  CoalesceFuncExprCommonSubexpr a -> exprList a+  GreatestFuncExprCommonSubexpr a -> exprList a+  LeastFuncExprCommonSubexpr a -> exprList a++extractList (ExtractList a b) = extractArg a <> aExpr b++extractArg _ = []++overlayList (OverlayList a b c d) = foldMap aExpr ([a, b, c] <> toList d)++positionList (PositionList a b) = bExpr a <> bExpr b++substrList = \case+  ExprSubstrList a b -> aExpr a <> substrListFromFor b+  ExprListSubstrList a -> exprList a++substrListFromFor = \case+  FromForSubstrListFromFor a b -> aExpr a <> aExpr b+  ForFromSubstrListFromFor a b -> aExpr a <> aExpr b+  FromSubstrListFromFor a -> aExpr a+  ForSubstrListFromFor a -> aExpr a++trimModifier _ = []++trimList = \case+  ExprFromExprListTrimList a b -> aExpr a <> exprList b+  FromExprListTrimList a -> exprList a+  ExprListTrimList a -> exprList a++whenClause (WhenClause a b) = aExpr a <> aExpr b++funcApplication (FuncApplication a b) = funcName a <> foldMap funcApplicationParams b++funcApplicationParams = \case+  NormalFuncApplicationParams _ a b -> foldMap funcArgExpr a <> foldMap (foldMap sortBy) b+  VariadicFuncApplicationParams a b c -> foldMap (foldMap funcArgExpr) a <> funcArgExpr b <> foldMap (foldMap sortBy) c+  StarFuncApplicationParams -> []++funcArgExpr = \case+  ExprFuncArgExpr a -> aExpr a+  ColonEqualsFuncArgExpr _ a -> aExpr a+  EqualsGreaterFuncArgExpr _ a -> aExpr a++caseExpr (CaseExpr a b c) = foldMap aExpr a <> whenClauseList b <> foldMap aExpr c++whenClauseList = foldMap whenClause++arrayExpr = \case+  ExprListArrayExpr a -> exprList a+  ArrayExprListArrayExpr a -> arrayExprList a+  EmptyArrayExpr -> []++arrayExprList = foldMap arrayExpr++inExpr = \case+  SelectInExpr a -> selectWithParens a+  ExprListInExpr a -> exprList a++-- * Operators++symbolicExprBinOp = \case+  MathSymbolicExprBinOp a -> mathOp a+  QualSymbolicExprBinOp a -> qualOp a++qualOp = \case+  OpQualOp a -> op a+  OperatorQualOp a -> anyOperator a++qualAllOp = \case+  AllQualAllOp a -> allOp a+  AnyQualAllOp a -> anyOperator a++verbalExprBinOp = const []++aExprReversableOp = \case+  NullAExprReversableOp -> []+  TrueAExprReversableOp -> []+  FalseAExprReversableOp -> []+  UnknownAExprReversableOp -> []+  DistinctFromAExprReversableOp a -> aExpr a+  OfAExprReversableOp a -> typeList a+  BetweenAExprReversableOp a b c -> bExpr b <> aExpr c+  BetweenSymmetricAExprReversableOp a b -> bExpr a <> aExpr b+  InAExprReversableOp a -> inExpr a+  DocumentAExprReversableOp -> []++subqueryOp = \case+  AllSubqueryOp a -> allOp a+  AnySubqueryOp a -> anyOperator a+  LikeSubqueryOp _ -> []+  IlikeSubqueryOp _ -> []++bExprIsOp = \case+  DistinctFromBExprIsOp a -> bExpr a+  OfBExprIsOp a -> typeList a+  DocumentBExprIsOp -> []++allOp = \case+  OpAllOp a -> op a+  MathAllOp a -> mathOp a++anyOperator = \case+  AllOpAnyOperator a -> allOp a+  QualifiedAnyOperator a b -> colId a <> anyOperator b++op = const []++mathOp = const []++-- * Rows++row = \case+  ExplicitRowRow a -> explicitRow a+  ImplicitRowRow a -> implicitRow a++explicitRow = foldMap exprList++implicitRow (ImplicitRow a b) = exprList a <> aExpr b++-- * Constants++aexprConst = \case+  IAexprConst _ -> []+  FAexprConst _ -> []+  SAexprConst _ -> []+  BAexprConst _ -> []+  XAexprConst _ -> []+  FuncAexprConst a b _ -> funcName a <> foldMap funcConstArgs b+  ConstTypenameAexprConst a _ -> constTypename a+  StringIntervalAexprConst _ a -> foldMap interval a+  IntIntervalAexprConst _ _ -> []+  BoolAexprConst _ -> []+  NullAexprConst -> []++funcConstArgs (FuncConstArgs a b) = foldMap funcArgExpr a <> foldMap sortClause b++constTypename = \case+  NumericConstTypename a -> numeric a+  ConstBitConstTypename a -> constBit a+  ConstCharacterConstTypename a -> constCharacter a+  ConstDatetimeConstTypename a -> constDatetime a++numeric = \case+  IntNumeric -> []+  IntegerNumeric -> []+  SmallintNumeric -> []+  BigintNumeric -> []+  RealNumeric -> []+  FloatNumeric _ -> []+  DoublePrecisionNumeric -> []+  DecimalNumeric a -> foldMap exprList a+  DecNumeric a -> foldMap exprList a+  NumericNumeric a -> foldMap exprList a+  BooleanNumeric -> []++bit (Bit _ a) = foldMap exprList a++constBit = bit++constCharacter (ConstCharacter _ _) = []++constDatetime _ = []++interval _ = []++-- * Names++ident _ = []++colId = ident++name = colId++cursorName = name++anyName (AnyName a b) = colId a <> foldMap attrs b++columnref (Columnref a b) = colId a <> foldMap indirection b++funcName = \case+  TypeFuncName a -> typeFunctionName a+  IndirectedFuncName a b -> colId a <> indirection b++qualifiedName = \case+  SimpleQualifiedName _ -> []+  IndirectedQualifiedName _ a -> indirection a++indirection = foldMap indirectionEl++indirectionEl = \case+  AttrNameIndirectionEl _ -> []+  AllIndirectionEl -> []+  ExprIndirectionEl a -> aExpr a+  SliceIndirectionEl a b -> exprList a <> exprList b++-- * Types++typeList = foldMap typename++typename (Typename a b c d) =+  simpleTypename b++simpleTypename = \case+  GenericTypeSimpleTypename a -> genericType a+  NumericSimpleTypename a -> numeric a+  BitSimpleTypename a -> bit a+  CharacterSimpleTypename a -> character a+  ConstDatetimeSimpleTypename a -> constDatetime a+  ConstIntervalSimpleTypename a -> either (foldMap interval) (const []) a++arrayBounds _ = []++genericType (GenericType a b c) = typeFunctionName a <> foldMap attrs b <> foldMap typeModifiers c++typeFunctionName = ident++attrs = foldMap attrName++attrName _ = []++typeModifiers = exprList++character _ = []++subType _ = []++-- * Indexes++indexParams = foldMap indexElem++indexElem (IndexElem a b c d e) = indexElemDef a <> foldMap anyName b <> foldMap anyName c++indexElemDef = \case+  IdIndexElemDef a -> colId a+  FuncIndexElemDef a -> funcExprWindowless a+  ExprIndexElemDef a -> aExpr a++ascDesc = const []++nullsOrder = const []
+ src/library/Hasql/TH/Extraction/Exp.hs view
@@ -0,0 +1,112 @@+module Hasql.TH.Extraction.Exp where++import qualified Hasql.Decoders as Decoders+import qualified Hasql.Encoders as Encoders+import qualified Hasql.TH.Construction.Exp as Exp+import qualified Hasql.TH.Extraction.InputTypeList as InputTypeList+import qualified Hasql.TH.Extraction.OutputTypeList as OutputTypeList+import qualified Hasql.TH.Extraction.PrimitiveType as PrimitiveType+import Hasql.TH.Prelude+import Language.Haskell.TH+import qualified PostgresqlSyntax.Ast as Ast+import qualified PostgresqlSyntax.Rendering as Rendering++undecodedStatement :: (Exp -> Exp) -> Ast.PreparableStmt -> Either Text Exp+undecodedStatement _decoderProj _ast =+  let _sql = (Exp.byteString . Rendering.toByteString . Rendering.preparableStmt) _ast+   in do+        _encoder <- paramsEncoder _ast+        _rowDecoder <- rowDecoder _ast+        return (Exp.statement _sql _encoder (_decoderProj _rowDecoder))++foldStatement :: Ast.PreparableStmt -> Either Text Exp+foldStatement _ast =+  let _sql = (Exp.byteString . Rendering.toByteString . Rendering.preparableStmt) _ast+   in do+        _encoder <- paramsEncoder _ast+        _rowDecoder <- rowDecoder _ast+        return (Exp.foldStatement _sql _encoder _rowDecoder)++paramsEncoder :: Ast.PreparableStmt -> Either Text Exp+paramsEncoder a = do+  b <- InputTypeList.preparableStmt a+  c <- traverse paramEncoder b+  return (Exp.contrazip c)++rowDecoder :: Ast.PreparableStmt -> Either Text Exp+rowDecoder a = do+  b <- OutputTypeList.preparableStmt a+  c <- traverse columnDecoder b+  return (Exp.cozip c)++paramEncoder :: Ast.Typename -> Either Text Exp+paramEncoder =+  byTypename+    (\a b -> valueEncoder a & fmap (Exp.unidimensionalParamEncoder b))+    (\a b c d -> valueEncoder a & fmap (Exp.multidimensionalParamEncoder b c d))++columnDecoder :: Ast.Typename -> Either Text Exp+columnDecoder =+  byTypename+    (\a b -> valueDecoder a & fmap (Exp.unidimensionalColumnDecoder b))+    (\a b c d -> valueDecoder a & fmap (Exp.multidimensionalColumnDecoder b c d))++byTypename :: (PrimitiveType.PrimitiveType -> Bool -> Either Text Exp) -> (PrimitiveType.PrimitiveType -> Bool -> Int -> Bool -> Either Text Exp) -> Ast.Typename -> Either Text Exp+byTypename unidimensional multidimensional (Ast.Typename a b c d) =+  if a+    then Left "SETOF is not supported"+    else do+      e <- PrimitiveType.simpleTypename b+      case d of+        Nothing -> unidimensional e c+        Just (f, g) -> case f of+          Ast.BoundsTypenameArrayDimensions h -> multidimensional e c (length h) g+          Ast.ExplicitTypenameArrayDimensions _ -> multidimensional e c 1 g++valueEncoder :: PrimitiveType.PrimitiveType -> Either Text Exp+valueEncoder =+  Right . VarE . \case+    PrimitiveType.BoolPrimitiveType -> 'Encoders.bool+    PrimitiveType.Int2PrimitiveType -> 'Encoders.int2+    PrimitiveType.Int4PrimitiveType -> 'Encoders.int4+    PrimitiveType.Int8PrimitiveType -> 'Encoders.int8+    PrimitiveType.Float4PrimitiveType -> 'Encoders.float4+    PrimitiveType.Float8PrimitiveType -> 'Encoders.float8+    PrimitiveType.NumericPrimitiveType -> 'Encoders.numeric+    PrimitiveType.CharPrimitiveType -> 'Encoders.char+    PrimitiveType.TextPrimitiveType -> 'Encoders.text+    PrimitiveType.ByteaPrimitiveType -> 'Encoders.bytea+    PrimitiveType.DatePrimitiveType -> 'Encoders.date+    PrimitiveType.TimestampPrimitiveType -> 'Encoders.timestamp+    PrimitiveType.TimestamptzPrimitiveType -> 'Encoders.timestamptz+    PrimitiveType.TimePrimitiveType -> 'Encoders.time+    PrimitiveType.TimetzPrimitiveType -> 'Encoders.timetz+    PrimitiveType.IntervalPrimitiveType -> 'Encoders.interval+    PrimitiveType.UuidPrimitiveType -> 'Encoders.uuid+    PrimitiveType.InetPrimitiveType -> 'Encoders.inet+    PrimitiveType.JsonPrimitiveType -> 'Encoders.json+    PrimitiveType.JsonbPrimitiveType -> 'Encoders.jsonb++valueDecoder :: PrimitiveType.PrimitiveType -> Either Text Exp+valueDecoder =+  Right . VarE . \case+    PrimitiveType.BoolPrimitiveType -> 'Decoders.bool+    PrimitiveType.Int2PrimitiveType -> 'Decoders.int2+    PrimitiveType.Int4PrimitiveType -> 'Decoders.int4+    PrimitiveType.Int8PrimitiveType -> 'Decoders.int8+    PrimitiveType.Float4PrimitiveType -> 'Decoders.float4+    PrimitiveType.Float8PrimitiveType -> 'Decoders.float8+    PrimitiveType.NumericPrimitiveType -> 'Decoders.numeric+    PrimitiveType.CharPrimitiveType -> 'Decoders.char+    PrimitiveType.TextPrimitiveType -> 'Decoders.text+    PrimitiveType.ByteaPrimitiveType -> 'Decoders.bytea+    PrimitiveType.DatePrimitiveType -> 'Decoders.date+    PrimitiveType.TimestampPrimitiveType -> 'Decoders.timestamp+    PrimitiveType.TimestamptzPrimitiveType -> 'Decoders.timestamptz+    PrimitiveType.TimePrimitiveType -> 'Decoders.time+    PrimitiveType.TimetzPrimitiveType -> 'Decoders.timetz+    PrimitiveType.IntervalPrimitiveType -> 'Decoders.interval+    PrimitiveType.UuidPrimitiveType -> 'Decoders.uuid+    PrimitiveType.InetPrimitiveType -> 'Decoders.inet+    PrimitiveType.JsonPrimitiveType -> 'Decoders.json+    PrimitiveType.JsonbPrimitiveType -> 'Decoders.jsonb
+ src/library/Hasql/TH/Extraction/InputTypeList.hs view
@@ -0,0 +1,52 @@+-- |+-- AST traversal extracting input types.+module Hasql.TH.Extraction.InputTypeList where++import qualified Data.IntMap.Strict as IntMap+import qualified Hasql.TH.Extraction.PlaceholderTypeMap as PlaceholderTypeMap+import Hasql.TH.Prelude+import PostgresqlSyntax.Ast++-- |+-- >>> import qualified PostgresqlSyntax.Parsing as P+-- >>> test = either fail (return . preparableStmt) . P.run P.preparableStmt+--+-- >>> test "select $1 :: INT"+-- Right [Typename False (NumericSimpleTypename IntNumeric) False Nothing]+--+-- >>> test "select $1 :: INT, a + $2 :: INTEGER"+-- Right [Typename False (NumericSimpleTypename IntNumeric) False Nothing,Typename False (NumericSimpleTypename IntegerNumeric) False Nothing]+--+-- >>> test "select $1 :: INT4"+-- Right [Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "int4") Nothing Nothing)) False Nothing]+--+-- >>> test "select $1 :: text[]?"+-- Right [Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "text") Nothing Nothing)) False (Just (BoundsTypenameArrayDimensions (Nothing :| []),True))]+--+-- >>> test "select $1 :: text?[]?"+-- Right [Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "text") Nothing Nothing)) True (Just (BoundsTypenameArrayDimensions (Nothing :| []),True))]+--+-- >>> test "select $1"+-- Left "Placeholder $1 misses an explicit typecast"+--+-- >>> test "select $2 :: int4, $1 :: int4, $2 :: int4"+-- Right [Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "int4") Nothing Nothing)) False Nothing,Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "int4") Nothing Nothing)) False Nothing]+--+-- >>> test "select $1 :: int4, $1 :: text"+-- Left "Placeholder $1 has conflicting type annotations"+--+-- >>> test "select $2 :: int4, $2 :: text"+-- Left "Placeholder $2 has conflicting type annotations"+--+-- >>> test "select $3 :: int4, $1 :: int4"+-- Left "You've missed placeholder $2"+preparableStmt :: PreparableStmt -> Either Text [Typename]+preparableStmt = placeholderTypeMap <=< PlaceholderTypeMap.preparableStmt++placeholderTypeMap :: IntMap Typename -> Either Text [Typename]+placeholderTypeMap a = do+  zipWithM+    (\a b -> if a == b then Right () else Left ("You've missed placeholder $" <> showAsText b))+    (IntMap.keys a)+    [1 ..]+  return (IntMap.elems a)
+ src/library/Hasql/TH/Extraction/OutputTypeList.hs view
@@ -0,0 +1,90 @@+{-# OPTIONS_GHC -Wno-unused-binds -Wno-unused-imports -Wno-name-shadowing -Wno-incomplete-patterns -Wno-unused-matches -Wno-missing-methods -Wno-unused-record-wildcards -Wno-redundant-constraints -Wno-deprecations -Wno-missing-signatures #-}++-- |+-- AST traversal extracting output types.+module Hasql.TH.Extraction.OutputTypeList where++import Hasql.TH.Prelude+import PostgresqlSyntax.Ast++foldable :: (Foldable f) => (a -> Either Text [Typename]) -> f a -> Either Text [Typename]+foldable fn = fmap join . traverse fn . toList++preparableStmt = \case+  SelectPreparableStmt a -> selectStmt a+  InsertPreparableStmt a -> insertStmt a+  UpdatePreparableStmt a -> updateStmt a+  DeletePreparableStmt a -> deleteStmt a+  CallPreparableStmt a -> callStmt a++-- * Call++callStmt (CallStmt a) =+  Right []++-- * Insert++insertStmt (InsertStmt a b c d e) = foldable returningClause e++returningClause = targetList++-- * Update++updateStmt (UpdateStmt _ _ _ _ _ a) = foldable returningClause a++-- * Delete++deleteStmt (DeleteStmt _ _ _ _ a) = foldable returningClause a++-- * Select++selectStmt = \case+  Left a -> selectNoParens a+  Right a -> selectWithParens a++selectNoParens (SelectNoParens _ a _ _ _) = selectClause a++selectWithParens = \case+  NoParensSelectWithParens a -> selectNoParens a+  WithParensSelectWithParens a -> selectWithParens a++selectClause = either simpleSelect selectWithParens++simpleSelect = \case+  NormalSimpleSelect a _ _ _ _ _ _ -> foldable targeting a+  ValuesSimpleSelect a -> valuesClause a+  TableSimpleSelect _ -> Left "TABLE cannot be used as a final statement, since it's impossible to specify the output types"+  BinSimpleSelect _ a _ b -> do+    c <- selectClause a+    d <- selectClause b+    if c == d+      then return c+      else Left "Merged queries produce results of incompatible types"++targeting = \case+  NormalTargeting a -> targetList a+  AllTargeting a -> foldable targetList a+  DistinctTargeting _ b -> targetList b++targetList = foldable targetEl++targetEl = \case+  AliasedExprTargetEl a _ -> aExpr a+  ImplicitlyAliasedExprTargetEl a _ -> aExpr a+  ExprTargetEl a -> aExpr a+  AsteriskTargetEl ->+    Left+      "Target of all fields is not allowed, \+      \because it leaves the output types unspecified. \+      \You have to be specific."++valuesClause = foldable (foldable aExpr)++aExpr = \case+  CExprAExpr a -> cExpr a+  TypecastAExpr _ a -> Right [a]+  a -> Left "Result expression is missing a typecast"++cExpr = \case+  InParensCExpr a Nothing -> aExpr a+  a -> Left "Result expression is missing a typecast"
+ src/library/Hasql/TH/Extraction/PlaceholderTypeMap.hs view
@@ -0,0 +1,58 @@+{-# OPTIONS_GHC -Wno-missing-signatures #-}++module Hasql.TH.Extraction.PlaceholderTypeMap where++import qualified Data.IntMap.Strict as IntMap+import Hasql.TH.Extraction.ChildExprList (ChildExpr (..))+import qualified Hasql.TH.Extraction.ChildExprList as ChildExprList+import Hasql.TH.Prelude hiding (union)+import PostgresqlSyntax.Ast++preparableStmt :: PreparableStmt -> Either Text (IntMap Typename)+preparableStmt = childExprList . ChildExprList.preparableStmt++childExprList :: [ChildExpr] -> Either Text (IntMap Typename)+childExprList = foldM union IntMap.empty <=< traverse childExpr++union :: IntMap Typename -> IntMap Typename -> Either Text (IntMap Typename)+union a b = IntMap.mergeWithKey merge (fmap Right) (fmap Right) a b & sequence+  where+    merge index a b =+      if a == b+        then Just (Right a)+        else Just (Left ("Placeholder $" <> (fromString . show) index <> " has conflicting type annotations"))++childExpr :: ChildExpr -> Either Text (IntMap Typename)+childExpr = \case+  AChildExpr a -> aExpr a+  BChildExpr a -> bExpr a+  CChildExpr a -> cExpr a++aExpr = \case+  CExprAExpr a -> cExpr a+  TypecastAExpr a b -> castedAExpr b a+  a -> childExprList (ChildExprList.aChildExpr a)++bExpr = \case+  CExprBExpr a -> cExpr a+  TypecastBExpr a b -> castedBExpr b a+  a -> childExprList (ChildExprList.bChildExpr a)++cExpr = \case+  ParamCExpr a _ -> Left ("Placeholder $" <> (fromString . show) a <> " misses an explicit typecast")+  a -> childExprList (ChildExprList.cChildExpr a)++castedAExpr a = \case+  CExprAExpr b -> castedCExpr a b+  TypecastAExpr b c -> castedAExpr c b+  b -> aExpr b++castedBExpr a = \case+  CExprBExpr b -> castedCExpr a b+  TypecastBExpr b c -> castedBExpr c b+  b -> bExpr b++castedCExpr a = \case+  ParamCExpr b _ -> Right (IntMap.singleton b a)+  InParensCExpr b _ -> castedAExpr a b+  b -> cExpr b
+ src/library/Hasql/TH/Extraction/PrimitiveType.hs view
@@ -0,0 +1,102 @@+{-# OPTIONS_GHC -Wno-unused-binds -Wno-unused-imports -Wno-name-shadowing -Wno-incomplete-patterns -Wno-unused-matches -Wno-missing-methods -Wno-unused-record-wildcards -Wno-redundant-constraints -Wno-deprecations -Wno-missing-signatures #-}++module Hasql.TH.Extraction.PrimitiveType where++import Hasql.TH.Prelude hiding (bit, fromList, sortBy)+import PostgresqlSyntax.Ast++data PrimitiveType+  = BoolPrimitiveType+  | Int2PrimitiveType+  | Int4PrimitiveType+  | Int8PrimitiveType+  | Float4PrimitiveType+  | Float8PrimitiveType+  | NumericPrimitiveType+  | CharPrimitiveType+  | TextPrimitiveType+  | ByteaPrimitiveType+  | DatePrimitiveType+  | TimestampPrimitiveType+  | TimestamptzPrimitiveType+  | TimePrimitiveType+  | TimetzPrimitiveType+  | IntervalPrimitiveType+  | UuidPrimitiveType+  | InetPrimitiveType+  | JsonPrimitiveType+  | JsonbPrimitiveType++simpleTypename = \case+  GenericTypeSimpleTypename a -> genericType a+  NumericSimpleTypename a -> numeric a+  BitSimpleTypename a -> bit a+  CharacterSimpleTypename a -> character a+  ConstDatetimeSimpleTypename a -> constDatetime a+  ConstIntervalSimpleTypename a -> Right IntervalPrimitiveType++genericType (GenericType a b c) = case b of+  Just _ -> Left "Type attributes are not supported"+  Nothing -> case c of+    Just _ -> Left "Type modifiers are not supported"+    Nothing -> ident a++numeric = \case+  IntNumeric -> Right Int4PrimitiveType+  IntegerNumeric -> Right Int4PrimitiveType+  SmallintNumeric -> Right Int2PrimitiveType+  BigintNumeric -> Right Int8PrimitiveType+  RealNumeric -> Right Float4PrimitiveType+  FloatNumeric a -> case a of+    Just _ -> Left "Modifier on FLOAT is not supported"+    Nothing -> Right Float4PrimitiveType+  DoublePrecisionNumeric -> Right Float8PrimitiveType+  DecimalNumeric a -> case a of+    Just _ -> Left "Modifiers on DECIMAL are not supported"+    Nothing -> Right NumericPrimitiveType+  DecNumeric a -> case a of+    Just _ -> Left "Modifiers on DEC are not supported"+    Nothing -> Right NumericPrimitiveType+  NumericNumeric a -> case a of+    Just _ -> Left "Modifiers on NUMERIC are not supported"+    Nothing -> Right NumericPrimitiveType+  BooleanNumeric -> Right BoolPrimitiveType++bit _ = Left "Bit codec is not supported"++character _ = Right CharPrimitiveType++constDatetime = \case+  TimestampConstDatetime _ a -> if tz a then Right TimestamptzPrimitiveType else Right TimestampPrimitiveType+  TimeConstDatetime _ a -> if tz a then Right TimetzPrimitiveType else Right TimePrimitiveType+  where+    tz = \case+      Just a -> a+      Nothing -> False++ident = \case+  QuotedIdent a -> name a+  UnquotedIdent a -> name a++name = \case+  "bool" -> Right BoolPrimitiveType+  "int2" -> Right Int2PrimitiveType+  "int4" -> Right Int4PrimitiveType+  "int8" -> Right Int8PrimitiveType+  "float4" -> Right Float4PrimitiveType+  "float8" -> Right Float8PrimitiveType+  "numeric" -> Right NumericPrimitiveType+  "char" -> Right CharPrimitiveType+  "text" -> Right TextPrimitiveType+  "bytea" -> Right ByteaPrimitiveType+  "date" -> Right DatePrimitiveType+  "timestamp" -> Right TimestampPrimitiveType+  "timestamptz" -> Right TimestamptzPrimitiveType+  "time" -> Right TimePrimitiveType+  "timetz" -> Right TimetzPrimitiveType+  "interval" -> Right IntervalPrimitiveType+  "uuid" -> Right UuidPrimitiveType+  "inet" -> Right InetPrimitiveType+  "json" -> Right JsonPrimitiveType+  "jsonb" -> Right JsonbPrimitiveType+  name -> Left ("No codec exists for type: " <> name)
+ src/library/Hasql/TH/Prelude.hs view
@@ -0,0 +1,94 @@+module Hasql.TH.Prelude+  ( module Exports,+    showAsText,+    suffixRec,+  )+where++import Control.Applicative as Exports+import Control.Arrow as Exports hiding (first, second)+import Control.Category as Exports+import Control.Concurrent as Exports+import Control.Exception as Exports+import Control.Foldl as Exports (Fold (..))+import Control.Monad as Exports hiding (fail, forM, forM_, mapM, mapM_, msum, sequence, sequence_)+import Control.Monad.Fail as Exports+import Control.Monad.Fix as Exports hiding (fix)+import Control.Monad.IO.Class as Exports+import Control.Monad.ST as Exports+import Data.Bifunctor as Exports+import Data.Bits as Exports+import Data.Bool as Exports+import Data.ByteString as Exports (ByteString)+import Data.Char as Exports+import Data.Coerce as Exports+import Data.Complex as Exports+import Data.Data as Exports+import Data.Dynamic as Exports+import Data.Either as Exports+import Data.Fixed as Exports+import Data.Foldable as Exports+import Data.Function as Exports hiding (id, (.))+import Data.Functor as Exports hiding (unzip)+import Data.Functor.Contravariant as Exports+import Data.Functor.Contravariant.Divisible as Exports+import Data.Functor.Identity as Exports+import Data.IORef as Exports+import Data.Int as Exports+import Data.IntMap.Strict as Exports (IntMap)+import Data.IntSet as Exports (IntSet)+import Data.Ix as Exports+import Data.List as Exports hiding (all, and, any, concat, concatMap, elem, find, foldl, foldl', foldl1, foldr, foldr1, isSubsequenceOf, mapAccumL, mapAccumR, maximum, maximumBy, minimum, minimumBy, notElem, or, product, sortOn, sum, uncons)+import Data.List.NonEmpty as Exports (NonEmpty (..))+import Data.Map.Strict as Exports (Map)+import Data.Maybe as Exports+import Data.Monoid as Exports hiding (First (..), Last (..), (<>))+import Data.Ord as Exports+import Data.Proxy as Exports+import Data.Ratio as Exports+import Data.STRef as Exports+import Data.Semigroup as Exports+import Data.Sequence as Exports (Seq)+import Data.Set as Exports (Set)+import Data.String as Exports+import Data.Text as Exports (Text)+import Data.Traversable as Exports+import Data.Tuple as Exports+import Data.UUID as Exports (UUID)+import Data.Unique as Exports+import Data.Version as Exports+import Data.Void as Exports+import Data.Word as Exports+import Debug.Trace as Exports+import Foreign.ForeignPtr as Exports+import Foreign.Ptr as Exports+import Foreign.StablePtr as Exports+import Foreign.Storable as Exports hiding (alignment, sizeOf)+import GHC.Conc as Exports hiding (orElse, threadWaitRead, threadWaitReadSTM, threadWaitWrite, threadWaitWriteSTM, withMVar)+import GHC.Exts as Exports (IsList (Item, fromList), groupWith, inline, lazy, sortWith)+import GHC.Generics as Exports (Generic, Generic1)+import GHC.IO.Exception as Exports+import Numeric as Exports+import System.Environment as Exports+import System.Exit as Exports+import System.IO as Exports+import System.IO.Error as Exports+import System.IO.Unsafe as Exports+import System.Mem as Exports+import System.Mem.StableName as Exports+import System.Timeout as Exports+import Text.Printf as Exports (hPrintf, printf)+import Text.Read as Exports (Read (..), readEither, readMaybe)+import Unsafe.Coerce as Exports+import Prelude as Exports hiding (all, and, any, concat, concatMap, elem, fail, foldl, foldl1, foldr, foldr1, id, mapM, mapM_, maximum, minimum, notElem, or, product, sequence, sequence_, sum, (.))++showAsText :: (Show a) => a -> Text+showAsText = show >>> fromString++-- |+-- Compose a monad, which attempts to extend a value, based on the following input.+-- It does that recursively until the suffix alternative fails.+suffixRec :: (Monad m, Alternative m) => m a -> (a -> m a) -> m a+suffixRec base suffix = do+  _base <- base+  suffixRec (suffix _base) suffix <|> pure _base