{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE TemplateHaskell #-}

-- | This module provides common building blocks for composing Schema Parsers
-- used in the schema of Update Mutations.
module Hasura.GraphQL.Schema.Update
  ( UpdateOperator (..),
    updateOperator,
    buildUpdateOperators,
    presetColumns,
    setOp,
    incOp,
  )
where

import Data.Has (Has (getter))
import Data.HashMap.Strict.Extended qualified as HashMap
import Data.List.NonEmpty qualified as NE
import Data.Text.Casing (GQLNameIdentifier, fromAutogeneratedName)
import Data.Text.Extended ((<>>))
import Hasura.Base.ToErrorValue
import Hasura.GraphQL.Schema.Backend (BackendSchema (..), MonadBuildSchema, columnParser)
import Hasura.GraphQL.Schema.Common
import Hasura.GraphQL.Schema.Parser qualified as P
import Hasura.GraphQL.Schema.Table (getTableIdentifierName, tableUpdateColumns)
import Hasura.GraphQL.Schema.Typename
import Hasura.Prelude
import Hasura.RQL.IR.Value
import Hasura.RQL.Types.Backend (Backend (..))
import Hasura.RQL.Types.Column (ColumnInfo (..), isNumCol)
import Hasura.RQL.Types.Source
import Hasura.RQL.Types.SourceCustomization
import Hasura.Table.Cache
import Language.GraphQL.Draft.Syntax (Description (..), Nullability (..), litName)

-- | @UpdateOperator b m n op@ represents one single update operator for a
-- backend @b@.
--
-- The type variable @op@ is the backend-specific data type that represents
-- update operators, typically in the form of a sum-type with an
-- @UnpreparedValue b@ in each constructor.
--
-- The @UpdateOperator b m n@ is a @Functor@. There exist building blocks of
-- common update operators (such as 'setOp', etc.) which have @op ~
-- UnpreparedValue b@. The Functor instance lets you wrap the generic update
-- operators in backend-specific tags.
data UpdateOperator b r m n op = UpdateOperator
  { forall (b :: BackendType) r (m :: * -> *) (n :: * -> *) op.
UpdateOperator b r m n op -> ColumnInfo b -> Bool
updateOperatorApplicableColumn :: ColumnInfo b -> Bool,
    forall (b :: BackendType) r (m :: * -> *) (n :: * -> *) op.
UpdateOperator b r m n op
-> GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT r m (InputFieldsParser n (HashMap (Column b) op))
updateOperatorParser ::
      GQLNameIdentifier ->
      TableName b ->
      NonEmpty (ColumnInfo b) ->
      SchemaT r m (P.InputFieldsParser n (HashMap (Column b) op))
  }
  deriving ((forall a b.
 (a -> b) -> UpdateOperator b r m n a -> UpdateOperator b r m n b)
-> (forall a b.
    a -> UpdateOperator b r m n b -> UpdateOperator b r m n a)
-> Functor (UpdateOperator b r m n)
forall a b.
a -> UpdateOperator b r m n b -> UpdateOperator b r m n a
forall a b.
(a -> b) -> UpdateOperator b r m n a -> UpdateOperator b r m n b
forall (b :: BackendType) r (m :: * -> *) (n :: * -> *) a b.
(Functor m, Functor n) =>
a -> UpdateOperator b r m n b -> UpdateOperator b r m n a
forall (b :: BackendType) r (m :: * -> *) (n :: * -> *) a b.
(Functor m, Functor n) =>
(a -> b) -> UpdateOperator b r m n a -> UpdateOperator b r m n b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall (b :: BackendType) r (m :: * -> *) (n :: * -> *) a b.
(Functor m, Functor n) =>
(a -> b) -> UpdateOperator b r m n a -> UpdateOperator b r m n b
fmap :: forall a b.
(a -> b) -> UpdateOperator b r m n a -> UpdateOperator b r m n b
$c<$ :: forall (b :: BackendType) r (m :: * -> *) (n :: * -> *) a b.
(Functor m, Functor n) =>
a -> UpdateOperator b r m n b -> UpdateOperator b r m n a
<$ :: forall a b.
a -> UpdateOperator b r m n b -> UpdateOperator b r m n a
Functor)

-- | The top-level component for building update operators parsers.
--
-- * It implements the @preset@ functionality from Update Permissions (see
--   <https://hasura.io/docs/latest/graphql/core/auth/authorization/permission-rules.html#column-presets
--   Permissions user docs>). Use the 'presetColumns' function to extract those from the update permissions.
-- * It validates that that the update fields parsed are sound when taken as a
--   whole, i.e. that some changes are actually specified (either in the
--   mutation query text or in update preset columns) and that each column is
--   only used in one operator.
buildUpdateOperators ::
  forall b r m n op.
  (MonadBuildSchema b r m n) =>
  -- | Columns with @preset@ expressions
  (HashMap (Column b) op) ->
  -- | Update operators to include in the Schema
  [UpdateOperator b r m n op] ->
  TableInfo b ->
  SchemaT r m (P.InputFieldsParser n (HashMap (Column b) op))
buildUpdateOperators :: forall (b :: BackendType) r (m :: * -> *) (n :: * -> *) op.
MonadBuildSchema b r m n =>
HashMap (Column b) op
-> [UpdateOperator b r m n op]
-> TableInfo b
-> SchemaT r m (InputFieldsParser n (HashMap (Column b) op))
buildUpdateOperators HashMap (Column b) op
presetCols [UpdateOperator b r m n op]
ops TableInfo b
tableInfo = do
  InputFieldsParser n [HashMap (Column b) op]
parsers :: P.InputFieldsParser n [HashMap (Column b) op] <-
    [InputFieldsParser n (HashMap (Column b) op)]
-> InputFieldsParser n [HashMap (Column b) op]
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
forall (f :: * -> *) a. Applicative f => [f a] -> f [a]
sequenceA ([InputFieldsParser n (HashMap (Column b) op)]
 -> InputFieldsParser n [HashMap (Column b) op])
-> ([Maybe (InputFieldsParser n (HashMap (Column b) op))]
    -> [InputFieldsParser n (HashMap (Column b) op)])
-> [Maybe (InputFieldsParser n (HashMap (Column b) op))]
-> InputFieldsParser n [HashMap (Column b) op]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe (InputFieldsParser n (HashMap (Column b) op))]
-> [InputFieldsParser n (HashMap (Column b) op)]
forall a. [Maybe a] -> [a]
forall (f :: * -> *) a. Filterable f => f (Maybe a) -> f a
catMaybes ([Maybe (InputFieldsParser n (HashMap (Column b) op))]
 -> InputFieldsParser n [HashMap (Column b) op])
