-- | BigQuery DDL ComputedField
--
--  Implementation to build 'ComputedFieldInfo' for a BigQuery table from metadata
module Hasura.Backends.BigQuery.DDL.ComputedField
  ( buildComputedFieldInfo,
  )
where

import Control.Monad.Validate qualified as MV
import Data.HashMap.Strict qualified as HashMap
import Data.HashSet qualified as HS
import Data.Sequence qualified as Seq
import Data.Text.Extended
import Hasura.Backends.BigQuery.DDL.Source
import Hasura.Backends.BigQuery.Instances.Types ()
import Hasura.Backends.BigQuery.Meta
import Hasura.Backends.BigQuery.Types
import Hasura.Base.Error
import Hasura.Function.Cache
import Hasura.Prelude
import Hasura.RQL.Types.BackendType
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.ComputedField
import Hasura.Server.Utils
import Language.GraphQL.Draft.Syntax qualified as G

-- | Errors that occur when validating and building computed fields.
data ComputedFieldError
  = CFENoArgumentType FunctionArgName
  | CFENotTableValuedFunction
  | CFENoInputArguments
  | CFENoArgumentName
  | CFEInvalidArgumentName FunctionArgName
  | CFEInvalidColumnName TableName ColumnName
  | CFEReturnTableNotTracked TableName
  | CFENeedReturnTableName
  | CFENotRelevantReturnTable TableName
  | CFEReturnTableSchemaError ReturnTableSchemaError

-- | Errors that occur when validating returning table schema fields
data ReturnTableSchemaError
  = RTSENoFieldName
  | RTSENoType Text
  | RTSENotValidGraphQLName Text

-- | Generate read-able error message
showError :: FunctionName -> ComputedFieldError -> Text
showError :: FunctionName -> ComputedFieldError -> Text
showError FunctionName
functionName = \case
  CFENoArgumentType FunctionArgName
argName ->
    Text
"argument " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> FunctionArgName
argName FunctionArgName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" has no data type defined in the function " Text -> FunctionName -> Text
forall t. ToTxt t => Text -> t -> Text
<>> FunctionName
functionName
  ComputedFieldError
CFENotTableValuedFunction ->
    Text
prefixFunction Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is not a TABLE_VALUED_FUNCTION"
  ComputedFieldError
CFENoInputArguments ->
    Text
prefixFunction Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" has no input arguments defined"
  ComputedFieldError
CFENoArgumentName ->
    Text
prefixFunction Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" has at least one argument without name"
  CFEInvalidArgumentName FunctionArgName
argName ->
    Text
"the argument " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> FunctionArgName
argName FunctionArgName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" is not one of function " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> FunctionName
functionName FunctionName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" input arguments"
  CFEInvalidColumnName TableName
tableName ColumnName
columnName ->
    Text
"the column " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ColumnName
columnName ColumnName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" does not exist in table " Text -> TableName -> Text
forall t. ToTxt t => Text -> t -> Text
<>> TableName
tableName
  CFEReturnTableNotTracked TableName
tableName ->
    Text
prefixFunction Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" returning set of table " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> TableName
tableName TableName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" is not tracked"
  ComputedFieldError
CFENeedReturnTableName ->
    Text
prefixFunction Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" is not defined with 'RETURNS TABLE'. Expecting return table name."
  CFENotRelevantReturnTable TableName
tableName ->
    Text
"return table " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> TableName
tableName TableName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" is not required as the function " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> FunctionName
functionName FunctionName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" returns arbitrary column fields"
  CFEReturnTableSchemaError ReturnTableSchemaError
returnFieldsError -> ReturnTableSchemaError -> Text
showReturnFieldsError ReturnTableSchemaError
returnFieldsError
  where
    showReturnFieldsError :: ReturnTableSchemaError -> Text
    showReturnFieldsError :: ReturnTableSchemaError -> Text
showReturnFieldsError = \case
      ReturnTableSchemaError
RTSENoFieldName -> Text
"at least one field name is absent"
      RTSENoType Text
fieldName -> Text
"fieldName " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
fieldName Text -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" has not type information"
      RTSENotValidGraphQLName Text
fieldName -> Text
"fieldName " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
fieldName Text -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" is not a valid GraphQL name"

    prefixFunction :: Text
    prefixFunction :: Text
prefixFunction = Text
"function " Text -> FunctionName -> Text
forall t. ToTxt t => Text -> t -> Text
<>> FunctionName
functionName

