2018-07-20 13:51:20 +03:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
|
|
{-# LANGUAGE MultiWayIf #-}
|
|
|
|
{-# LANGUAGE NoImplicitPrelude #-}
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
|
|
module Hasura.GraphQL.Resolve.Mutation
|
|
|
|
( convertUpdate
|
|
|
|
, convertDelete
|
2018-10-05 18:13:51 +03:00
|
|
|
, convertMutResp
|
2018-06-27 16:11:32 +03:00
|
|
|
) where
|
|
|
|
|
|
|
|
import Hasura.Prelude
|
|
|
|
|
2018-10-12 13:36:47 +03:00
|
|
|
import qualified Data.HashMap.Strict.InsOrd as OMap
|
2018-06-27 16:11:32 +03:00
|
|
|
import qualified Language.GraphQL.Draft.Syntax as G
|
|
|
|
|
|
|
|
import qualified Hasura.RQL.DML.Delete as RD
|
|
|
|
import qualified Hasura.RQL.DML.Returning as RR
|
2018-08-30 12:49:21 +03:00
|
|
|
import qualified Hasura.RQL.DML.Select as RS
|
2018-06-27 16:11:32 +03:00
|
|
|
import qualified Hasura.RQL.DML.Update as RU
|
|
|
|
|
|
|
|
import qualified Hasura.SQL.DML as S
|
|
|
|
|
|
|
|
import Hasura.GraphQL.Resolve.BoolExp
|
|
|
|
import Hasura.GraphQL.Resolve.Context
|
|
|
|
import Hasura.GraphQL.Resolve.InputValue
|
2018-08-30 12:49:21 +03:00
|
|
|
import Hasura.GraphQL.Resolve.Select (fromSelSet)
|
2018-06-27 16:11:32 +03:00
|
|
|
import Hasura.GraphQL.Validate.Field
|
|
|
|
import Hasura.GraphQL.Validate.Types
|
|
|
|
import Hasura.RQL.Types
|
|
|
|
import Hasura.SQL.Types
|
2018-07-20 13:51:20 +03:00
|
|
|
import Hasura.SQL.Value
|
2018-06-27 16:11:32 +03:00
|
|
|
|
2018-10-05 11:56:47 +03:00
|
|
|
withSelSet :: (Monad m) => SelSet -> (Field -> m a) -> m [(Text, a)]
|
2018-06-27 16:11:32 +03:00
|
|
|
withSelSet selSet f =
|
2018-10-05 11:56:47 +03:00
|
|
|
forM (toList selSet) $ \fld -> do
|
2018-06-27 16:11:32 +03:00
|
|
|
res <- f fld
|
|
|
|
return (G.unName $ G.unAlias $ _fAlias fld, res)
|
|
|
|
|
|
|
|
convertReturning
|
2018-10-05 11:56:47 +03:00
|
|
|
:: QualifiedTable -> G.NamedType -> SelSet -> Convert RS.AnnSel
|
2018-08-30 12:49:21 +03:00
|
|
|
convertReturning qt ty selSet = do
|
|
|
|
annFlds <- fromSelSet ty selSet
|
2018-10-05 11:56:47 +03:00
|
|
|
return $ RS.AnnSel annFlds qt (Just frmItem)
|
|
|
|
(S.BELit True) Nothing RS.noTableArgs
|
2018-08-30 12:49:21 +03:00
|
|
|
where
|
2018-10-05 11:56:47 +03:00
|
|
|
frmItem = S.FIIden $ RR.qualTableToAliasIden qt
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
|
|
convertMutResp
|
2018-08-30 12:49:21 +03:00
|
|
|
:: QualifiedTable -> G.NamedType -> SelSet -> Convert RR.MutFlds
|
|
|
|
convertMutResp qt ty selSet =
|
2018-06-27 16:11:32 +03:00
|
|
|
withSelSet selSet $ \fld ->
|
|
|
|
case _fName fld of
|
|
|
|
"__typename" -> return $ RR.MExp $ G.unName $ G.unNamedType ty
|
|
|
|
"affected_rows" -> return RR.MCount
|
2018-08-30 12:49:21 +03:00
|
|
|
_ -> fmap RR.MRet $ convertReturning qt (_fType fld) $ _fSelSet fld
|
2018-06-27 16:11:32 +03:00
|
|
|
|
|
|
|
convertRowObj
|
|
|
|
:: (MonadError QErr m, MonadState PrepArgs m)
|
|
|
|
=> AnnGValue
|
|
|
|
-> m [(PGCol, S.SQLExp)]
|
|
|
|
convertRowObj val =
|
2018-10-12 13:36:47 +03:00
|
|
|
flip withObject val $ \_ obj -> forM (OMap.toList obj) $ \(k, v) -> do
|
2018-08-07 13:43:42 +03:00
|
|
|
prepExpM <- asPGColValM v >>= mapM prepare
|
|
|
|
let prepExp = fromMaybe (S.SEUnsafe "NULL") prepExpM
|
2018-06-27 16:11:32 +03:00
|
|
|
return (PGCol $ G.unName k, prepExp)
|
|
|
|
|
2018-07-20 13:51:20 +03:00
|
|
|
type ApplySQLOp = (PGCol, S.SQLExp) -> S.SQLExp
|
|
|
|
|
|
|
|
rhsExpOp :: S.SQLOp -> S.AnnType -> ApplySQLOp
|
|
|
|
rhsExpOp op annTy (col, e) =
|
|
|
|
S.mkSQLOpExp op (S.SEIden $ toIden col) annExp
|
|
|
|
where
|
|
|
|
annExp = S.SETyAnn e annTy
|
|
|
|
|
|
|
|
lhsExpOp :: S.SQLOp -> S.AnnType -> ApplySQLOp
|
|
|
|
lhsExpOp op annTy (col, e) =
|
|
|
|
S.mkSQLOpExp op annExp $ S.SEIden $ toIden col
|
|
|
|
where
|
|
|
|
annExp = S.SETyAnn e annTy
|
|
|
|
|
|
|
|
convObjWithOp
|
|
|
|
:: (MonadError QErr m)
|
|
|
|
=> ApplySQLOp -> AnnGValue -> m [(PGCol, S.SQLExp)]
|
|
|
|
convObjWithOp opFn val =
|
2018-10-12 13:36:47 +03:00
|
|
|
flip withObject val $ \_ obj -> forM (OMap.toList obj) $ \(k, v) -> do
|
2018-07-20 13:51:20 +03:00
|
|
|
(_, colVal) <- asPGColVal v
|
|
|
|
let pgCol = PGCol $ G.unName k
|
|
|
|
encVal = txtEncoder colVal
|
|
|
|
sqlExp = opFn (pgCol, encVal)
|
|
|
|
return (pgCol, sqlExp)
|
|
|
|
|
|
|
|
convDeleteAtPathObj
|
|
|
|
:: (MonadError QErr m)
|
|
|
|
=> AnnGValue -> m [(PGCol, S.SQLExp)]
|
|
|
|
convDeleteAtPathObj val =
|
2018-10-12 13:36:47 +03:00
|
|
|
flip withObject val $ \_ obj -> forM (OMap.toList obj) $ \(k, v) -> do
|
2018-07-20 13:51:20 +03:00
|
|
|
vals <- flip withArray v $ \_ annVals -> mapM asPGColVal annVals
|
|
|
|
let valExps = map (txtEncoder . snd) vals
|
|
|
|
pgCol = PGCol $ G.unName k
|
|
|
|
annEncVal = S.SETyAnn (S.SEArray valExps) S.textArrType
|
|
|
|
sqlExp = S.SEOpApp S.jsonbDeleteAtPathOp
|
|
|
|
[S.SEIden $ toIden pgCol, annEncVal]
|
|
|
|
return (pgCol, sqlExp)
|
|
|
|
|
2018-06-27 16:11:32 +03:00
|
|
|
convertUpdate
|
|
|
|
:: QualifiedTable -- table
|
|
|
|
-> S.BoolExp -- the filter expression
|
|
|
|
-> Field -- the mutation field
|
|
|
|
-> Convert RespTx
|
|
|
|
convertUpdate tn filterExp fld = do
|
|
|
|
-- a set expression is same as a row object
|
2018-07-20 13:51:20 +03:00
|
|
|
setExpM <- withArgM args "_set" convertRowObj
|
|
|
|
-- where bool expression to filter column
|
2018-06-27 16:11:32 +03:00
|
|
|
whereExp <- withArg args "where" $ convertBoolExp tn
|
2018-07-20 13:51:20 +03:00
|
|
|
-- increment operator on integer columns
|
|
|
|
incExpM <- withArgM args "_inc" $
|
|
|
|
convObjWithOp $ rhsExpOp S.incOp S.intType
|
|
|
|
-- append jsonb value
|
|
|
|
appendExpM <- withArgM args "_append" $
|
|
|
|
convObjWithOp $ rhsExpOp S.jsonbConcatOp S.jsonbType
|
|
|
|
-- prepend jsonb value
|
|
|
|
prependExpM <- withArgM args "_prepend" $
|
|
|
|
convObjWithOp $ lhsExpOp S.jsonbConcatOp S.jsonbType
|
|
|
|
-- delete a key in jsonb object
|
|
|
|
deleteKeyExpM <- withArgM args "_delete_key" $
|
|
|
|
convObjWithOp $ rhsExpOp S.jsonbDeleteOp S.textType
|
|
|
|
-- delete an element in jsonb array
|
|
|
|
deleteElemExpM <- withArgM args "_delete_elem" $
|
|
|
|
convObjWithOp $ rhsExpOp S.jsonbDeleteOp S.intType
|
|
|
|
-- delete at path in jsonb value
|
|
|
|
deleteAtPathExpM <- withArgM args "_delete_at_path" convDeleteAtPathObj
|
|
|
|
|
2018-08-30 12:49:21 +03:00
|
|
|
mutFlds <- convertMutResp tn (_fType fld) $ _fSelSet fld
|
2018-06-27 16:11:32 +03:00
|
|
|
prepArgs <- get
|
2018-07-20 13:51:20 +03:00
|
|
|
let updExpsM = [ setExpM, incExpM, appendExpM, prependExpM
|
|
|
|
, deleteKeyExpM, deleteElemExpM, deleteAtPathExpM
|
|
|
|
]
|
|
|
|
updExp = concat $ catMaybes updExpsM
|
|
|
|
-- atleast one of update operators is expected
|
2018-09-04 16:39:48 +03:00
|
|
|
unless (any isJust updExpsM) $ throwVE $
|
2018-07-20 13:51:20 +03:00
|
|
|
"atleast any one of _set, _inc, _append, _prepend, _delete_key, _delete_elem and "
|
|
|
|
<> " _delete_at_path operator is expected"
|
|
|
|
let p1 = RU.UpdateQueryP1 tn updExp (filterExp, whereExp) mutFlds
|
2018-06-27 16:11:32 +03:00
|
|
|
return $ RU.updateP2 (p1, prepArgs)
|
|
|
|
where
|
|
|
|
args = _fArguments fld
|
|
|
|
|
|
|
|
convertDelete
|
|
|
|
:: QualifiedTable -- table
|
|
|
|
-> S.BoolExp -- the filter expression
|
|
|
|
-> Field -- the mutation field
|
|
|
|
-> Convert RespTx
|
|
|
|
convertDelete tn filterExp fld = do
|
|
|
|
whereExp <- withArg (_fArguments fld) "where" $ convertBoolExp tn
|
2018-08-30 12:49:21 +03:00
|
|
|
mutFlds <- convertMutResp tn (_fType fld) $ _fSelSet fld
|
2018-06-27 16:11:32 +03:00
|
|
|
args <- get
|
|
|
|
let p1 = RD.DeleteQueryP1 tn (filterExp, whereExp) mutFlds
|
|
|
|
return $ RD.deleteP2 (p1, args)
|