graphql-engine/server/src-lib/Hasura/Backends/Postgres/Translate/Select/Internal/Helpers.hs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

121 lines
4.2 KiB
Haskell
Raw Normal View History

-- | Stuff gutted from Translate.Select.
module Hasura.Backends.Postgres.Translate.Select.Internal.Helpers
( mkFirstElementExp,
mkLastElementExp,
cursorIdentifier,
startCursorIdentifier,
endCursorIdentifier,
hasNextPageIdentifier,
hasPreviousPageIdentifier,
pageInfoSelectAliasIdentifier,
cursorsSelectAliasIdentifier,
encodeBase64,
fromTableRowArgs,
selectFromToFromItem,
functionToIdentifier,
withJsonBuildObj,
withForceAggregation,
)
where
import Hasura.Backends.Postgres.SQL.DML qualified as S
import Hasura.Backends.Postgres.SQL.Types (Identifier (..), QualifiedFunction, qualifiedObjectToText, toIdentifier)
import Hasura.Backends.Postgres.Translate.Select.Internal.Aliases
import Hasura.Backends.Postgres.Types.Function
import Hasura.Prelude
import Hasura.RQL.IR
import Hasura.RQL.Types.Common (FieldName)
import Hasura.RQL.Types.Function
import Hasura.SQL.Backend
-- | First element extractor expression from given record set
-- For example:- To get first "id" column from given row set,
-- the function generates the SQL expression AS `(array_agg("id"))[1]`
mkFirstElementExp :: S.SQLExp -> S.SQLExp
mkFirstElementExp expIdentifier =
-- For Example
S.SEArrayIndex (S.SEFnApp "array_agg" [expIdentifier] Nothing) (S.intToSQLExp 1)
-- | Last element extractor expression from given record set.
-- For example:- To get first "id" column from given row set,
-- the function generates the SQL expression AS `(array_agg("id"))[array_length(array_agg("id"), 1)]`
mkLastElementExp :: S.SQLExp -> S.SQLExp
mkLastElementExp expIdentifier =
let arrayExp = S.SEFnApp "array_agg" [expIdentifier] Nothing
in S.SEArrayIndex arrayExp $
S.SEFnApp "array_length" [arrayExp, S.intToSQLExp 1] Nothing
cursorIdentifier :: Identifier
cursorIdentifier = Identifier "__cursor"
startCursorIdentifier :: Identifier
startCursorIdentifier = Identifier "__start_cursor"
endCursorIdentifier :: Identifier
endCursorIdentifier = Identifier "__end_cursor"
hasPreviousPageIdentifier :: Identifier
hasPreviousPageIdentifier = Identifier "__has_previous_page"
hasNextPageIdentifier :: Identifier
hasNextPageIdentifier = Identifier "__has_next_page"
pageInfoSelectAliasIdentifier :: Identifier
pageInfoSelectAliasIdentifier = Identifier "__page_info"
cursorsSelectAliasIdentifier :: Identifier
cursorsSelectAliasIdentifier = Identifier "__cursors_select"
encodeBase64 :: S.SQLExp -> S.SQLExp
encodeBase64 =
removeNewline . bytesToBase64Text . convertToBytes
where
convertToBytes e =
S.SEFnApp "convert_to" [e, S.SELit "UTF8"] Nothing
bytesToBase64Text e =
S.SEFnApp "encode" [e, S.SELit "base64"] Nothing
removeNewline e =
S.SEFnApp "regexp_replace" [e, S.SELit "\\n", S.SELit "", S.SELit "g"] Nothing
fromTableRowArgs ::
Identifier -> FunctionArgsExpG (ArgumentExp S.SQLExp) -> S.FunctionArgs
fromTableRowArgs prefix = toFunctionArgs . fmap toSQLExp
where
toFunctionArgs (FunctionArgsExp positional named) =
S.FunctionArgs positional named
toSQLExp =
onArgumentExp
(S.SERowIdentifier alias)
(S.mkQIdenExp alias . Identifier)
alias = mkBaseTableAlias prefix
selectFromToFromItem :: Identifier -> SelectFrom ('Postgres pgKind) -> S.FromItem
selectFromToFromItem pfx = \case
FromTable tn -> S.FISimple tn Nothing
FromIdentifier i -> S.FIIdentifier $ toIdentifier i
FromFunction qf args defListM ->
S.FIFunc $
S.FunctionExp qf (fromTableRowArgs pfx args) $
Just $ S.mkFunctionAlias (functionToIdentifier qf) defListM
-- | Converts a function name to an 'Identifier'.
--
-- If the schema name is public, it will just use its name, otherwise it will
-- prefix it by the schema name.
functionToIdentifier :: QualifiedFunction -> Identifier
functionToIdentifier = Identifier . qualifiedObjectToText
-- uses json_build_object to build a json object
withJsonBuildObj ::
FieldName -> [S.SQLExp] -> (S.Alias, S.SQLExp)
withJsonBuildObj parAls exps =
(S.toAlias parAls, jsonRow)
where
jsonRow = S.applyJsonBuildObj exps
-- | Forces aggregation
withForceAggregation :: S.TypeAnn -> S.SQLExp -> S.SQLExp
withForceAggregation tyAnn e =
-- bool_or to force aggregation
S.SEFnApp "coalesce" [e, S.SETyAnn (S.SEUnsafe "bool_or('true')") tyAnn] Nothing