-> SchemaT
     r m [Maybe (InputFieldsParser n (HashMap (Column b) op))]
-> SchemaT r m (InputFieldsParser n [HashMap (Column b) op])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (UpdateOperator b r m n op
 -> SchemaT
      r m (Maybe (InputFieldsParser n (HashMap (Column b) op))))
-> [UpdateOperator b r m n op]
-> SchemaT
     r m [Maybe (InputFieldsParser n (HashMap (Column b) op))]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse (TableInfo b
-> UpdateOperator b r m n op
-> SchemaT
     r m (Maybe (InputFieldsParser n (HashMap (Column b) op)))
forall (b :: BackendType) r (m :: * -> *) (n :: * -> *) op.
MonadBuildSchema b r m n =>
TableInfo b
-> UpdateOperator b r m n op
-> SchemaT
     r m (Maybe (InputFieldsParser n (HashMap (Column b) op)))
runUpdateOperator TableInfo b
tableInfo) [UpdateOperator b r m n op]
ops
  pure
    $ InputFieldsParser n [HashMap (Column b) op]
parsers
    InputFieldsParser n [HashMap (Column b) op]
-> ([HashMap (Column b) op] -> n (HashMap (Column b) op))
-> InputFieldsParser n (HashMap (Column b) op)
forall (m :: * -> *) origin a b.
Monad m =>
InputFieldsParser origin m a
-> (a -> m b) -> InputFieldsParser origin m b
`P.bindFields` ( \[HashMap (Column b) op]
opExps -> do
                       let withPreset :: [HashMap (Column b) op]
withPreset = HashMap (Column b) op
presetCols HashMap (Column b) op
-> [HashMap (Column b) op] -> [HashMap (Column b) op]
forall a. a -> [a] -> [a]
: [HashMap (Column b) op]
opExps
                       forall (b :: BackendType) (m :: * -> *) t.
(Backend b, MonadParse m) =>
[HashMap (Column b) t] -> m (HashMap (Column b) t)
mergeDisjoint @b [HashMap (Column b) op]
withPreset
                   )

-- | The columns that have 'preset' definitions applied to them. (see
-- <https://hasura.io/docs/latest/graphql/core/auth/authorization/permission-rules.html#column-presets
-- Permissions user docs>)
presetColumns :: UpdPermInfo b -> HashMap (Column b) (UnpreparedValue b)
presetColumns :: forall (b :: BackendType).
UpdPermInfo b -> HashMap (Column b) (UnpreparedValue b)
presetColumns = (PartialSQLExp b -> UnpreparedValue b)
-> HashMap (Column b) (PartialSQLExp b)
-> HashMap (Column b) (UnpreparedValue b)
forall a b.
(a -> b) -> HashMap (Column b) a -> HashMap (Column b) b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap PartialSQLExp b -> UnpreparedValue b
forall (b :: BackendType). PartialSQLExp b -> UnpreparedValue b
partialSQLExpToUnpreparedValue (HashMap (Column b) (PartialSQLExp b)
 -> HashMap (Column b) (UnpreparedValue b))
