-- | Postgres Translate Column
--
-- Translate column values to Postgres-specific SQL expressions.
module Hasura.Backends.Postgres.Translate.Column
  ( toTxtValue,
    toJSONableExp,
  )
where

import Hasura.Backends.Postgres.SQL.DML
import Hasura.Backends.Postgres.SQL.Types
import Hasura.Backends.Postgres.SQL.Value
import Hasura.Backends.Postgres.Types.Column
import Hasura.GraphQL.Schema.NamingCase
import Hasura.GraphQL.Schema.Options qualified as Options
import Hasura.Prelude
import Hasura.RQL.Types.Column
import Hasura.SQL.Backend

toTxtValue :: ColumnValue ('Postgres pgKind) -> SQLExp
toTxtValue :: ColumnValue ('Postgres pgKind) -> SQLExp
toTxtValue ColumnValue {ScalarValue ('Postgres pgKind)
ColumnType ('Postgres pgKind)
cvValue :: forall (b :: BackendType). ColumnValue b -> ScalarValue b
cvType :: forall (b :: BackendType). ColumnValue b -> ColumnType b
cvValue :: ScalarValue ('Postgres pgKind)
cvType :: ColumnType ('Postgres pgKind)
..} =
  PGScalarType -> SQLExp -> SQLExp
withScalarTypeAnn PGScalarType
ty (SQLExp -> SQLExp) -> (SQLExp -> SQLExp) -> SQLExp -> SQLExp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PGScalarType -> SQLExp -> SQLExp
withConstructorFn PGScalarType
ty (SQLExp -> SQLExp) -> SQLExp -> SQLExp
forall a b. (a -> b) -> a -> b
$ PGScalarValue -> SQLExp
txtEncoder ScalarValue ('Postgres pgKind)
PGScalarValue
cvValue
  where
    ty :: PGScalarType
ty = ColumnType ('Postgres pgKind) -> PGScalarType
forall (pgKind :: PostgresKind).
ColumnType ('Postgres pgKind) -> PGScalarType
unsafePGColumnToBackend ColumnType ('Postgres pgKind)
cvType

-- | Formats each columns to appropriate SQL expression
toJSONableExp :: Options.StringifyNumbers -> ColumnType ('Postgres pgKind) -> Bool -> Maybe NamingCase -> SQLExp -> SQLExp
toJSONableExp :: StringifyNumbers
-> ColumnType ('Postgres pgKind)
-> Bool
-> Maybe NamingCase
-> SQLExp
-> SQLExp
toJSONableExp StringifyNumbers
stringifyNum ColumnType ('Postgres pgKind)
colType Bool
asText Maybe NamingCase
tCase SQLExp
expression
  -- If it's a numeric column greater than a 32-bit integer, we have to stringify it as JSON spec doesn't support >32-bit integers
  | Bool
asText Bool -> Bool -> Bool
|| ((ScalarType ('Postgres pgKind) -> Bool)
-> ColumnType ('Postgres pgKind) -> Bool
forall (b :: BackendType).
(ScalarType b -> Bool) -> ColumnType b -> Bool
isScalarColumnWhere ScalarType ('Postgres pgKind) -> Bool
PGScalarType -> Bool
isBigNum ColumnType ('Postgres pgKind)
colType Bool -> Bool -> Bool
&& (case StringifyNumbers
stringifyNum of StringifyNumbers
Options.StringifyNumbers -> Bool
True; StringifyNumbers
Options.Don'tStringifyNumbers -> Bool
False)) =
    SQLExp
expression SQLExp -> TypeAnn -> SQLExp
`SETyAnn` TypeAnn
textTypeAnn
  -- If the column is either a `Geometry` or `Geography` then apply the `ST_AsGeoJSON` function to convert it into GeoJSON format
  | (ScalarType ('Postgres pgKind) -> Bool)
-> ColumnType ('Postgres pgKind) -> Bool
forall (b :: BackendType).
(ScalarType b -> Bool) -> ColumnType b -> Bool
isScalarColumnWhere ScalarType ('Postgres pgKind) -> Bool
PGScalarType -> Bool
isGeoType ColumnType ('Postgres pgKind)
colType =
    Text -> [SQLExp] -> Maybe OrderByExp -> SQLExp
SEFnApp
      Text
"ST_AsGeoJSON"
      [ SQLExp
expression,
        Text -> SQLExp
SEUnsafe Text
"15", -- max decimal digits
        Text -> SQLExp
SEUnsafe Text
"4" -- to print out crs
      ]
      Maybe OrderByExp
forall a. Maybe a
Nothing
      SQLExp -> TypeAnn -> SQLExp
`SETyAnn` TypeAnn
jsonTypeAnn
  | ColumnType ('Postgres pgKind) -> Bool
forall (b :: BackendType). ColumnType b -> Bool
isEnumColumn ColumnType ('Postgres pgKind)
colType Bool -> Bool -> Bool
&& (NamingCase -> Bool) -> Maybe NamingCase -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any NamingCase -> Bool
isGraphqlCase Maybe NamingCase
tCase = SQLExp -> SQLExp
applyUppercase SQLExp
expression
  | Bool
otherwise = SQLExp
expression