module Hasura.Backends.Postgres.Translate.Select.Internal.Helpers
( mkFirstElementExp,
mkLastElementExp,
cursorIdentifier,
startCursorIdentifier,
endCursorIdentifier,
hasNextPageIdentifier,
hasPreviousPageIdentifier,
pageInfoSelectAlias,
pageInfoSelectAliasIdentifier,
cursorsSelectAlias,
cursorsSelectAliasIdentifier,
encodeBase64,
fromTableRowArgs,
functionToIdentifier,
withJsonBuildObj,
withForceAggregation,
selectToSelectWith,
customSQLToTopLevelCTEs,
customSQLToInnerCTEs,
nativeQueryNameToAlias,
toQuery,
)
where
import Control.Monad.Writer (Writer, runWriter)
import Data.Bifunctor (bimap)
import Data.HashMap.Strict qualified as HashMap
import Data.Text.Extended (toTxt)
import Database.PG.Query (Query, fromBuilder)
import Hasura.Backends.Postgres.SQL.DML qualified as S
import Hasura.Backends.Postgres.SQL.RenameIdentifiers
import Hasura.Backends.Postgres.SQL.Types
( Identifier (..),
QualifiedFunction,
TableIdentifier (..),
qualifiedObjectToText,
tableIdentifierToIdentifier,
)
import Hasura.Backends.Postgres.Translate.Select.Internal.Aliases
import Hasura.Backends.Postgres.Translate.Types (CustomSQLCTEs (..))
import Hasura.Backends.Postgres.Types.Function
import Hasura.Function.Cache
import Hasura.NativeQuery.Metadata (NativeQueryName (..))
import Hasura.Prelude
import Hasura.RQL.Types.Common (FieldName)
import Hasura.SQL.Types (ToSQL (toSQL))
mkFirstElementExp :: S.SQLExp -> S.SQLExp
mkFirstElementExp :: SQLExp -> SQLExp
mkFirstElementExp SQLExp
expIdentifier =
SQLExp -> SQLExp -> SQLExp
S.SEArrayIndex (Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
S.SEFnApp Text
"array_agg" [SQLExp
expIdentifier] Maybe OrderByExp
forall a. Maybe a
Nothing) (Int -> SQLExp
S.intToSQLExp Int
1)
mkLastElementExp :: S.SQLExp -> S.SQLExp
mkLastElementExp :: SQLExp -> SQLExp
mkLastElementExp SQLExp
expIdentifier =
let arrayExp :: SQLExp
arrayExp = Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
S.SEFnApp Text
"array_agg" [SQLExp
expIdentifier] Maybe OrderByExp
forall a. Maybe a
Nothing
in SQLExp -> SQLExp -> SQLExp
S.SEArrayIndex SQLExp
arrayExp
(SQLExp -> SQLExp) -> SQLExp -> SQLExp
forall a b. (a -> b) -> a -> b
$ Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
S.SEFnApp Text
"array_length" [SQLExp
arrayExp, Int -> SQLExp
S.intToSQLExp Int
1] Maybe OrderByExp
forall a. Maybe a
Nothing
cursorIdentifier :: Identifier
cursorIdentifier :: Identifier
cursorIdentifier = Text -> Identifier
Identifier Text
"__cursor"
startCursorIdentifier :: Identifier
startCursorIdentifier :: Identifier
startCursorIdentifier = Text -> Identifier
Identifier Text
"__start_cursor"
endCursorIdentifier :: Identifier
endCursorIdentifier :: Identifier
endCursorIdentifier = Text -> Identifier
Identifier Text
"__end_cursor"
hasPreviousPageIdentifier :: Identifier
hasPreviousPageIdentifier :: Identifier
hasPreviousPageIdentifier = Text -> Identifier
Identifier Text
"__has_previous_page"
hasNextPageIdentifier :: Identifier
hasNextPageIdentifier :: Identifier
hasNextPageIdentifier = Text -> Identifier
Identifier Text
"__has_next_page"
pageInfoSelectAlias :: S.TableAlias
pageInfoSelectAlias :: TableAlias
pageInfoSelectAlias = Text -> TableAlias
S.mkTableAlias Text
"__page_info"
pageInfoSelectAliasIdentifier :: TableIdentifier
pageInfoSelectAliasIdentifier :: TableIdentifier
pageInfoSelectAliasIdentifier = TableAlias -> TableIdentifier
S.tableAliasToIdentifier TableAlias
pageInfoSelectAlias
cursorsSelectAlias :: S.TableAlias
= Text -> TableAlias
S.mkTableAlias Text
"__cursors_select"
cursorsSelectAliasIdentifier :: TableIdentifier
= TableAlias -> TableIdentifier
S.tableAliasToIdentifier TableAlias
cursorsSelectAlias
encodeBase64 :: S.SQLExp -> S.SQLExp
encodeBase64 :: SQLExp -> SQLExp
encodeBase64 =
SQLExp -> SQLExp
removeNewline (SQLExp -> SQLExp) -> (SQLExp -> SQLExp) -> SQLExp -> SQLExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SQLExp -> SQLExp
bytesToBase64Text (SQLExp -> SQLExp) -> (SQLExp -> SQLExp) -> SQLExp -> SQLExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SQLExp -> SQLExp
convertToBytes
where
convertToBytes :: SQLExp -> SQLExp
convertToBytes SQLExp
e =
Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
S.SEFnApp Text
"convert_to" [SQLExp
e, Text -> SQLExp
S.SELit Text
"UTF8"] Maybe OrderByExp
forall a. Maybe a
Nothing
bytesToBase64Text :: SQLExp -> SQLExp
bytesToBase64Text SQLExp
e =
Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
S.SEFnApp Text
"encode" [SQLExp
e, Text -> SQLExp
S.SELit Text
"base64"] Maybe OrderByExp
forall a. Maybe a
Nothing
removeNewline :: SQLExp -> SQLExp
removeNewline SQLExp
e =
Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
S.SEFnApp Text
"regexp_replace" [SQLExp
e, Text -> SQLExp
S.SELit Text
"\\n", Text -> SQLExp
S.SELit Text
"", Text -> SQLExp
S.SELit Text
"g"] Maybe OrderByExp
forall a. Maybe a
Nothing
fromTableRowArgs ::
TableIdentifier -> FunctionArgsExpG (ArgumentExp S.SQLExp) -> S.FunctionArgs
fromTableRowArgs :: TableIdentifier
-> FunctionArgsExpG (ArgumentExp SQLExp) -> FunctionArgs
fromTableRowArgs TableIdentifier
prefix = FunctionArgsExpG SQLExp -> FunctionArgs
toFunctionArgs (FunctionArgsExpG SQLExp -> FunctionArgs)
-> (FunctionArgsExpG (ArgumentExp SQLExp)
-> FunctionArgsExpG SQLExp)
-> FunctionArgsExpG (ArgumentExp SQLExp)
-> FunctionArgs
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ArgumentExp SQLExp -> SQLExp)
-> FunctionArgsExpG (ArgumentExp SQLExp) -> FunctionArgsExpG SQLExp
forall a b. (a -> b) -> FunctionArgsExpG a -> FunctionArgsExpG b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ArgumentExp SQLExp -> SQLExp
toSQLExp
where
toFunctionArgs :: FunctionArgsExpG SQLExp -> FunctionArgs
toFunctionArgs (FunctionArgsExp [SQLExp]
positional HashMap Text SQLExp
named) =
[SQLExp] -> HashMap Text SQLExp -> FunctionArgs
S.FunctionArgs [SQLExp]
positional HashMap Text SQLExp
named
toSQLExp :: ArgumentExp SQLExp -> SQLExp
toSQLExp =
SQLExp -> (Text -> SQLExp) -> ArgumentExp SQLExp -> SQLExp
forall a. a -> (Text -> a) -> ArgumentExp a -> a
onArgumentExp
(Identifier -> SQLExp
S.SERowIdentifier (TableIdentifier -> Identifier
tableIdentifierToIdentifier TableIdentifier
baseTableIdentifier))
(TableIdentifier -> Identifier -> SQLExp
forall b. IsIdentifier b => TableIdentifier -> b -> SQLExp
S.mkQIdenExp TableIdentifier
baseTableIdentifier (Identifier -> SQLExp) -> (Text -> Identifier) -> Text -> SQLExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Identifier
Identifier)
baseTableIdentifier :: TableIdentifier
baseTableIdentifier = TableIdentifier -> TableIdentifier
mkBaseTableIdentifier TableIdentifier
prefix
nativeQueryNameToAlias :: NativeQueryName -> Int -> S.TableAlias
nativeQueryNameToAlias :: NativeQueryName -> Int -> TableAlias
nativeQueryNameToAlias NativeQueryName
nqName Int
freshId = Text -> TableAlias
S.mkTableAlias (Text
"cte_" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Name -> Text
forall a. ToTxt a => a -> Text
toTxt (NativeQueryName -> Name
getNativeQueryName NativeQueryName
nqName) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"_" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall a. Show a => a -> Text
tshow Int
freshId)
functionToIdentifier :: QualifiedFunction -> Identifier
functionToIdentifier :: QualifiedFunction -> Identifier
functionToIdentifier = Text -> Identifier
Identifier (Text -> Identifier)
-> (QualifiedFunction -> Text) -> QualifiedFunction -> Identifier
forall b c a. (b -> c) -> (a -> b) -> a -> c
. QualifiedFunction -> Text
forall a. ToTxt a => QualifiedObject a -> Text
qualifiedObjectToText
withJsonBuildObj ::
FieldName -> [S.SQLExp] -> (S.ColumnAlias, S.SQLExp)
withJsonBuildObj :: FieldName -> [SQLExp] -> (ColumnAlias, SQLExp)
withJsonBuildObj FieldName
parAls [SQLExp]
exps =
(FieldName -> ColumnAlias
forall a. IsIdentifier a => a -> ColumnAlias
S.toColumnAlias FieldName
parAls, SQLExp
jsonRow)
where
jsonRow :: SQLExp
jsonRow = [SQLExp] -> SQLExp
S.applyJsonBuildObj [SQLExp]
exps
withForceAggregation :: S.TypeAnn -> S.SQLExp -> S.SQLExp
withForceAggregation :: TypeAnn -> SQLExp -> SQLExp
withForceAggregation TypeAnn
tyAnn SQLExp
e =
Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
S.SEFnApp Text
"coalesce" [SQLExp
e, SQLExp -> TypeAnn -> SQLExp
S.SETyAnn (Text -> SQLExp
S.SEUnsafe Text
"bool_or('true')") TypeAnn
tyAnn] Maybe OrderByExp
forall a. Maybe a
Nothing
selectToSelectWith :: Writer CustomSQLCTEs S.Select -> S.SelectWith
selectToSelectWith :: Writer CustomSQLCTEs Select -> SelectWithG TopLevelCTE
selectToSelectWith Writer CustomSQLCTEs Select
action =
let (Select
selectSQL, CustomSQLCTEs
customSQLCTEs) = Writer CustomSQLCTEs Select -> (Select, CustomSQLCTEs)
forall w a. Writer w a -> (a, w)
runWriter Writer CustomSQLCTEs Select
action
in [(TableAlias, TopLevelCTE)] -> Select -> SelectWithG TopLevelCTE
forall statement.
[(TableAlias, statement)] -> Select -> SelectWithG statement
S.SelectWith (CustomSQLCTEs -> [(TableAlias, TopLevelCTE)]
customSQLToTopLevelCTEs CustomSQLCTEs
customSQLCTEs) Select
selectSQL
customSQLToTopLevelCTEs :: CustomSQLCTEs -> [(S.TableAlias, S.TopLevelCTE)]
customSQLToTopLevelCTEs :: CustomSQLCTEs -> [(TableAlias, TopLevelCTE)]
customSQLToTopLevelCTEs =
((TableAlias, InterpolatedQuery SQLExp)
-> (TableAlias, TopLevelCTE))
-> [(TableAlias, InterpolatedQuery SQLExp)]
-> [(TableAlias, TopLevelCTE)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((TableAlias -> TableAlias)
-> (InterpolatedQuery SQLExp -> TopLevelCTE)
-> (TableAlias, InterpolatedQuery SQLExp)
-> (TableAlias, TopLevelCTE)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap TableAlias -> TableAlias
forall a. IsIdentifier a => a -> TableAlias
S.toTableAlias InterpolatedQuery SQLExp -> TopLevelCTE
S.CTEUnsafeRawSQL) ([(TableAlias, InterpolatedQuery SQLExp)]
-> [(TableAlias, TopLevelCTE)])
-> (CustomSQLCTEs -> [(TableAlias, InterpolatedQuery SQLExp)])
-> CustomSQLCTEs
-> [(TableAlias, TopLevelCTE)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap TableAlias (InterpolatedQuery SQLExp)
-> [(TableAlias, InterpolatedQuery SQLExp)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList (HashMap TableAlias (InterpolatedQuery SQLExp)
-> [(TableAlias, InterpolatedQuery SQLExp)])
-> (CustomSQLCTEs -> HashMap TableAlias (InterpolatedQuery SQLExp))
-> CustomSQLCTEs
-> [(TableAlias, InterpolatedQuery SQLExp)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CustomSQLCTEs -> HashMap TableAlias (InterpolatedQuery SQLExp)
getCustomSQLCTEs
customSQLToInnerCTEs :: CustomSQLCTEs -> [(S.TableAlias, S.InnerCTE)]
customSQLToInnerCTEs :: CustomSQLCTEs -> [(TableAlias, InnerCTE)]
customSQLToInnerCTEs =
((TableAlias, InterpolatedQuery SQLExp) -> (TableAlias, InnerCTE))
-> [(TableAlias, InterpolatedQuery SQLExp)]
-> [(TableAlias, InnerCTE)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((TableAlias -> TableAlias)
-> (InterpolatedQuery SQLExp -> InnerCTE)
-> (TableAlias, InterpolatedQuery SQLExp)
-> (TableAlias, InnerCTE)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap TableAlias -> TableAlias
forall a. IsIdentifier a => a -> TableAlias
S.toTableAlias InterpolatedQuery SQLExp -> InnerCTE
S.ICTEUnsafeRawSQL) ([(TableAlias, InterpolatedQuery SQLExp)]
-> [(TableAlias, InnerCTE)])
-> (CustomSQLCTEs -> [(TableAlias, InterpolatedQuery SQLExp)])
-> CustomSQLCTEs
-> [(TableAlias, InnerCTE)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap TableAlias (InterpolatedQuery SQLExp)
-> [(TableAlias, InterpolatedQuery SQLExp)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList (HashMap TableAlias (InterpolatedQuery SQLExp)
-> [(TableAlias, InterpolatedQuery SQLExp)])
-> (CustomSQLCTEs -> HashMap TableAlias (InterpolatedQuery SQLExp))
-> CustomSQLCTEs
-> [(TableAlias, InterpolatedQuery SQLExp)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CustomSQLCTEs -> HashMap TableAlias (InterpolatedQuery SQLExp)
getCustomSQLCTEs
toQuery :: S.SelectWithG S.TopLevelCTE -> Query
toQuery :: SelectWithG TopLevelCTE -> Query
toQuery = Builder -> Query
fromBuilder (Builder -> Query)
-> (SelectWithG TopLevelCTE -> Builder)
-> SelectWithG TopLevelCTE
-> Query
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SelectWithG TopLevelCTE -> Builder
forall a. ToSQL a => a -> Builder
toSQL (SelectWithG TopLevelCTE -> Builder)
-> (SelectWithG TopLevelCTE -> SelectWithG TopLevelCTE)
-> SelectWithG TopLevelCTE
-> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SelectWithG TopLevelCTE -> SelectWithG TopLevelCTE
renameIdentifiersSelectWithTopLevelCTE