-> (UpdPermInfo b -> HashMap (Column b) (PartialSQLExp b))
-> UpdPermInfo b
-> HashMap (Column b) (UnpreparedValue b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UpdPermInfo b -> HashMap (Column b) (PartialSQLExp b)
forall (b :: BackendType). UpdPermInfo b -> PreSetColsPartial b
upiSet

-- | Produce an InputFieldsParser from an UpdateOperator, but only if the operator
-- applies to the table (i.e., it admits a non-empty column set).
runUpdateOperator ::
  forall b r m n op.
  (MonadBuildSchema b r m n) =>
  TableInfo b ->
  UpdateOperator b r m n op ->
  SchemaT
    r
    m
    ( Maybe
        ( P.InputFieldsParser
            n
            (HashMap (Column b) op)
        )
    )
runUpdateOperator :: forall (b :: BackendType) r (m :: * -> *) (n :: * -> *) op.
MonadBuildSchema b r m n =>
TableInfo b
-> UpdateOperator b r m n op
-> SchemaT
     r m (Maybe (InputFieldsParser n (HashMap (Column b) op)))
runUpdateOperator TableInfo b
tableInfo UpdateOperator {GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT r m (InputFieldsParser n (HashMap (Column b) op))
ColumnInfo b -> Bool
updateOperatorApplicableColumn :: forall (b :: BackendType) r (m :: * -> *) (n :: * -> *) op.
UpdateOperator b r m n op -> ColumnInfo b -> Bool
updateOperatorParser :: forall (b :: BackendType) r (m :: * -> *) (n :: * -> *) op.
UpdateOperator b r m n op
-> GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT r m (InputFieldsParser n (HashMap (Column b) op))
updateOperatorApplicableColumn :: ColumnInfo b -> Bool
updateOperatorParser :: GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT r m (InputFieldsParser n (HashMap (Column b) op))
..} = do
  let tableName :: TableName b
tableName = TableInfo b -> TableName b
forall (b :: BackendType). TableInfo b -> TableName b
tableInfoName TableInfo b
tableInfo
  GQLNameIdentifier
tableGQLName <- TableInfo b -> SchemaT r m GQLNameIdentifier
forall (b :: BackendType) (m :: * -> *).
(Backend b, MonadError QErr m) =>
TableInfo b -> m GQLNameIdentifier
getTableIdentifierName TableInfo b
tableInfo
  RoleName
roleName <- (SchemaContext -> RoleName) -> SchemaT r m RoleName
forall r (m :: * -> *) a b.
(MonadReader r m, Has a r) =>
(a -> b) -> m b
retrieve SchemaContext -> RoleName
scRole
  let columns :: [ColumnInfo b]
columns = RoleName -> TableInfo b -> [ColumnInfo b]
forall (b :: BackendType).
Backend b =>
RoleName -> TableInfo b -> [ColumnInfo b]
tableUpdateColumns RoleName
roleName TableInfo b
tableInfo

  let Maybe (NonEmpty (ColumnInfo b))
applicableCols :: Maybe (NonEmpty (ColumnInfo b)) =
        [ColumnInfo b] -> Maybe (NonEmpty (ColumnInfo b))
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty ([ColumnInfo b] -> Maybe (NonEmpty (ColumnInfo b)))
-> ([ColumnInfo b] -> [ColumnInfo b])
-> [ColumnInfo b]
-> Maybe (NonEmpty (ColumnInfo b))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ColumnInfo b -> Bool) -> [ColumnInfo b] -> [ColumnInfo b]
forall a. (a -> Bool) -> [a] -> [a]
filter ColumnInfo b -> Bool
updateOperatorApplicableColumn ([ColumnInfo b] -> Maybe (NonEmpty (ColumnInfo b)))
-> [ColumnInfo b] -> Maybe (NonEmpty (ColumnInfo b))
forall a b. (a -> b) -> a -> b
$ [ColumnInfo b]
columns

  (Maybe (SchemaT r m a) -> SchemaT r m (Maybe a)
forall {a}. Maybe (SchemaT r m a) -> SchemaT r m (Maybe a)
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
forall (f :: * -> *) a. Applicative f => Maybe (f a) -> f (Maybe a)
sequenceA :: Maybe (SchemaT r m a) -> SchemaT r m (Maybe a))
    (Maybe (NonEmpty (ColumnInfo b))
applicableCols Maybe (NonEmpty (ColumnInfo b))
-> (NonEmpty (ColumnInfo b)
    -> SchemaT r m (InputFieldsParser n (HashMap (Column b) op)))
-> Maybe
     (SchemaT r m (InputFieldsParser n (HashMap (Column b) op)))
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT r m (InputFieldsParser n (HashMap (Column b) op))
updateOperatorParser GQLNameIdentifier
tableGQLName TableName b
tableName)