-- | Validate computed field metadata and build field information
buildComputedFieldInfo ::
  forall m.
  (MonadError QErr m) =>
  HashSet TableName ->
  TableName ->
  HashSet ColumnName ->
  ComputedFieldName ->
  ComputedFieldDefinition ->
  RestRoutine ->
  Comment ->
  m (ComputedFieldInfo 'BigQuery)
buildComputedFieldInfo :: forall (m :: * -> *).
MonadError QErr m =>
HashSet TableName
-> TableName
-> HashSet ColumnName
-> ComputedFieldName
-> ComputedFieldDefinition
-> RestRoutine
-> Comment
-> m (ComputedFieldInfo 'BigQuery)
buildComputedFieldInfo HashSet TableName
trackedTables TableName
table HashSet ColumnName
tableColumns ComputedFieldName
computedField ComputedFieldDefinition {Maybe TableName
HashMap FunctionArgName ColumnName
FunctionName
_bqcfdFunction :: FunctionName
_bqcfdReturnTable :: Maybe TableName
_bqcfdArgumentMapping :: HashMap FunctionArgName ColumnName
$sel:_bqcfdFunction:ComputedFieldDefinition :: ComputedFieldDefinition -> FunctionName
$sel:_bqcfdReturnTable:ComputedFieldDefinition :: ComputedFieldDefinition -> Maybe TableName
$sel:_bqcfdArgumentMapping:ComputedFieldDefinition :: ComputedFieldDefinition -> HashMap FunctionArgName ColumnName
..} RestRoutine
restRoutine Comment
comment = do
  ([ComputedFieldError] -> m (ComputedFieldInfo 'BigQuery))
-> (ComputedFieldInfo 'BigQuery -> m (ComputedFieldInfo 'BigQuery))
-> Either [ComputedFieldError] (ComputedFieldInfo 'BigQuery)
-> m (ComputedFieldInfo 'BigQuery)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Code -> Text -> m (ComputedFieldInfo 'BigQuery)
forall (m :: * -> *) a. QErrM m => Code -> Text -> m a
throw400 Code
NotSupported (Text -> m (ComputedFieldInfo 'BigQuery))
-> ([ComputedFieldError] -> Text)
-> [ComputedFieldError]
-> m (ComputedFieldInfo 'BigQuery)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ComputedFieldError] -> Text
showErrors) ComputedFieldInfo 'BigQuery -> m (ComputedFieldInfo 'BigQuery)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either [ComputedFieldError] (ComputedFieldInfo 'BigQuery)
 -> m (ComputedFieldInfo 'BigQuery))
-> m (Either [ComputedFieldError] (ComputedFieldInfo 'BigQuery))
-> m (ComputedFieldInfo 'BigQuery)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ValidateT [ComputedFieldError] m (ComputedFieldInfo 'BigQuery)
-> m (Either [ComputedFieldError] (ComputedFieldInfo 'BigQuery))
forall e (m :: * -> *) a.
Functor m =>
ValidateT e m a -> m (Either e a)
MV.runValidateT ValidateT [ComputedFieldError] m (ComputedFieldInfo 'BigQuery)
forall (n :: * -> *).
MonadValidate [ComputedFieldError] n =>
n (ComputedFieldInfo 'BigQuery)
mkComputedFieldInfo
  where
    mkComputedFieldInfo ::
      forall n.
      (MV.MonadValidate [ComputedFieldError] n) =>
      n (ComputedFieldInfo 'BigQuery)
    mkComputedFieldInfo :: forall (n :: * -> *).
MonadValidate [ComputedFieldError] n =>
n (ComputedFieldInfo 'BigQuery)
mkComputedFieldInfo = do
      -- Currently, we only support functions returning set of rows in computed field.
      -- Support for scalar computed fields is being tracked at https://github.com/hasura/graphql-engine/issues/8521.
      Bool -> n () -> n ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (RestRoutine -> RestRoutineType
routineType RestRoutine
restRoutine RestRoutineType -> RestRoutineType -> Bool
forall a. Eq a => a -> a -> Bool
== RestRoutineType
TABLE_VALUED_FUNCTION) (n () -> n ()) -> n () -> n ()
forall a b. (a -> b) -> a -> b
$ [ComputedFieldError] -> n ()
forall e (m :: * -> *). MonadValidate e m => e -> m ()
MV.dispute ([ComputedFieldError] -> n ()) -> [ComputedFieldError] -> n ()
forall a b. (a -> b) -> a -> b
$ ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ComputedFieldError
CFENotTableValuedFunction
      [RestArgument]
restArguments <- Maybe [RestArgument] -> n [RestArgument] -> n [RestArgument]
forall (m :: * -> *) a. Applicative m => Maybe a -> m a -> m a
onNothing (RestRoutine -> Maybe [RestArgument]
arguments RestRoutine
restRoutine) (n [RestArgument] -> n [RestArgument])
-> n [RestArgument] -> n [RestArgument]
forall a b. (a -> b) -> a -> b
$ [ComputedFieldError] -> n [RestArgument]
forall a. [ComputedFieldError] -> n a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
MV.refute (ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ComputedFieldError
CFENoInputArguments)
      Seq FunctionArgument
inputArguments <- [FunctionArgument] -> Seq FunctionArgument
forall a. [a] -> Seq a
Seq.fromList ([FunctionArgument] -> Seq FunctionArgument)
-> n [FunctionArgument] -> n (Seq FunctionArgument)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [RestArgument]
-> (RestArgument -> n FunctionArgument) -> n [FunctionArgument]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for [RestArgument]
restArguments RestArgument -> n FunctionArgument
resolveInputArgument
      [(FunctionArgName, ColumnName)]
-> ((FunctionArgName, ColumnName) -> n ()) -> n ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (HashMap FunctionArgName ColumnName
-> [(FunctionArgName, ColumnName)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList HashMap FunctionArgName ColumnName
_bqcfdArgumentMapping) (Seq FunctionArgument -> (FunctionArgName, ColumnName) -> n ()
validateArgumentMapping Seq FunctionArgument
inputArguments)
      let fieldFunction :: ComputedFieldFunction 'BigQuery
fieldFunction = FunctionName 'BigQuery
-> Seq (FunctionArgument 'BigQuery)
-> ComputedFieldImplicitArguments 'BigQuery
-> Maybe PGDescription
-> ComputedFieldFunction 'BigQuery
forall (b :: BackendType).
FunctionName b
-> Seq (FunctionArgument b)
-> ComputedFieldImplicitArguments b
-> Maybe PGDescription
-> ComputedFieldFunction b
ComputedFieldFunction FunctionName 'BigQuery
FunctionName
_bqcfdFunction Seq (FunctionArgument 'BigQuery)
Seq FunctionArgument
inputArguments HashMap FunctionArgName ColumnName
ComputedFieldImplicitArguments 'BigQuery
_bqcfdArgumentMapping Maybe PGDescription
forall a. Maybe a
Nothing
      ComputedFieldReturn
fieldReturn <- Maybe RestStandardSqlTableType
-> Maybe TableName -> n ComputedFieldReturn
resolveFunctionReturning (RestRoutine -> Maybe RestStandardSqlTableType
returnTableType RestRoutine
restRoutine) Maybe TableName
_bqcfdReturnTable
      ComputedFieldInfo 'BigQuery -> n (ComputedFieldInfo 'BigQuery)
forall a. a -> n a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ComputedFieldInfo 'BigQuery -> n (ComputedFieldInfo 'BigQuery))
-> ComputedFieldInfo 'BigQuery -> n (ComputedFieldInfo 'BigQuery)
forall a b. (a -> b) -> a -> b
$ forall (b :: BackendType).
XComputedField b
-> ComputedFieldName
-> ComputedFieldFunction b
-> ComputedFieldReturn b
-> Maybe Text
-> ComputedFieldInfo b
ComputedFieldInfo @'BigQuery () ComputedFieldName
computedField ComputedFieldFunction 'BigQuery
fieldFunction ComputedFieldReturn 'BigQuery
ComputedFieldReturn
fieldReturn (Maybe Text -> ComputedFieldInfo 'BigQuery)
-> Maybe Text -> ComputedFieldInfo 'BigQuery
forall a b. (a -> b) -> a -> b
$ Comment -> Maybe Text
commentToMaybeText Comment
comment
      where
        resolveInputArgument :: RestArgument -> n FunctionArgument
        resolveInputArgument :: RestArgument -> n FunctionArgument
resolveInputArgument RestArgument {Maybe Text
Maybe RestType
_raName :: Maybe Text
_raDataType :: Maybe RestType
$sel:_raName:RestArgument :: RestArgument -> Maybe Text
$sel:_raDataType:RestArgument :: RestArgument -> Maybe RestType
..} = do
          case Maybe Text
_raName of
            Maybe Text
Nothing -> [ComputedFieldError] -> n FunctionArgument
forall a. [ComputedFieldError] -> n a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
MV.refute ([ComputedFieldError] -> n FunctionArgument)
-> [ComputedFieldError] -> n FunctionArgument
forall a b. (a -> b) -> a -> b
$ ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ComputedFieldError
CFENoArgumentName
            Just Text
name -> do
              let argName :: FunctionArgName
argName = Text -> FunctionArgName
FunctionArgName Text
name
              RestType
restType <- Maybe RestType -> n RestType -> n RestType
forall (m :: * -> *) a. Applicative m => Maybe a -> m a -> m a
onNothing Maybe RestType
_raDataType (n RestType -> n RestType) -> n RestType -> n RestType
forall a b. (a -> b) -> a -> b
$ [ComputedFieldError] -> n RestType
forall a. [ComputedFieldError] -> n a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
MV.refute ([ComputedFieldError] -> n RestType)
-> [ComputedFieldError] -> n RestType
forall a b. (a -> b) -> a -> b
$ ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ComputedFieldError -> [ComputedFieldError])
-> ComputedFieldError -> [ComputedFieldError]
forall a b. (a -> b) -> a -> b
$ FunctionArgName -> ComputedFieldError
CFENoArgumentType FunctionArgName
argName
              FunctionArgument -> n FunctionArgument
forall a. a -> n a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FunctionArgument -> n FunctionArgument)
-> FunctionArgument -> n FunctionArgument
forall a b. (a -> b) -> a -> b
$ FunctionArgName -> ScalarType -> FunctionArgument
FunctionArgument FunctionArgName
argName (RestType -> ScalarType
restTypeToScalarType RestType
restType)

        validateArgumentMapping :: Seq FunctionArgument -> (FunctionArgName, ColumnName) -> n ()
        validateArgumentMapping :: Seq FunctionArgument -> (FunctionArgName, ColumnName) -> n ()
validateArgumentMapping Seq FunctionArgument
args (FunctionArgName
functionArgName, ColumnName
columnName) = do
          -- Check if argument is one of function input arguments
          Bool -> n () -> n ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (FunctionArgName
functionArgName FunctionArgName -> Seq FunctionArgName -> Bool
forall a. Eq a => a -> Seq a -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` (FunctionArgument -> FunctionArgName
_faName (FunctionArgument -> FunctionArgName)
-> Seq FunctionArgument -> Seq FunctionArgName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Seq FunctionArgument
args)) (n () -> n ()) -> n () -> n ()
forall a b. (a -> b) -> a -> b
$ [ComputedFieldError] -> n ()
forall e (m :: * -> *). MonadValidate e m => e -> m ()
MV.dispute ([ComputedFieldError] -> n ()) -> [ComputedFieldError] -> n ()
forall a b. (a -> b) -> a -> b
$ ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ComputedFieldError -> [ComputedFieldError])
-> ComputedFieldError -> [ComputedFieldError]
forall a b. (a -> b) -> a -> b
$ FunctionArgName -> ComputedFieldError
CFEInvalidArgumentName FunctionArgName
functionArgName
          -- Check if column name exist in list of table columns
          Bool -> n () -> n ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (ColumnName
columnName ColumnName -> HashSet ColumnName -> Bool
forall a. (Eq a, Hashable a) => a -> HashSet a -> Bool
`HS.member` HashSet ColumnName
tableColumns) (n () -> n ()) -> n () -> n ()
forall a b. (a -> b) -> a -> b
$ [ComputedFieldError] -> n ()
forall e (m :: * -> *). MonadValidate e m => e -> m ()
MV.dispute ([ComputedFieldError] -> n ()) -> [ComputedFieldError] -> n ()
forall a b. (a -> b) -> a -> b
$ ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ComputedFieldError -> [ComputedFieldError])
-> ComputedFieldError -> [ComputedFieldError]
forall a b. (a -> b) -> a -> b
$ TableName -> ColumnName -> ComputedFieldError
CFEInvalidColumnName TableName
table ColumnName
columnName

        resolveReturnSqlFields :: [RestStandardSqlField] -> n [(ColumnName, G.Name, ScalarType)]
        resolveReturnSqlFields :: [RestStandardSqlField] -> n [(ColumnName, Name, ScalarType)]
resolveReturnSqlFields [RestStandardSqlField]
fields =
          [RestStandardSqlField]
-> (RestStandardSqlField -> n (ColumnName, Name, ScalarType))
-> n [(ColumnName, Name, ScalarType)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [RestStandardSqlField]
fields ((RestStandardSqlField -> n (ColumnName, Name, ScalarType))
 -> n [(ColumnName, Name, ScalarType)])
-> (RestStandardSqlField -> n (ColumnName, Name, ScalarType))
-> n [(ColumnName, Name, ScalarType)]
forall a b. (a -> b) -> a -> b
$ \RestStandardSqlField {Maybe Text
Maybe RestType
_rssfName :: Maybe Text
_rssType :: Maybe RestType
$sel:_rssfName:RestStandardSqlField :: RestStandardSqlField -> Maybe Text
$sel:_rssType:RestStandardSqlField :: RestStandardSqlField -> Maybe RestType
..} -> do
            Text
fieldName <- Maybe Text -> n Text -> n Text
forall (m :: * -> *) a. Applicative m => Maybe a -> m a -> m a
onNothing Maybe Text
_rssfName (n Text -> n Text) -> n Text -> n Text
forall a b. (a -> b) -> a -> b
$ [ComputedFieldError] -> n Text
forall a. [ComputedFieldError] -> n a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
MV.refute ([ComputedFieldError] -> n Text) -> [ComputedFieldError] -> n Text
forall a b. (a -> b) -> a -> b
$ ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ComputedFieldError -> [ComputedFieldError])
-> ComputedFieldError -> [ComputedFieldError]
forall a b. (a -> b) -> a -> b
$ ReturnTableSchemaError -> ComputedFieldError
CFEReturnTableSchemaError ReturnTableSchemaError
RTSENoFieldName
            Name
fieldGraphQLName <- Maybe Name -> n Name -> n Name
forall (m :: * -> *) a. Applicative m => Maybe a -> m a -> m a
onNothing (Text -> Maybe Name
G.mkName Text
fieldName) (n Name -> n Name) -> n Name -> n Name
forall a b. (a -> b) -> a -> b
$ [ComputedFieldError] -> n Name
forall a. [ComputedFieldError] -> n a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
MV.refute ([ComputedFieldError] -> n Name) -> [ComputedFieldError] -> n Name
forall a b. (a -> b) -> a -> b
$ ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ComputedFieldError -> [ComputedFieldError])
-> ComputedFieldError -> [ComputedFieldError]
forall a b. (a -> b) -> a -> b
$ ReturnTableSchemaError -> ComputedFieldError
CFEReturnTableSchemaError (ReturnTableSchemaError -> ComputedFieldError)
-> ReturnTableSchemaError -> ComputedFieldError
forall a b. (a -> b) -> a -> b
$ Text -> ReturnTableSchemaError
RTSENotValidGraphQLName Text
fieldName
            RestType
type' <- Maybe RestType -> n RestType -> n RestType
forall (m :: * -> *) a. Applicative m => Maybe a -> m a -> m a
onNothing Maybe RestType
_rssType (n RestType -> n RestType) -> n RestType -> n RestType
forall a b. (a -> b) -> a -> b
$ [ComputedFieldError] -> n RestType
forall a. [ComputedFieldError] -> n a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
MV.refute ([ComputedFieldError] -> n RestType)
-> [ComputedFieldError] -> n RestType
forall a b. (a -> b) -> a -> b
$ ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ComputedFieldError -> [ComputedFieldError])
-> ComputedFieldError -> [ComputedFieldError]
forall a b. (a -> b) -> a -> b
$ ReturnTableSchemaError -> ComputedFieldError
CFEReturnTableSchemaError (ReturnTableSchemaError -> ComputedFieldError)
-> ReturnTableSchemaError -> ComputedFieldError
forall a b. (a -> b) -> a -> b
$ Text -> ReturnTableSchemaError
RTSENoType Text
fieldName
            (ColumnName, Name, ScalarType) -> n (ColumnName, Name, ScalarType)
forall a. a -> n a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> ColumnName
ColumnName Text
fieldName, Name
fieldGraphQLName, RestType -> ScalarType
restTypeToScalarType RestType
type')

        resolveFunctionReturning ::
          Maybe RestStandardSqlTableType ->
          Maybe TableName ->
          n ComputedFieldReturn
        resolveFunctionReturning :: Maybe RestStandardSqlTableType
-> Maybe TableName -> n ComputedFieldReturn
resolveFunctionReturning Maybe RestStandardSqlTableType
Nothing Maybe TableName
Nothing =
          [ComputedFieldError] -> n ComputedFieldReturn
forall a. [ComputedFieldError] -> n a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
MV.refute ([ComputedFieldError] -> n ComputedFieldReturn)
-> [ComputedFieldError] -> n ComputedFieldReturn
forall a b. (a -> b) -> a -> b
$ ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ComputedFieldError
CFENeedReturnTableName
        resolveFunctionReturning Maybe RestStandardSqlTableType
Nothing (Just TableName
returnTable) =
          -- Function does not return schema of a table. The return table type should be inferred
          -- from function definition. The user provides returning table name through metadata.
          -- Check if returning table is tracked.
          if TableName
returnTable TableName -> HashSet TableName -> Bool
forall a. (Eq a, Hashable a) => a -> HashSet a -> Bool
`HS.member` HashSet TableName
trackedTables
            then ComputedFieldReturn -> n ComputedFieldReturn
forall a. a -> n a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TableName -> ComputedFieldReturn
ReturnExistingTable TableName
returnTable)
            else [ComputedFieldError] -> n ComputedFieldReturn
forall a. [ComputedFieldError] -> n a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
MV.refute ([ComputedFieldError] -> n ComputedFieldReturn)
-> [ComputedFieldError] -> n ComputedFieldReturn
forall a b. (a -> b) -> a -> b
$ ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ComputedFieldError -> [ComputedFieldError])
-> ComputedFieldError -> [ComputedFieldError]
forall a b. (a -> b) -> a -> b
$ TableName -> ComputedFieldError
CFEReturnTableNotTracked TableName
returnTable
        resolveFunctionReturning (Just RestStandardSqlTableType
returnFields) Maybe TableName
Nothing =
          -- Return table is not specified and the function returns a schema of a table,
          -- specified as a list of column names and their type.
          [(ColumnName, Name, ScalarType)] -> ComputedFieldReturn
ReturnTableSchema ([(ColumnName, Name, ScalarType)] -> ComputedFieldReturn)
-> n [(ColumnName, Name, ScalarType)] -> n ComputedFieldReturn
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [RestStandardSqlField] -> n [(ColumnName, Name, ScalarType)]
resolveReturnSqlFields (RestStandardSqlTableType -> [RestStandardSqlField]
_rrttColumns RestStandardSqlTableType
returnFields)
        resolveFunctionReturning (Just RestStandardSqlTableType
_) (Just TableName
returnTable) =
          [ComputedFieldError] -> n ComputedFieldReturn
forall a. [ComputedFieldError] -> n a
forall e (m :: * -> *) a. MonadValidate e m => e -> m a
MV.refute ([ComputedFieldError] -> n ComputedFieldReturn)
-> [ComputedFieldError] -> n ComputedFieldReturn
forall a b. (a -> b) -> a -> b
$ ComputedFieldError -> [ComputedFieldError]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ComputedFieldError -> [ComputedFieldError])
-> ComputedFieldError -> [ComputedFieldError]
forall a b. (a -> b) -> a -> b
$ TableName -> ComputedFieldError
CFENotRelevantReturnTable TableName
returnTable

    showErrors :: [ComputedFieldError] -> Text
    showErrors :: [ComputedFieldError] -> Text
showErrors [ComputedFieldError]
allErrors =
      Text
"the computed field "
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ComputedFieldName
computedField
        ComputedFieldName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" cannot be added to table "
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> TableName
table
        TableName -> Text -> Text
forall t. ToTxt t => t -> Text -> Text
<<> Text
" "
        Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
reasonMessage
      where
        reasonMessage :: Text
reasonMessage = [ComputedFieldError] -> (ComputedFieldError -> Text) -> Text
forall a. [a] -> (a -> Text) -> Text
makeReasonMessage [ComputedFieldError]
allErrors (FunctionName -> ComputedFieldError -> Text
showError FunctionName
_bqcfdFunction)