module PostgREST.Query.Statements
( createWriteStatement
, createReadStatement
, callProcStatement
, createExplainStatement
) where
import qualified Data.Aeson as JSON
import qualified Data.Aeson.Lens as L
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy as LBS
import qualified Hasql.Decoders as HD
import qualified Hasql.DynamicStatements.Snippet as SQL
import qualified Hasql.DynamicStatements.Statement as SQL
import qualified Hasql.Statement as SQL
import Control.Lens ((^?))
import Data.Maybe (fromJust)
import Data.Text.Read (decimal)
import Network.HTTP.Types.Status (Status)
import PostgREST.Error (Error (..))
import PostgREST.GucHeader (GucHeader)
import PostgREST.DbStructure.Identifiers (FieldName)
import PostgREST.Query.SqlFragment
import PostgREST.Request.Preferences
import Protolude
type ResultsWithCount = (Maybe Int64, Int64, [BS.ByteString], BS.ByteString, Either Error [GucHeader], Either Error (Maybe Status))
createWriteStatement :: SQL.Snippet -> SQL.Snippet -> Bool -> Bool -> Bool ->
PreferRepresentation -> [Text] -> Bool ->
SQL.Statement () ResultsWithCount
createWriteStatement :: Snippet
-> Snippet
-> Bool
-> Bool
-> Bool
-> PreferRepresentation
-> [Text]
-> Bool
-> Statement () ResultsWithCount
createWriteStatement Snippet
selectQuery Snippet
mutateQuery Bool
wantSingle Bool
isInsert Bool
asCsv PreferRepresentation
rep [Text]
pKeys =
Snippet
-> Result ResultsWithCount -> Bool -> Statement () ResultsWithCount
forall result.
Snippet -> Result result -> Bool -> Statement () result
SQL.dynamicallyParameterized Snippet
snippet Result ResultsWithCount
decodeStandard
where
snippet :: Snippet
snippet =
Snippet
"WITH " Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> ByteString -> Snippet
SQL.sql ByteString
sourceCTEName Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
" AS (" Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
mutateQuery Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
") " Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<>
ByteString -> Snippet
SQL.sql (
ByteString
"SELECT " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
"'' AS total_result_set, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
"pg_catalog.count(_postgrest_t) AS page_total, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
locF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS header, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
bodyF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS body, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
responseHeadersF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS response_headers, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
responseStatusF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS response_status "
) Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<>
Snippet
"FROM (" Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
selectF Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
") _postgrest_t"
locF :: ByteString
locF =
if Bool
isInsert Bool -> Bool -> Bool
&& PreferRepresentation
rep PreferRepresentation -> [PreferRepresentation] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [PreferRepresentation
Full, PreferRepresentation
HeadersOnly]
then [ByteString] -> ByteString
BS.unwords [
ByteString
"CASE WHEN pg_catalog.count(_postgrest_t) = 1",
ByteString
"THEN coalesce(" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> [Text] -> ByteString
locationF [Text]
pKeys ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
", " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
noLocationF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
")",
ByteString
"ELSE " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
noLocationF,
ByteString
"END"]
else ByteString
noLocationF
bodyF :: ByteString
bodyF
| PreferRepresentation
rep PreferRepresentation -> [PreferRepresentation] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [PreferRepresentation
None, PreferRepresentation
HeadersOnly] = ByteString
"''"
| Bool
asCsv = ByteString
asCsvF
| Bool
wantSingle = Bool -> ByteString
asJsonSingleF Bool
False
| Bool
otherwise = Bool -> ByteString
asJsonF Bool
False
selectF :: Snippet
selectF
| PreferRepresentation
rep PreferRepresentation -> [PreferRepresentation] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [PreferRepresentation
None, PreferRepresentation
HeadersOnly] = ByteString -> Snippet
SQL.sql (ByteString
"SELECT * FROM " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
sourceCTEName)
| Bool
otherwise = Snippet
selectQuery
decodeStandard :: HD.Result ResultsWithCount
decodeStandard :: Result ResultsWithCount
decodeStandard =
ResultsWithCount -> Maybe ResultsWithCount -> ResultsWithCount
forall a. a -> Maybe a -> a
fromMaybe (Maybe Int64
forall a. Maybe a
Nothing, Int64
0, [], ByteString
forall a. Monoid a => a
mempty, [GucHeader] -> Either Error [GucHeader]
forall a b. b -> Either a b
Right [], Maybe Status -> Either Error (Maybe Status)
forall a b. b -> Either a b
Right Maybe Status
forall a. Maybe a
Nothing) (Maybe ResultsWithCount -> ResultsWithCount)
-> Result (Maybe ResultsWithCount) -> Result ResultsWithCount
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Row ResultsWithCount -> Result (Maybe ResultsWithCount)
forall a. Row a -> Result (Maybe a)
HD.rowMaybe Row ResultsWithCount
standardRow
createReadStatement :: SQL.Snippet -> SQL.Snippet -> Bool -> Bool -> Bool -> Maybe FieldName -> Bool ->
SQL.Statement () ResultsWithCount
createReadStatement :: Snippet
-> Snippet
-> Bool
-> Bool
-> Bool
-> Maybe Text
-> Bool
-> Statement () ResultsWithCount
createReadStatement Snippet
selectQuery Snippet
countQuery Bool
isSingle Bool
countTotal Bool
asCsv Maybe Text
binaryField =
Snippet
-> Result ResultsWithCount -> Bool -> Statement () ResultsWithCount
forall result.
Snippet -> Result result -> Bool -> Statement () result
SQL.dynamicallyParameterized Snippet
snippet Result ResultsWithCount
decodeStandard
where
snippet :: Snippet
snippet =
Snippet
"WITH " Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<>
ByteString -> Snippet
SQL.sql ByteString
sourceCTEName Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
" AS ( " Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
selectQuery Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
" ) " Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<>
Snippet
countCTEF Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
" " Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<>
ByteString -> Snippet
SQL.sql (ByteString
"SELECT " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
countResultF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS total_result_set, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
"pg_catalog.count(_postgrest_t) AS page_total, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
noLocationF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS header, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
bodyF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS body, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
responseHeadersF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS response_headers, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
responseStatusF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS response_status " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
"FROM ( SELECT * FROM " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
sourceCTEName ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" ) _postgrest_t")
(Snippet
countCTEF, ByteString
countResultF) = Snippet -> Bool -> (Snippet, ByteString)
countF Snippet
countQuery Bool
countTotal
bodyF :: ByteString
bodyF
| Bool
asCsv = ByteString
asCsvF
| Bool
isSingle = Bool -> ByteString
asJsonSingleF Bool
False
| Maybe Text -> Bool
forall a. Maybe a -> Bool
isJust Maybe Text
binaryField = Text -> ByteString
asBinaryF (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ Maybe Text -> Text
forall a. HasCallStack => Maybe a -> a
fromJust Maybe Text
binaryField
| Bool
otherwise = Bool -> ByteString
asJsonF Bool
False
decodeStandard :: HD.Result ResultsWithCount
decodeStandard :: Result ResultsWithCount
decodeStandard =
Row ResultsWithCount -> Result ResultsWithCount
forall a. Row a -> Result a
HD.singleRow Row ResultsWithCount
standardRow
standardRow :: HD.Row ResultsWithCount
standardRow :: Row ResultsWithCount
standardRow = (,,,,,) (Maybe Int64
-> Int64
-> [ByteString]
-> ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ResultsWithCount)
-> Row (Maybe Int64)
-> Row
(Int64
-> [ByteString]
-> ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ResultsWithCount)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value Int64 -> Row (Maybe Int64)
forall a. Value a -> Row (Maybe a)
nullableColumn Value Int64
HD.int8 Row
(Int64
-> [ByteString]
-> ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ResultsWithCount)
-> Row Int64
-> Row
([ByteString]
-> ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ResultsWithCount)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Value Int64 -> Row Int64
forall a. Value a -> Row a
column Value Int64
HD.int8
Row
([ByteString]
-> ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ResultsWithCount)
-> Row [ByteString]
-> Row
(ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ResultsWithCount)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Value ByteString -> Row [ByteString]
forall a. Value a -> Row [a]
arrayColumn Value ByteString
HD.bytea Row
(ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ResultsWithCount)
-> Row ByteString
-> Row
(Either Error [GucHeader]
-> Either Error (Maybe Status) -> ResultsWithCount)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Value ByteString -> Row ByteString
forall a. Value a -> Row a
column Value ByteString
HD.bytea
Row
(Either Error [GucHeader]
-> Either Error (Maybe Status) -> ResultsWithCount)
-> Row (Either Error [GucHeader])
-> Row (Either Error (Maybe Status) -> ResultsWithCount)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Either Error [GucHeader]
-> Maybe (Either Error [GucHeader]) -> Either Error [GucHeader]
forall a. a -> Maybe a -> a
fromMaybe ([GucHeader] -> Either Error [GucHeader]
forall a b. b -> Either a b
Right []) (Maybe (Either Error [GucHeader]) -> Either Error [GucHeader])
-> Row (Maybe (Either Error [GucHeader]))
-> Row (Either Error [GucHeader])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value (Either Error [GucHeader])
-> Row (Maybe (Either Error [GucHeader]))
forall a. Value a -> Row (Maybe a)
nullableColumn Value (Either Error [GucHeader])
decodeGucHeaders)
Row (Either Error (Maybe Status) -> ResultsWithCount)
-> Row (Either Error (Maybe Status)) -> Row ResultsWithCount
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Either Error (Maybe Status)
-> Maybe (Either Error (Maybe Status))
-> Either Error (Maybe Status)
forall a. a -> Maybe a -> a
fromMaybe (Maybe Status -> Either Error (Maybe Status)
forall a b. b -> Either a b
Right Maybe Status
forall a. Maybe a
Nothing) (Maybe (Either Error (Maybe Status))
-> Either Error (Maybe Status))
-> Row (Maybe (Either Error (Maybe Status)))
-> Row (Either Error (Maybe Status))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value (Either Error (Maybe Status))
-> Row (Maybe (Either Error (Maybe Status)))
forall a. Value a -> Row (Maybe a)
nullableColumn Value (Either Error (Maybe Status))
decodeGucStatus)
type ProcResults = (Maybe Int64, Int64, ByteString, Either Error [GucHeader], Either Error (Maybe Status))
callProcStatement :: Bool -> Bool -> SQL.Snippet -> SQL.Snippet -> SQL.Snippet -> Bool ->
Bool -> Bool -> Bool -> Maybe FieldName -> Bool ->
SQL.Statement () ProcResults
callProcStatement :: Bool
-> Bool
-> Snippet
-> Snippet
-> Snippet
-> Bool
-> Bool
-> Bool
-> Bool
-> Maybe Text
-> Bool
-> Statement () ProcResults
callProcStatement Bool
returnsScalar Bool
returnsSingle Snippet
callProcQuery Snippet
selectQuery Snippet
countQuery Bool
countTotal Bool
asSingle Bool
asCsv Bool
multObjects Maybe Text
binaryField =
Snippet -> Result ProcResults -> Bool -> Statement () ProcResults
forall result.
Snippet -> Result result -> Bool -> Statement () result
SQL.dynamicallyParameterized Snippet
snippet Result ProcResults
decodeProc
where
snippet :: Snippet
snippet =
Snippet
"WITH " Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> ByteString -> Snippet
SQL.sql ByteString
sourceCTEName Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
" AS (" Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
callProcQuery Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
") " Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<>
Snippet
countCTEF Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<>
ByteString -> Snippet
SQL.sql (
ByteString
"SELECT " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
countResultF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS total_result_set, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
"pg_catalog.count(_postgrest_t) AS page_total, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
bodyF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS body, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
responseHeadersF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS response_headers, " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>
ByteString
responseStatusF ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
" AS response_status ") Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<>
Snippet
"FROM (" Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
selectQuery Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
") _postgrest_t"
(Snippet
countCTEF, ByteString
countResultF) = Snippet -> Bool -> (Snippet, ByteString)
countF Snippet
countQuery Bool
countTotal
bodyF :: ByteString
bodyF
| Bool
asSingle = Bool -> ByteString
asJsonSingleF Bool
returnsScalar
| Bool
asCsv = ByteString
asCsvF
| Maybe Text -> Bool
forall a. Maybe a -> Bool
isJust Maybe Text
binaryField = Text -> ByteString
asBinaryF (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ Maybe Text -> Text
forall a. HasCallStack => Maybe a -> a
fromJust Maybe Text
binaryField
| Bool
returnsSingle
Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
multObjects = Bool -> ByteString
asJsonSingleF Bool
returnsScalar
| Bool
otherwise = Bool -> ByteString
asJsonF Bool
returnsScalar
decodeProc :: HD.Result ProcResults
decodeProc :: Result ProcResults
decodeProc =
ProcResults -> Maybe ProcResults -> ProcResults
forall a. a -> Maybe a -> a
fromMaybe (Int64 -> Maybe Int64
forall a. a -> Maybe a
Just Int64
0, Int64
0, ByteString
forall a. Monoid a => a
mempty, Either Error [GucHeader]
forall a a. Either a [a]
defGucHeaders, Either Error (Maybe Status)
forall a a. Either a (Maybe a)
defGucStatus) (Maybe ProcResults -> ProcResults)
-> Result (Maybe ProcResults) -> Result ProcResults
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Row ProcResults -> Result (Maybe ProcResults)
forall a. Row a -> Result (Maybe a)
HD.rowMaybe Row ProcResults
procRow
where
defGucHeaders :: Either a [a]
defGucHeaders = [a] -> Either a [a]
forall a b. b -> Either a b
Right []
defGucStatus :: Either a (Maybe a)
defGucStatus = Maybe a -> Either a (Maybe a)
forall a b. b -> Either a b
Right Maybe a
forall a. Maybe a
Nothing
procRow :: Row ProcResults
procRow = (,,,,) (Maybe Int64
-> Int64
-> ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ProcResults)
-> Row (Maybe Int64)
-> Row
(Int64
-> ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ProcResults)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value Int64 -> Row (Maybe Int64)
forall a. Value a -> Row (Maybe a)
nullableColumn Value Int64
HD.int8 Row
(Int64
-> ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ProcResults)
-> Row Int64
-> Row
(ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ProcResults)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Value Int64 -> Row Int64
forall a. Value a -> Row a
column Value Int64
HD.int8
Row
(ByteString
-> Either Error [GucHeader]
-> Either Error (Maybe Status)
-> ProcResults)
-> Row ByteString
-> Row
(Either Error [GucHeader]
-> Either Error (Maybe Status) -> ProcResults)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Value ByteString -> Row ByteString
forall a. Value a -> Row a
column Value ByteString
HD.bytea
Row
(Either Error [GucHeader]
-> Either Error (Maybe Status) -> ProcResults)
-> Row (Either Error [GucHeader])
-> Row (Either Error (Maybe Status) -> ProcResults)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Either Error [GucHeader]
-> Maybe (Either Error [GucHeader]) -> Either Error [GucHeader]
forall a. a -> Maybe a -> a
fromMaybe Either Error [GucHeader]
forall a a. Either a [a]
defGucHeaders (Maybe (Either Error [GucHeader]) -> Either Error [GucHeader])
-> Row (Maybe (Either Error [GucHeader]))
-> Row (Either Error [GucHeader])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value (Either Error [GucHeader])
-> Row (Maybe (Either Error [GucHeader]))
forall a. Value a -> Row (Maybe a)
nullableColumn Value (Either Error [GucHeader])
decodeGucHeaders)
Row (Either Error (Maybe Status) -> ProcResults)
-> Row (Either Error (Maybe Status)) -> Row ProcResults
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Either Error (Maybe Status)
-> Maybe (Either Error (Maybe Status))
-> Either Error (Maybe Status)
forall a. a -> Maybe a -> a
fromMaybe Either Error (Maybe Status)
forall a a. Either a (Maybe a)
defGucStatus (Maybe (Either Error (Maybe Status))
-> Either Error (Maybe Status))
-> Row (Maybe (Either Error (Maybe Status)))
-> Row (Either Error (Maybe Status))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value (Either Error (Maybe Status))
-> Row (Maybe (Either Error (Maybe Status)))
forall a. Value a -> Row (Maybe a)
nullableColumn Value (Either Error (Maybe Status))
decodeGucStatus)
createExplainStatement :: SQL.Snippet -> Bool -> SQL.Statement () (Maybe Int64)
createExplainStatement :: Snippet -> Bool -> Statement () (Maybe Int64)
createExplainStatement Snippet
countQuery =
Snippet
-> Result (Maybe Int64) -> Bool -> Statement () (Maybe Int64)
forall result.
Snippet -> Result result -> Bool -> Statement () result
SQL.dynamicallyParameterized Snippet
snippet Result (Maybe Int64)
decodeExplain
where
snippet :: Snippet
snippet = Snippet
"EXPLAIN (FORMAT JSON) " Snippet -> Snippet -> Snippet
forall a. Semigroup a => a -> a -> a
<> Snippet
countQuery
decodeExplain :: HD.Result (Maybe Int64)
decodeExplain :: Result (Maybe Int64)
decodeExplain =
let row :: Result ByteString
row = Row ByteString -> Result ByteString
forall a. Row a -> Result a
HD.singleRow (Row ByteString -> Result ByteString)
-> Row ByteString -> Result ByteString
forall a b. (a -> b) -> a -> b
$ Value ByteString -> Row ByteString
forall a. Value a -> Row a
column Value ByteString
HD.bytea in
(ByteString -> Getting (First Int64) ByteString Int64 -> Maybe Int64
forall s a. s -> Getting (First a) s a -> Maybe a
^? Int -> Traversal' ByteString Value
forall t. AsValue t => Int -> Traversal' t Value
L.nth Int
0 ((Value -> Const (First Int64) Value)
-> ByteString -> Const (First Int64) ByteString)
-> ((Int64 -> Const (First Int64) Int64)
-> Value -> Const (First Int64) Value)
-> Getting (First Int64) ByteString Int64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Traversal' Value Value
forall t. AsValue t => Text -> Traversal' t Value
L.key Text
"Plan" ((Value -> Const (First Int64) Value)
-> Value -> Const (First Int64) Value)
-> ((Int64 -> Const (First Int64) Int64)
-> Value -> Const (First Int64) Value)
-> (Int64 -> Const (First Int64) Int64)
-> Value
-> Const (First Int64) Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Traversal' Value Value
forall t. AsValue t => Text -> Traversal' t Value
L.key Text
"Plan Rows" ((Value -> Const (First Int64) Value)
-> Value -> Const (First Int64) Value)
-> ((Int64 -> Const (First Int64) Int64)
-> Value -> Const (First Int64) Value)
-> (Int64 -> Const (First Int64) Int64)
-> Value
-> Const (First Int64) Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int64 -> Const (First Int64) Int64)
-> Value -> Const (First Int64) Value
forall t a. (AsNumber t, Integral a) => Prism' t a
L._Integral) (ByteString -> Maybe Int64)
-> Result ByteString -> Result (Maybe Int64)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Result ByteString
row
decodeGucHeaders :: HD.Value (Either Error [GucHeader])
= (String -> Error)
-> Either String [GucHeader] -> Either Error [GucHeader]
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Error -> String -> Error
forall a b. a -> b -> a
const Error
GucHeadersError) (Either String [GucHeader] -> Either Error [GucHeader])
-> (ByteString -> Either String [GucHeader])
-> ByteString
-> Either Error [GucHeader]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String [GucHeader]
forall a. FromJSON a => ByteString -> Either String a
JSON.eitherDecode (ByteString -> Either String [GucHeader])
-> (ByteString -> ByteString)
-> ByteString
-> Either String [GucHeader]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LBS.fromStrict (ByteString -> Either Error [GucHeader])
-> Value ByteString -> Value (Either Error [GucHeader])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value ByteString
HD.bytea
decodeGucStatus :: HD.Value (Either Error (Maybe Status))
decodeGucStatus :: Value (Either Error (Maybe Status))
decodeGucStatus = (String -> Error)
-> Either String (Maybe Status) -> Either Error (Maybe Status)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (Error -> String -> Error
forall a b. a -> b -> a
const Error
GucStatusError) (Either String (Maybe Status) -> Either Error (Maybe Status))
-> (Text -> Either String (Maybe Status))
-> Text
-> Either Error (Maybe Status)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Int, Text) -> Maybe Status)
-> Either String (Int, Text) -> Either String (Maybe Status)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Status -> Maybe Status
forall a. a -> Maybe a
Just (Status -> Maybe Status)
-> ((Int, Text) -> Status) -> (Int, Text) -> Maybe Status
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Status
forall a. Enum a => Int -> a
toEnum (Int -> Status) -> ((Int, Text) -> Int) -> (Int, Text) -> Status
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, Text) -> Int
forall a b. (a, b) -> a
fst) (Either String (Int, Text) -> Either String (Maybe Status))
-> (Text -> Either String (Int, Text))
-> Text
-> Either String (Maybe Status)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either String (Int, Text)
forall a. Integral a => Reader a
decimal (Text -> Either Error (Maybe Status))
-> Value Text -> Value (Either Error (Maybe Status))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value Text
HD.text
column :: HD.Value a -> HD.Row a
column :: Value a -> Row a
column = NullableOrNot Value a -> Row a
forall a. NullableOrNot Value a -> Row a
HD.column (NullableOrNot Value a -> Row a)
-> (Value a -> NullableOrNot Value a) -> Value a -> Row a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value a -> NullableOrNot Value a
forall (decoder :: * -> *) a. decoder a -> NullableOrNot decoder a
HD.nonNullable
nullableColumn :: HD.Value a -> HD.Row (Maybe a)
nullableColumn :: Value a -> Row (Maybe a)
nullableColumn = NullableOrNot Value (Maybe a) -> Row (Maybe a)
forall a. NullableOrNot Value a -> Row a
HD.column (NullableOrNot Value (Maybe a) -> Row (Maybe a))
-> (Value a -> NullableOrNot Value (Maybe a))
-> Value a
-> Row (Maybe a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value a -> NullableOrNot Value (Maybe a)
forall (decoder :: * -> *) a.
decoder a -> NullableOrNot decoder (Maybe a)
HD.nullable
arrayColumn :: HD.Value a -> HD.Row [a]
arrayColumn :: Value a -> Row [a]
arrayColumn = Value [a] -> Row [a]
forall a. Value a -> Row a
column (Value [a] -> Row [a])
-> (Value a -> Value [a]) -> Value a -> Row [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NullableOrNot Value a -> Value [a]
forall element. NullableOrNot Value element -> Value [element]
HD.listArray (NullableOrNot Value a -> Value [a])
-> (Value a -> NullableOrNot Value a) -> Value a -> Value [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value a -> NullableOrNot Value a
forall (decoder :: * -> *) a. decoder a -> NullableOrNot decoder a
HD.nonNullable