-- | Merge the results of parsed update operators. Throws an error if the same
-- column has been specified in multiple operators.
mergeDisjoint ::
  forall b m t.
  (Backend b, P.MonadParse m) =>
  [HashMap (Column b) t] ->
  m (HashMap (Column b) t)
mergeDisjoint :: forall (b :: BackendType) (m :: * -> *) t.
(Backend b, MonadParse m) =>
[HashMap (Column b) t] -> m (HashMap (Column b) t)
mergeDisjoint [HashMap (Column b) t]
parsedResults = do
  let unioned :: HashMap (Column b) (NonEmpty t)
unioned = [HashMap (Column b) t] -> HashMap (Column b) (NonEmpty t)
forall k (t :: * -> *) v.
(Hashable k, Foldable t) =>
t (HashMap k v) -> HashMap k (NonEmpty v)
HashMap.unionsAll [HashMap (Column b) t]
parsedResults
      duplicates :: [Column b]
duplicates = HashMap (Column b) (NonEmpty t) -> [Column b]
forall k v. HashMap k v -> [k]
HashMap.keys (HashMap (Column b) (NonEmpty t) -> [Column b])
-> HashMap (Column b) (NonEmpty t) -> [Column b]
forall a b. (a -> b) -> a -> b
$ (NonEmpty t -> Bool)
-> HashMap (Column b) (NonEmpty t)
-> HashMap (Column b) (NonEmpty t)
forall v k. (v -> Bool) -> HashMap k v -> HashMap k v
HashMap.filter (Bool -> Bool
not (Bool -> Bool) -> (NonEmpty t -> Bool) -> NonEmpty t -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [t] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([t] -> Bool) -> (NonEmpty t -> [t]) -> NonEmpty t -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty t -> [t]
forall a. NonEmpty a -> [a]
NE.tail) HashMap (Column b) (NonEmpty t)
unioned

  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([Column b] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Column b]
duplicates)
    (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ ErrorMessage -> m ()
forall (m :: * -> *) a. MonadParse m => ErrorMessage -> m a
P.parseError
      ( ErrorMessage
"Column found in multiple operators: "
          ErrorMessage -> ErrorMessage -> ErrorMessage
forall a. Semigroup a => a -> a -> a
<> [Column b] -> ErrorMessage
forall a. ToErrorValue a => a -> ErrorMessage
toErrorValue [Column b]
duplicates
          ErrorMessage -> ErrorMessage -> ErrorMessage
forall a. Semigroup a => a -> a -> a
<> ErrorMessage
"."
      )

  return $ (NonEmpty t -> t)
-> HashMap (Column b) (NonEmpty t) -> HashMap (Column b) t
forall v1 v2 k. (v1 -> v2) -> HashMap k v1 -> HashMap k v2
HashMap.map NonEmpty t -> t
forall a. NonEmpty a -> a
NE.head HashMap (Column b) (NonEmpty t)
unioned

-- | Construct a parser for a single update operator.
--
-- @updateOperator _ "op" fp MkOp ["col1","col2"]@ gives a parser that accepts
-- objects in the shape of:
--
-- > op: {
-- >   col1: "x",
-- >   col2: "y"
-- > }
--
-- And (morally) parses into values:
--
-- > HashMap.fromList [("col1", MkOp (fp "x")), ("col2", MkOp (fp "y"))]
updateOperator ::
  forall n r m b a.
  (MonadBuildSchema b r m n) =>
  GQLNameIdentifier ->
  GQLNameIdentifier ->
  GQLNameIdentifier ->
  (ColumnInfo b -> SchemaT r m (P.Parser 'P.Both n a)) ->
  NonEmpty (ColumnInfo b) ->
  Description ->
  Description ->
  SchemaT r m (P.InputFieldsParser n (HashMap (Column b) a))
updateOperator :: forall (n :: * -> *) r (m :: * -> *) (b :: BackendType) a.
MonadBuildSchema b r m n =>
GQLNameIdentifier
-> GQLNameIdentifier
-> GQLNameIdentifier
-> (ColumnInfo b -> SchemaT r m (Parser 'Both n a))
-> NonEmpty (ColumnInfo b)
-> Description
-> Description
-> SchemaT r m (InputFieldsParser n (HashMap (Column b) a))
updateOperator GQLNameIdentifier
tableGQLName GQLNameIdentifier
opName GQLNameIdentifier
opFieldName ColumnInfo b -> SchemaT r m (Parser 'Both n a)
mkParser NonEmpty (ColumnInfo b)
columns Description
opDesc Description
objDesc = do
  SourceInfo b
sourceInfo :: SourceInfo b <- (r -> SourceInfo b) -> SchemaT r m (SourceInfo b)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks r -> SourceInfo b
forall a t. Has a t => t -> a
getter
  let customization :: ResolvedSourceCustomization
customization = SourceInfo b -> ResolvedSourceCustomization
forall (b :: BackendType).
SourceInfo b -> ResolvedSourceCustomization
_siCustomization SourceInfo b
sourceInfo
      tCase :: NamingCase
tCase = ResolvedSourceCustomization -> NamingCase
_rscNamingConvention ResolvedSourceCustomization
customization
      mkTypename :: Name -> Name
mkTypename = MkTypename -> Name -> Name
runMkTypename (MkTypename -> Name -> Name) -> MkTypename -> Name -> Name
forall a b. (a -> b) -> a -> b
$ ResolvedSourceCustomization -> MkTypename
_rscTypeNames ResolvedSourceCustomization
customization
  NonEmpty (InputFieldsParser n (Maybe (Column b, a)))
fieldParsers :: NonEmpty (P.InputFieldsParser n (Maybe (Column b, a))) <-
    NonEmpty (ColumnInfo b)
-> (ColumnInfo b
    -> SchemaT r m (InputFieldsParser n (Maybe (Column b, a))))
-> SchemaT
     r m (NonEmpty (InputFieldsParser n (Maybe (Column b, a))))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for NonEmpty (ColumnInfo b)
columns \ColumnInfo b
columnInfo -> do
      let fieldName :: Name
fieldName = ColumnInfo b -> Name
forall (b :: BackendType). ColumnInfo b -> Name
ciName ColumnInfo b
columnInfo
          fieldDesc :: Maybe Description
fieldDesc = ColumnInfo b -> Maybe Description
forall (b :: BackendType). ColumnInfo b -> Maybe Description
ciDescription ColumnInfo b
columnInfo
      Parser 'Both n a
fieldParser <- ColumnInfo b -> SchemaT r m (Parser 'Both n a)
mkParser ColumnInfo b
columnInfo
      pure
        $ Name
-> Maybe Description
-> Parser 'Both n a
-> InputFieldsParser MetadataObjId n (Maybe a)
forall (m :: * -> *) (k :: Kind) origin a.
(MonadParse m, 'Input <: k) =>
Name
-> Maybe Description
-> Parser origin k m a
-> InputFieldsParser origin m (Maybe a)
P.fieldOptional Name
fieldName Maybe Description
fieldDesc Parser 'Both n a
fieldParser
        InputFieldsParser MetadataObjId n (Maybe a)
-> (a -> (Column b, a))
-> InputFieldsParser n (Maybe (Column b, a))
forall (m :: * -> *) a b.
Functor m =>
InputFieldsParser m (Maybe a)
-> (a -> b) -> InputFieldsParser m (Maybe b)
`mapField` \a
value -> (ColumnInfo b -> Column b
forall (b :: BackendType). ColumnInfo b -> Column b
ciColumn ColumnInfo b
columnInfo, a
value)
  let objName :: Name
objName = Name -> Name
mkTypename (Name -> Name) -> Name -> Name
forall a b. (a -> b) -> a -> b
$ NamingCase -> GQLNameIdentifier -> Name
applyTypeNameCaseIdentifier NamingCase
tCase (GQLNameIdentifier -> Name) -> GQLNameIdentifier -> Name
forall a b. (a -> b) -> a -> b
$ GQLNameIdentifier -> GQLNameIdentifier -> GQLNameIdentifier
mkTableOperatorInputTypeName GQLNameIdentifier
tableGQLName GQLNameIdentifier
opName
  InputFieldsParser n (HashMap (Column b) a)
-> SchemaT r m (InputFieldsParser n (HashMap (Column b) a))
forall a. a -> SchemaT r m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    (InputFieldsParser n (HashMap (Column b) a)
 -> SchemaT r m (InputFieldsParser n (HashMap (Column b) a)))
-> InputFieldsParser n (HashMap (Column b) a)
-> SchemaT r m (InputFieldsParser n (HashMap (Column b) a))
forall a b. (a -> b) -> a -> b
$ (Maybe [(Column b, a)] -> HashMap (Column b) a)
-> InputFieldsParser MetadataObjId n (Maybe [(Column b, a)])
-> InputFieldsParser n (HashMap (Column b) a)
forall a b.
(a -> b)
-> InputFieldsParser MetadataObjId n a
-> InputFieldsParser MetadataObjId n b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([(Column b, a)] -> HashMap (Column b) a
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList ([(Column b, a)] -> HashMap (Column b) a)
-> (Maybe [(Column b, a)] -> [(Column b, a)])
-> Maybe [(Column b, a)]
-> HashMap (Column b) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe [(Column b, a)] -> [(Column b, a)]
forall m. Monoid m => Maybe m -> m
forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold :: Maybe [(Column b, a)] -> [(Column b, a)]))
    (InputFieldsParser MetadataObjId n (Maybe [(Column b, a)])
 -> InputFieldsParser n (HashMap (Column b) a))
-> InputFieldsParser MetadataObjId n (Maybe [(Column b, a)])
-> InputFieldsParser n (HashMap (Column b) a)
forall a b. (a -> b) -> a -> b
$ Name
-> Maybe Description
-> Parser MetadataObjId 'Input n [(Column b, a)]
-> InputFieldsParser MetadataObjId n (Maybe [(Column b, a)])
forall (m :: * -> *) (k :: Kind) origin a.
(MonadParse m, 'Input <: k) =>
Name
-> Maybe Description
-> Parser origin k m a
-> InputFieldsParser origin m (Maybe a)
P.fieldOptional (NamingCase -> GQLNameIdentifier -> Name
applyFieldNameCaseIdentifier NamingCase
tCase GQLNameIdentifier
opFieldName) (Description -> Maybe Description
forall a. a -> Maybe a
Just Description
opDesc)
    (Parser MetadataObjId 'Input n [(Column b, a)]
 -> InputFieldsParser MetadataObjId n (Maybe [(Column b, a)]))
-> Parser MetadataObjId 'Input n [(Column b, a)]
-> InputFieldsParser MetadataObjId n (Maybe [(Column b, a)])
forall a b. (a -> b) -> a -> b
$ Name
-> Maybe Description
-> InputFieldsParser MetadataObjId n [(Column b, a)]
-> Parser MetadataObjId 'Input n [(Column b, a)]
forall (m :: * -> *) origin a.
MonadParse m =>
Name
-> Maybe Description
-> InputFieldsParser origin m a
-> Parser origin 'Input m a
P.object Name
objName (Description -> Maybe Description
forall a. a -> Maybe a
Just Description
objDesc)
    (InputFieldsParser MetadataObjId n [(Column b, a)]
 -> Parser MetadataObjId 'Input n [(Column b, a)])
-> InputFieldsParser MetadataObjId n [(Column b, a)]
-> Parser MetadataObjId 'Input n [(Column b, a)]
forall a b. (a -> b) -> a -> b
$ ([Maybe (Column b, a)] -> [(Column b, a)]
forall a. [Maybe a] -> [a]
forall (f :: * -> *) a. Filterable f => f (Maybe a) -> f a
catMaybes ([Maybe (Column b, a)] -> [(Column b, a)])
-> (NonEmpty (Maybe (Column b, a)) -> [Maybe (Column b, a)])
-> NonEmpty (Maybe (Column b, a))
-> [(Column b, a)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty (Maybe (Column b, a)) -> [Maybe (Column b, a)]
forall a. NonEmpty a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList)
    (NonEmpty (Maybe (Column b, a)) -> [(Column b, a)])
-> InputFieldsParser
     MetadataObjId n (NonEmpty (Maybe (Column b, a)))
-> InputFieldsParser MetadataObjId n [(Column b, a)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty (InputFieldsParser n (Maybe (Column b, a)))
-> InputFieldsParser
     MetadataObjId n (NonEmpty (Maybe (Column b, a)))
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
forall (f :: * -> *) a.
Applicative f =>
NonEmpty (f a) -> f (NonEmpty a)
sequenceA NonEmpty (InputFieldsParser n (Maybe (Column b, a)))
fieldParsers
{-# ANN updateOperator ("HLint: ignore Use tuple-section" :: String) #-}

setOp ::
  forall b n r m.
  (MonadBuildSchema b r m n) =>
  UpdateOperator b r m n (UnpreparedValue b)
setOp :: forall (b :: BackendType) (n :: * -> *) r (m :: * -> *).
MonadBuildSchema b r m n =>
UpdateOperator b r m n (UnpreparedValue b)
setOp = UpdateOperator {GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT
     r m (InputFieldsParser n (HashMap (Column b) (UnpreparedValue b)))
ColumnInfo b -> Bool
forall {b}. b -> Bool
updateOperatorApplicableColumn :: ColumnInfo b -> Bool
updateOperatorParser :: GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT
     r m (InputFieldsParser n (HashMap (Column b) (UnpreparedValue b)))
updateOperatorApplicableColumn :: forall {b}. b -> Bool
updateOperatorParser :: GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT
     r m (InputFieldsParser n (HashMap (Column b) (UnpreparedValue b)))
..}
  where
    updateOperatorApplicableColumn :: b -> Bool
updateOperatorApplicableColumn = Bool -> b -> Bool
forall a b. a -> b -> a
const Bool
True

    updateOperatorParser :: GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT
     r m (InputFieldsParser n (HashMap (Column b) (UnpreparedValue b)))
updateOperatorParser GQLNameIdentifier
tableGQLName TableName b
tableName NonEmpty (ColumnInfo b)
columns = do
      let typedParser :: ColumnInfo b
-> SchemaT r m (Parser MetadataObjId 'Both n (UnpreparedValue b))
typedParser ColumnInfo b
columnInfo =
            (ValueWithOrigin (ColumnValue b) -> UnpreparedValue b)
-> Parser MetadataObjId 'Both n (ValueWithOrigin (ColumnValue b))
-> Parser MetadataObjId 'Both n (UnpreparedValue b)
forall a b.
(a -> b)
-> Parser MetadataObjId 'Both n a -> Parser MetadataObjId 'Both n b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ValueWithOrigin (ColumnValue b) -> UnpreparedValue b
forall (b :: BackendType).
ValueWithOrigin (ColumnValue b) -> UnpreparedValue b
mkParameter
              (Parser MetadataObjId 'Both n (ValueWithOrigin (ColumnValue b))
 -> Parser MetadataObjId 'Both n (UnpreparedValue b))
-> SchemaT
     r
     m
     (Parser MetadataObjId 'Both n (ValueWithOrigin (ColumnValue b)))
-> SchemaT r m (Parser MetadataObjId 'Both n (UnpreparedValue b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ColumnType b
-> Nullability
-> SchemaT
     r
     m
     (Parser MetadataObjId 'Both n (ValueWithOrigin (ColumnValue b)))
forall r (m :: * -> *) (n :: * -> *).
MonadBuildSchema b r m n =>
ColumnType b
-> Nullability
-> SchemaT r m (Parser 'Both n (ValueWithOrigin (ColumnValue b)))
forall (b :: BackendType) r (m :: * -> *) (n :: * -> *).
(BackendSchema b, MonadBuildSchema b r m n) =>
ColumnType b
-> Nullability
-> SchemaT r m (Parser 'Both n (ValueWithOrigin (ColumnValue b)))
columnParser
                (ColumnInfo b -> ColumnType b
forall (b :: BackendType). ColumnInfo b -> ColumnType b
ciType ColumnInfo b
columnInfo)
                (Bool -> Nullability
Nullability (Bool -> Nullability) -> Bool -> Nullability
forall a b. (a -> b) -> a -> b
$ ColumnInfo b -> Bool
forall (b :: BackendType). ColumnInfo b -> Bool
ciIsNullable ColumnInfo b
columnInfo)

      GQLNameIdentifier
-> GQLNameIdentifier
-> GQLNameIdentifier
-> (ColumnInfo b
    -> SchemaT r m (Parser 'Both n (UnpreparedValue b)))
-> NonEmpty (ColumnInfo b)
-> Description
-> Description
-> SchemaT
     r m (InputFieldsParser n (HashMap (Column b) (UnpreparedValue b)))
forall (n :: * -> *) r (m :: * -> *) (b :: BackendType) a.
MonadBuildSchema b r m n =>
GQLNameIdentifier
-> GQLNameIdentifier
-> GQLNameIdentifier
-> (ColumnInfo b -> SchemaT r m (Parser 'Both n a))
-> NonEmpty (ColumnInfo b)
-> Description
-> Description
-> SchemaT r m (InputFieldsParser n (HashMap (Column b) a))
updateOperator
        GQLNameIdentifier
tableGQLName
        (Name -> GQLNameIdentifier
fromAutogeneratedName $$(litName "set"))
        (Name -> GQLNameIdentifier
fromAutogeneratedName $$(litName "_set"))
        ColumnInfo b -> SchemaT r m (Parser 'Both n (UnpreparedValue b))
forall {b :: BackendType} {m :: * -> *} {n :: * -> *} {r}.
(BackendSchema b, MonadError QErr m, MonadMemoize m, MonadParse n,
 Has (SourceInfo b) r, Has SchemaContext r, Has SchemaOptions r) =>
ColumnInfo b
-> SchemaT r m (Parser MetadataObjId 'Both n (UnpreparedValue b))
typedParser
        NonEmpty (ColumnInfo b)
columns
        Description
"sets the columns of the filtered rows to the given values"
        (Text -> Description
Description (Text -> Description) -> Text -> Description
forall a b. (a -> b) -> a -> b
$ Text
"input type for updating data in table " Text -> TableName b -> Text
forall t. ToTxt t => Text -> t -> Text
<>> TableName b
tableName)

incOp ::
  forall b m n r.
  (MonadBuildSchema b r m n) =>
  UpdateOperator b r m n (UnpreparedValue b)
incOp :: forall (b :: BackendType) (m :: * -> *) (n :: * -> *) r.
MonadBuildSchema b r m n =>
UpdateOperator b r m n (UnpreparedValue b)
incOp = UpdateOperator {GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT
     r m (InputFieldsParser n (HashMap (Column b) (UnpreparedValue b)))
ColumnInfo b -> Bool
updateOperatorApplicableColumn :: ColumnInfo b -> Bool
updateOperatorParser :: GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT
     r m (InputFieldsParser n (HashMap (Column b) (UnpreparedValue b)))
updateOperatorApplicableColumn :: ColumnInfo b -> Bool
updateOperatorParser :: GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT
     r m (InputFieldsParser n (HashMap (Column b) (UnpreparedValue b)))
..}
  where
    updateOperatorApplicableColumn :: ColumnInfo b -> Bool
updateOperatorApplicableColumn = ColumnInfo b -> Bool
forall (b :: BackendType). Backend b => ColumnInfo b -> Bool
isNumCol

    updateOperatorParser :: GQLNameIdentifier
-> TableName b
-> NonEmpty (ColumnInfo b)
-> SchemaT
     r m (InputFieldsParser n (HashMap (Column b) (UnpreparedValue b)))
updateOperatorParser GQLNameIdentifier
tableGQLName TableName b
tableName NonEmpty (ColumnInfo b)
columns = do
      let typedParser :: ColumnInfo b
-> SchemaT r m (Parser MetadataObjId 'Both n (UnpreparedValue b))
typedParser ColumnInfo b
columnInfo =
            (ValueWithOrigin (ColumnValue b) -> UnpreparedValue b)
-> Parser MetadataObjId 'Both n (ValueWithOrigin (ColumnValue b))
-> Parser MetadataObjId 'Both n (UnpreparedValue b)
forall a b.
(a -> b)
-> Parser MetadataObjId 'Both n a -> Parser MetadataObjId 'Both n b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ValueWithOrigin (ColumnValue b) -> UnpreparedValue b
forall (b :: BackendType).
ValueWithOrigin (ColumnValue b) -> UnpreparedValue b
mkParameter
              (Parser MetadataObjId 'Both n (ValueWithOrigin (ColumnValue b))
 -> Parser MetadataObjId 'Both n (UnpreparedValue b))
-> SchemaT
     r
     m
     (Parser MetadataObjId 'Both n (ValueWithOrigin (ColumnValue b)))
-> SchemaT r m (Parser MetadataObjId 'Both n (UnpreparedValue b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ColumnType b
-> Nullability
-> SchemaT
     r
     m
     (Parser MetadataObjId 'Both n (ValueWithOrigin (ColumnValue b)))
forall r (m :: * -> *) (n :: * -> *).
MonadBuildSchema b r m n =>
ColumnType b
-> Nullability
-> SchemaT r m (Parser 'Both n (ValueWithOrigin (ColumnValue b)))
forall (b :: BackendType) r (m :: * -> *) (n :: * -> *).
(BackendSchema b, MonadBuildSchema b r m n) =>
ColumnType b
-> Nullability
-> SchemaT r m (Parser 'Both n (ValueWithOrigin (ColumnValue b)))
columnParser
                (ColumnInfo b -> ColumnType b
forall (b :: BackendType). ColumnInfo b -> ColumnType b
ciType ColumnInfo b
columnInfo)
                (Bool -> Nullability
Nullability (Bool -> Nullability) -> Bool -> Nullability
forall a b. (a -> b) -> a -> b
$ ColumnInfo b -> Bool
forall (b :: BackendType). ColumnInfo b -> Bool
ciIsNullable ColumnInfo b
columnInfo)

      GQLNameIdentifier
-> GQLNameIdentifier
-> GQLNameIdentifier
-> (ColumnInfo b
    -> SchemaT r m (Parser 'Both n (UnpreparedValue b)))
-> NonEmpty (ColumnInfo b)
-> Description
-> Description
-> SchemaT
     r m (InputFieldsParser n (HashMap (Column b) (UnpreparedValue b)))
forall (n :: * -> *) r (m :: * -> *) (b :: BackendType) a.
MonadBuildSchema b r m n =>
GQLNameIdentifier
-> GQLNameIdentifier
-> GQLNameIdentifier
-> (ColumnInfo b -> SchemaT r m (Parser 'Both n a))
-> NonEmpty (ColumnInfo b)
-> Description
-> Description
-> SchemaT r m (InputFieldsParser n (HashMap (Column b) a))
updateOperator
        GQLNameIdentifier
tableGQLName
        (Name -> GQLNameIdentifier
fromAutogeneratedName $$(litName "inc"))
        (Name -> GQLNameIdentifier
fromAutogeneratedName $$(litName "_inc"))
        ColumnInfo b -> SchemaT r m (Parser 'Both n (UnpreparedValue b))
forall {b :: BackendType} {m :: * -> *} {n :: * -> *} {r}.
(BackendSchema b, MonadError QErr m, MonadMemoize m, MonadParse n,
 Has (SourceInfo b) r, Has SchemaContext r, Has SchemaOptions r) =>
ColumnInfo b
-> SchemaT r m (Parser MetadataObjId 'Both n (UnpreparedValue b))
typedParser
        NonEmpty (ColumnInfo b)
columns
        Description
"increments the numeric columns with given value of the filtered values"
        (Text -> Description
Description (Text -> Description) -> Text -> Description
forall a b. (a -> b) -> a -> b
$ Text
"input type for incrementing numeric columns in table " Text -> TableName b -> Text
forall t. ToTxt t => Text -> t -> Text
<>> TableName b
tableName)