mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 08:02:15 +03:00
This commit is contained in:
parent
fc73d4d30a
commit
8e3b8f51c9
@ -188,7 +188,7 @@ mkCompExpInp colTy =
|
||||
, bool [] (map (mk $ mkScalarTy PGText) stringOps) isStringTy
|
||||
, bool [] (map jsonbOpToInpVal jsonbOps) isJsonbTy
|
||||
, bool [] (stDWithinOpInpVal : map geomOpToInpVal geomOps) isGeometryTy
|
||||
, [InpValInfo Nothing "_is_null" $ G.TypeNamed (G.Nullability True) $ G.NamedType "Boolean"]
|
||||
, [InpValInfo Nothing "_is_null" Nothing $ G.TypeNamed (G.Nullability True) $ G.NamedType "Boolean"]
|
||||
]) HasuraType
|
||||
where
|
||||
tyDesc = mconcat
|
||||
@ -200,7 +200,7 @@ mkCompExpInp colTy =
|
||||
PGVarchar -> True
|
||||
PGText -> True
|
||||
_ -> False
|
||||
mk t n = InpValInfo Nothing n $ G.toGT t
|
||||
mk t n = InpValInfo Nothing n Nothing $ G.toGT t
|
||||
colScalarTy = mkScalarTy colTy
|
||||
-- colScalarListTy = GA.GTList colGTy
|
||||
typedOps =
|
||||
@ -218,7 +218,7 @@ mkCompExpInp colTy =
|
||||
isJsonbTy = case colTy of
|
||||
PGJSONB -> True
|
||||
_ -> False
|
||||
jsonbOpToInpVal (op, ty, desc) = InpValInfo (Just desc) op ty
|
||||
jsonbOpToInpVal (op, ty, desc) = InpValInfo (Just desc) op Nothing ty
|
||||
jsonbOps =
|
||||
[ ( "_contains"
|
||||
, G.toGT $ mkScalarTy PGJSONB
|
||||
@ -244,7 +244,7 @@ mkCompExpInp colTy =
|
||||
|
||||
-- Geometry related ops
|
||||
stDWithinOpInpVal =
|
||||
InpValInfo (Just stDWithinDesc) "_st_d_within" $ G.toGT stDWithinInpTy
|
||||
InpValInfo (Just stDWithinDesc) "_st_d_within" Nothing $ G.toGT stDWithinInpTy
|
||||
stDWithinDesc =
|
||||
"is the column within a distance from a geometry value"
|
||||
|
||||
@ -253,7 +253,7 @@ mkCompExpInp colTy =
|
||||
_ -> False
|
||||
|
||||
geomOpToInpVal (op, desc) =
|
||||
InpValInfo (Just desc) op $ G.toGT $ mkScalarTy PGGeometry
|
||||
InpValInfo (Just desc) op Nothing $ G.toGT $ mkScalarTy PGGeometry
|
||||
geomOps =
|
||||
[
|
||||
( "_st_contains"
|
||||
@ -352,15 +352,15 @@ mkGCtx (TyAgg tyInfos fldInfos ordByEnums funcArgCtx) (RootFlds flds) insCtxMap
|
||||
G.toGT $ G.NamedType "__Type"
|
||||
where
|
||||
typeFldArgs = mapFromL _iviName [
|
||||
InpValInfo (Just "name of the type") "name"
|
||||
InpValInfo (Just "name of the type") "name" Nothing
|
||||
$ G.toGT $ G.toNT $ G.NamedType "String"
|
||||
]
|
||||
|
||||
stDWithinInpM = bool Nothing (Just stDWithinInp) (PGGeometry `elem` colTys)
|
||||
stDWithinInp =
|
||||
mkHsraInpTyInfo Nothing stDWithinInpTy $ fromInpValL
|
||||
[ InpValInfo Nothing "from" $ G.toGT $ G.toNT $ mkScalarTy PGGeometry
|
||||
, InpValInfo Nothing "distance" $ G.toNT $ G.toNT $ mkScalarTy PGFloat
|
||||
[ InpValInfo Nothing "from" Nothing $ G.toGT $ G.toNT $ mkScalarTy PGGeometry
|
||||
, InpValInfo Nothing "distance" Nothing $ G.toNT $ G.toNT $ mkScalarTy PGFloat
|
||||
]
|
||||
|
||||
emptyGCtx :: GCtx
|
||||
|
@ -14,6 +14,7 @@ import qualified Data.HashMap.Strict as Map
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.Encoding as T
|
||||
import qualified Language.GraphQL.Draft.Syntax as G
|
||||
import qualified Language.GraphQL.Draft.Parser as G
|
||||
import qualified Network.HTTP.Client as HTTP
|
||||
import qualified Network.Wreq as Wreq
|
||||
|
||||
@ -25,6 +26,7 @@ import qualified Hasura.GraphQL.Schema as GS
|
||||
import qualified Hasura.GraphQL.Validate.Types as VT
|
||||
|
||||
|
||||
|
||||
introspectionQuery :: BL.ByteString
|
||||
introspectionQuery = $(embedStringFile "src-rsr/introspection.json")
|
||||
|
||||
@ -265,11 +267,15 @@ instance J.FromJSON (FromIntrospection G.InputValueDefinition) where
|
||||
name <- o .: "name"
|
||||
desc <- o .:? "description"
|
||||
_type <- o .: "type"
|
||||
--defValue <- o .: "defaultValue"
|
||||
defVal <- o .:? "defaultValue"
|
||||
let desc' = fmap fromIntrospection desc
|
||||
r = G.InputValueDefinition desc' name (fromIntrospection _type) Nothing
|
||||
let defVal' = fmap fromIntrospection defVal
|
||||
r = G.InputValueDefinition desc' name (fromIntrospection _type) defVal'
|
||||
return $ FromIntrospection r
|
||||
|
||||
instance J.FromJSON (FromIntrospection G.ValueConst) where
|
||||
parseJSON = J.withText "defaultValue" $ \t -> fmap FromIntrospection
|
||||
$ either (fail . T.unpack) return $ G.parseValueConst t
|
||||
|
||||
-- instance J.FromJSON (FromIntrospection G.ListType) where
|
||||
-- parseJSON = parseJSON
|
||||
@ -284,11 +290,6 @@ instance J.FromJSON (FromIntrospection G.InputValueDefinition) where
|
||||
-- ofVal <- o .: "value"
|
||||
-- return $ FromIntrospection $ G.ObjectFieldG name ofVal
|
||||
|
||||
-- instance J.FromJSON (FromIntrospection G.ValueConst) where
|
||||
-- parseJSON =
|
||||
-- fmap FromIntrospection .
|
||||
-- $(J.mkParseJSON J.defaultOptions{J.sumEncoding=J.UntaggedValue} ''G.ValueConst)
|
||||
|
||||
-- instance J.FromJSON (FromIntrospection G.Value) where
|
||||
-- parseJSON =
|
||||
-- fmap FromIntrospection .
|
||||
|
@ -13,6 +13,7 @@ import qualified Language.GraphQL.Draft.Syntax as G
|
||||
|
||||
import Hasura.GraphQL.Resolve.Context
|
||||
import Hasura.GraphQL.Resolve.InputValue
|
||||
import Hasura.GraphQL.Validate.InputValue
|
||||
import Hasura.GraphQL.Validate.Context
|
||||
import Hasura.GraphQL.Validate.Field
|
||||
import Hasura.GraphQL.Validate.Types
|
||||
@ -201,7 +202,7 @@ inputValueR
|
||||
:: ( MonadReader r m, Has TypeMap r
|
||||
, MonadError QErr m)
|
||||
=> Field -> InpValInfo -> m J.Object
|
||||
inputValueR fld (InpValInfo descM n ty) =
|
||||
inputValueR fld (InpValInfo descM n defM ty) =
|
||||
withSubFields (_fSelSet fld) $ \subFld ->
|
||||
case _fName subFld of
|
||||
"__typename" -> retJT "__InputValue"
|
||||
@ -209,7 +210,7 @@ inputValueR fld (InpValInfo descM n ty) =
|
||||
"description" -> retJ $ fmap G.unDescription descM
|
||||
"type" -> J.toJSON <$> gtypeR ty subFld
|
||||
-- TODO: figure out what the spec means by 'string encoding'
|
||||
"defaultValue" -> return J.Null
|
||||
"defaultValue" -> retJ $ pPrintValueC <$> defM
|
||||
_ -> return J.Null
|
||||
|
||||
-- 4.5.5
|
||||
|
@ -348,12 +348,12 @@ mkPGColFld (PGColInfo colName colTy isNullable) =
|
||||
-- distinct_on: [table_select_column!]
|
||||
mkSelArgs :: QualifiedTable -> [InpValInfo]
|
||||
mkSelArgs tn =
|
||||
[ InpValInfo (Just whereDesc) "where" $ G.toGT $ mkBoolExpTy tn
|
||||
, InpValInfo (Just limitDesc) "limit" $ G.toGT $ mkScalarTy PGInteger
|
||||
, InpValInfo (Just offsetDesc) "offset" $ G.toGT $ mkScalarTy PGInteger
|
||||
, InpValInfo (Just orderByDesc) "order_by" $ G.toGT $ G.toLT $ G.toNT $
|
||||
[ InpValInfo (Just whereDesc) "where" Nothing $ G.toGT $ mkBoolExpTy tn
|
||||
, InpValInfo (Just limitDesc) "limit" Nothing $ G.toGT $ mkScalarTy PGInteger
|
||||
, InpValInfo (Just offsetDesc) "offset" Nothing $ G.toGT $ mkScalarTy PGInteger
|
||||
, InpValInfo (Just orderByDesc) "order_by" Nothing $ G.toGT $ G.toLT $ G.toNT $
|
||||
mkOrdByTy tn
|
||||
, InpValInfo (Just distinctDesc) "distinct_on" $ G.toGT $ G.toLT $
|
||||
, InpValInfo (Just distinctDesc) "distinct_on" Nothing $ G.toGT $ G.toLT $
|
||||
G.toNT $ mkSelColumnInpTy tn
|
||||
]
|
||||
where
|
||||
@ -471,9 +471,9 @@ mkTableAggFldsObj tn numCols compCols =
|
||||
|
||||
countParams = fromInpValL [countColInpVal, distinctInpVal]
|
||||
|
||||
countColInpVal = InpValInfo Nothing "columns" $ G.toGT $
|
||||
countColInpVal = InpValInfo Nothing "columns" Nothing $ G.toGT $
|
||||
G.toLT $ G.toNT $ mkSelColumnInpTy tn
|
||||
distinctInpVal = InpValInfo Nothing "distinct" $ G.toGT $
|
||||
distinctInpVal = InpValInfo Nothing "distinct" Nothing $ G.toGT $
|
||||
mkScalarTy PGBoolean
|
||||
|
||||
numFlds = bool (map mkColOpFld numAggOps) [] $ null numCols
|
||||
@ -544,7 +544,7 @@ mkSelFldPKey tn cols =
|
||||
args = fromInpValL $ map colInpVal cols
|
||||
ty = G.toGT $ mkTableTy tn
|
||||
colInpVal (PGColInfo n typ _) =
|
||||
InpValInfo Nothing (mkColName n) $ G.toGT $ G.toNT $ mkScalarTy typ
|
||||
InpValInfo Nothing (mkColName n) Nothing $ G.toGT $ G.toNT $ mkScalarTy typ
|
||||
|
||||
{-
|
||||
|
||||
@ -587,7 +587,7 @@ mkFuncArgs funInfo =
|
||||
retTable = fiReturnType funInfo
|
||||
|
||||
funcArgDesc = G.Description $ "input parameters for function " <>> funcName
|
||||
funcInpArg = InpValInfo (Just funcArgDesc) "args" $ G.toGT $ G.toNT $
|
||||
funcInpArg = InpValInfo (Just funcArgDesc) "args" Nothing $ G.toGT $ G.toNT $
|
||||
mkFuncArgsTy funcName
|
||||
funcInpArgs = bool [funcInpArg] [] $ null funcArgs
|
||||
|
||||
@ -685,7 +685,7 @@ mkBoolExpInp tn fields =
|
||||
-- all the fields of this input object
|
||||
inpValues = combinators <> map mkFldExpInp fields
|
||||
|
||||
mk n ty = InpValInfo Nothing n $ G.toGT ty
|
||||
mk n ty = InpValInfo Nothing n Nothing $ G.toGT ty
|
||||
|
||||
boolExpListTy = G.toLT boolExpTy
|
||||
|
||||
@ -703,7 +703,7 @@ mkBoolExpInp tn fields =
|
||||
|
||||
mkPGColInp :: PGColInfo -> InpValInfo
|
||||
mkPGColInp (PGColInfo colName colTy _) =
|
||||
InpValInfo Nothing (G.Name $ getPGColTxt colName) $
|
||||
InpValInfo Nothing (G.Name $ getPGColTxt colName) Nothing $
|
||||
G.toGT $ mkScalarTy colTy
|
||||
|
||||
{-
|
||||
@ -732,13 +732,13 @@ mkFuncArgsInp funcInfo =
|
||||
case nameM of
|
||||
Just argName ->
|
||||
let argGName = G.Name $ getFuncArgNameTxt argName
|
||||
inpVal = InpValInfo Nothing argGName $
|
||||
inpVal = InpValInfo Nothing argGName Nothing $
|
||||
G.toGT $ G.toNT $ mkScalarTy ty
|
||||
argCtxItem = FuncArgItem argGName
|
||||
in (items <> pure (inpVal, argCtxItem), argNo)
|
||||
Nothing ->
|
||||
let argGName = G.Name $ "arg_" <> T.pack (show argNo)
|
||||
inpVal = InpValInfo Nothing argGName $
|
||||
inpVal = InpValInfo Nothing argGName Nothing $
|
||||
G.toGT $ G.toNT $ mkScalarTy ty
|
||||
argCtxItem = FuncArgItem argGName
|
||||
in (items <> pure (inpVal, argCtxItem), argNo + 1)
|
||||
@ -889,19 +889,19 @@ mkUpdJSONOpInp tn cols = bool inpObjs [] $ null jsonbCols
|
||||
deleteKeyInpObj =
|
||||
mkHsraInpTyInfo (Just deleteKeyDesc) (mkJSONOpTy tn deleteKeyOp) $
|
||||
fromInpValL $ map deleteKeyInpVal jsonbColNames
|
||||
deleteKeyInpVal c = InpValInfo Nothing (G.Name $ getPGColTxt c) $
|
||||
deleteKeyInpVal c = InpValInfo Nothing (G.Name $ getPGColTxt c) Nothing $
|
||||
G.toGT $ G.NamedType "String"
|
||||
|
||||
deleteElemInpObj =
|
||||
mkHsraInpTyInfo (Just deleteElemDesc) (mkJSONOpTy tn deleteElemOp) $
|
||||
fromInpValL $ map deleteElemInpVal jsonbColNames
|
||||
deleteElemInpVal c = InpValInfo Nothing (G.Name $ getPGColTxt c) $
|
||||
deleteElemInpVal c = InpValInfo Nothing (G.Name $ getPGColTxt c) Nothing $
|
||||
G.toGT $ G.NamedType "Int"
|
||||
|
||||
deleteAtPathInpObj =
|
||||
mkHsraInpTyInfo (Just deleteAtPathDesc) (mkJSONOpTy tn deleteAtPathOp) $
|
||||
fromInpValL $ map deleteAtPathInpVal jsonbColNames
|
||||
deleteAtPathInpVal c = InpValInfo Nothing (G.Name $ getPGColTxt c) $
|
||||
deleteAtPathInpVal c = InpValInfo Nothing (G.Name $ getPGColTxt c) Nothing $
|
||||
G.toGT $ G.toLT $ G.NamedType "String"
|
||||
|
||||
{-
|
||||
@ -924,7 +924,7 @@ mkIncInpVal tn cols = bool (Just incArg) Nothing $ null intCols
|
||||
intCols = onlyIntCols cols
|
||||
incArgDesc = "increments the integer columns with given value of the filtered values"
|
||||
incArg =
|
||||
InpValInfo (Just incArgDesc) "_inc" $ G.toGT $ mkUpdIncTy tn
|
||||
InpValInfo (Just incArgDesc) "_inc" Nothing $ G.toGT $ mkUpdIncTy tn
|
||||
|
||||
mkJSONOpInpVals :: QualifiedTable -> [PGColInfo] -> [InpValInfo]
|
||||
mkJSONOpInpVals tn cols = bool jsonbOpArgs [] $ null jsonbCols
|
||||
@ -933,21 +933,21 @@ mkJSONOpInpVals tn cols = bool jsonbOpArgs [] $ null jsonbCols
|
||||
jsonbOpArgs = [appendArg, prependArg, deleteKeyArg, deleteElemArg, deleteAtPathArg]
|
||||
|
||||
appendArg =
|
||||
InpValInfo (Just appendDesc) appendOp $ G.toGT $ mkJSONOpTy tn appendOp
|
||||
InpValInfo (Just appendDesc) appendOp Nothing $ G.toGT $ mkJSONOpTy tn appendOp
|
||||
|
||||
prependArg =
|
||||
InpValInfo (Just prependDesc) prependOp $ G.toGT $ mkJSONOpTy tn prependOp
|
||||
InpValInfo (Just prependDesc) prependOp Nothing $ G.toGT $ mkJSONOpTy tn prependOp
|
||||
|
||||
deleteKeyArg =
|
||||
InpValInfo (Just deleteKeyDesc) deleteKeyOp $
|
||||
InpValInfo (Just deleteKeyDesc) deleteKeyOp Nothing $
|
||||
G.toGT $ mkJSONOpTy tn deleteKeyOp
|
||||
|
||||
deleteElemArg =
|
||||
InpValInfo (Just deleteElemDesc) deleteElemOp $
|
||||
InpValInfo (Just deleteElemDesc) deleteElemOp Nothing $
|
||||
G.toGT $ mkJSONOpTy tn deleteElemOp
|
||||
|
||||
deleteAtPathArg =
|
||||
InpValInfo (Just deleteAtPathDesc) deleteAtPathOp $
|
||||
InpValInfo (Just deleteAtPathDesc) deleteAtPathOp Nothing $
|
||||
G.toGT $ mkJSONOpTy tn deleteAtPathOp
|
||||
|
||||
mkUpdMutFld
|
||||
@ -964,12 +964,12 @@ mkUpdMutFld tn cols =
|
||||
|
||||
filterArgDesc = "filter the rows which have to be updated"
|
||||
filterArg =
|
||||
InpValInfo (Just filterArgDesc) "where" $ G.toGT $
|
||||
InpValInfo (Just filterArgDesc) "where" Nothing $ G.toGT $
|
||||
G.toNT $ mkBoolExpTy tn
|
||||
|
||||
setArgDesc = "sets the columns of the filtered rows to the given values"
|
||||
setArg =
|
||||
InpValInfo (Just setArgDesc) "_set" $ G.toGT $ mkUpdSetTy tn
|
||||
InpValInfo (Just setArgDesc) "_set" Nothing $ G.toGT $ mkUpdSetTy tn
|
||||
|
||||
incArg = maybeToList $ mkIncInpVal tn cols
|
||||
|
||||
@ -993,7 +993,7 @@ mkDelMutFld tn =
|
||||
|
||||
filterArgDesc = "filter the rows which have to be deleted"
|
||||
filterArg =
|
||||
InpValInfo (Just filterArgDesc) "where" $ G.toGT $
|
||||
InpValInfo (Just filterArgDesc) "where" Nothing $ G.toGT $
|
||||
G.toNT $ mkBoolExpTy tn
|
||||
|
||||
-- table_insert_input
|
||||
@ -1057,14 +1057,14 @@ mkRelInsInps
|
||||
mkRelInsInps tn upsertAllowed = [objRelInsInp, arrRelInsInp]
|
||||
where
|
||||
onConflictInpVal =
|
||||
InpValInfo Nothing "on_conflict" $ G.toGT $ mkOnConflictInpTy tn
|
||||
InpValInfo Nothing "on_conflict" Nothing $ G.toGT $ mkOnConflictInpTy tn
|
||||
|
||||
onConflictInp = bool [] [onConflictInpVal] upsertAllowed
|
||||
|
||||
objRelDesc = G.Description $
|
||||
"input type for inserting object relation for remote table " <>> tn
|
||||
|
||||
objRelDataInp = InpValInfo Nothing "data" $ G.toGT $
|
||||
objRelDataInp = InpValInfo Nothing "data" Nothing $ G.toGT $
|
||||
G.toNT $ mkInsInpTy tn
|
||||
objRelInsInp = mkHsraInpTyInfo (Just objRelDesc) (mkObjInsInpTy tn)
|
||||
$ fromInpValL $ objRelDataInp : onConflictInp
|
||||
@ -1072,7 +1072,7 @@ mkRelInsInps tn upsertAllowed = [objRelInsInp, arrRelInsInp]
|
||||
arrRelDesc = G.Description $
|
||||
"input type for inserting array relation for remote table " <>> tn
|
||||
|
||||
arrRelDataInp = InpValInfo Nothing "data" $ G.toGT $
|
||||
arrRelDataInp = InpValInfo Nothing "data" Nothing $ G.toGT $
|
||||
G.toNT $ G.toLT $ G.toNT $ mkInsInpTy tn
|
||||
arrRelInsInp = mkHsraInpTyInfo (Just arrRelDesc) (mkArrInsInpTy tn)
|
||||
$ fromInpValL $ arrRelDataInp : onConflictInp
|
||||
@ -1106,9 +1106,9 @@ mkInsInp tn insCtx =
|
||||
let rty = riType relInfo
|
||||
remoteQT = riRTable relInfo
|
||||
in case rty of
|
||||
ObjRel -> InpValInfo Nothing (G.Name $ getRelTxt relName) $
|
||||
ObjRel -> InpValInfo Nothing (G.Name $ getRelTxt relName) Nothing $
|
||||
G.toGT $ mkObjInsInpTy remoteQT
|
||||
ArrRel -> InpValInfo Nothing (G.Name $ getRelTxt relName) $
|
||||
ArrRel -> InpValInfo Nothing (G.Name $ getRelTxt relName) Nothing $
|
||||
G.toGT $ mkArrInsInpTy remoteQT
|
||||
|
||||
{-
|
||||
@ -1129,10 +1129,10 @@ mkOnConflictInp tn =
|
||||
desc = G.Description $
|
||||
"on conflict condition type for table " <>> tn
|
||||
|
||||
constraintInpVal = InpValInfo Nothing (G.Name "constraint") $
|
||||
constraintInpVal = InpValInfo Nothing (G.Name "constraint") Nothing $
|
||||
G.toGT $ G.toNT $ mkConstraintInpTy tn
|
||||
|
||||
updateColumnsInpVal = InpValInfo Nothing (G.Name "update_columns") $
|
||||
updateColumnsInpVal = InpValInfo Nothing (G.Name "update_columns") Nothing $
|
||||
G.toGT $ G.toNT $ G.toLT $ G.toNT $ mkUpdColumnInpTy tn
|
||||
{-
|
||||
|
||||
@ -1156,14 +1156,14 @@ mkInsMutFld tn isUpsertable =
|
||||
|
||||
objsArgDesc = "the rows to be inserted"
|
||||
objectsArg =
|
||||
InpValInfo (Just objsArgDesc) "objects" $ G.toGT $
|
||||
InpValInfo (Just objsArgDesc) "objects" Nothing $ G.toGT $
|
||||
G.toNT $ G.toLT $ G.toNT $ mkInsInpTy tn
|
||||
|
||||
onConflictInpVal = bool Nothing (Just onConflictArg) isUpsertable
|
||||
|
||||
onConflictDesc = "on conflict condition"
|
||||
onConflictArg =
|
||||
InpValInfo (Just onConflictDesc) "on_conflict" $ G.toGT $ mkOnConflictInpTy tn
|
||||
InpValInfo (Just onConflictDesc) "on_conflict" Nothing $ G.toGT $ mkOnConflictInpTy tn
|
||||
|
||||
mkConstriantTy :: QualifiedTable -> [ConstraintName] -> EnumTyInfo
|
||||
mkConstriantTy tn cons = enumTyInfo
|
||||
@ -1262,7 +1262,7 @@ mkTabAggOpOrdByInpObjs tn numCols compCols =
|
||||
mkInpObjTy cols op = mkHsraInpTyInfo (Just $ mkDesc op) (mkTabAggOpOrdByTy tn op) $
|
||||
fromInpValL $ map mkColInpVal cols
|
||||
|
||||
mkColInpVal c = InpValInfo Nothing (mkColName c) $ G.toGT
|
||||
mkColInpVal c = InpValInfo Nothing (mkColName c) Nothing $ G.toGT
|
||||
ordByTy
|
||||
|
||||
mkTabAggOrdByTy :: QualifiedTable -> G.NamedType
|
||||
@ -1287,10 +1287,10 @@ mkTabAggOrdByInpObj tn numCols compCols =
|
||||
|
||||
numOpOrdBys = bool (map mkInpValInfo numAggOps) [] $ null numCols
|
||||
compOpOrdBys = bool (map mkInpValInfo compAggOps) [] $ null compCols
|
||||
mkInpValInfo op = InpValInfo Nothing op $ G.toGT $
|
||||
mkInpValInfo op = InpValInfo Nothing op Nothing $ G.toGT $
|
||||
mkTabAggOpOrdByTy tn op
|
||||
|
||||
countInpVal = InpValInfo Nothing "count" $ G.toGT ordByTy
|
||||
countInpVal = InpValInfo Nothing "count" Nothing $ G.toGT ordByTy
|
||||
|
||||
mkOrdByTy :: QualifiedTable -> G.NamedType
|
||||
mkOrdByTy tn =
|
||||
@ -1326,14 +1326,14 @@ mkOrdByInpObj tn selFlds = (inpObjTy, ordByCtx)
|
||||
objRels = relFltr ObjRel
|
||||
arrRels = relFltr ArrRel
|
||||
|
||||
mkColOrdBy ci = InpValInfo Nothing (mkColName $ pgiName ci) $
|
||||
mkColOrdBy ci = InpValInfo Nothing (mkColName $ pgiName ci) Nothing $
|
||||
G.toGT ordByTy
|
||||
mkObjRelOrdBy (ri, _, _, _, _) =
|
||||
InpValInfo Nothing (mkRelName $ riName ri) $
|
||||
InpValInfo Nothing (mkRelName $ riName ri) Nothing $
|
||||
G.toGT $ mkOrdByTy $ riRTable ri
|
||||
|
||||
mkArrRelAggOrdBy (ri, isAggAllowed, _, _, _) =
|
||||
let ivi = InpValInfo Nothing (mkAggRelName $ riName ri) $
|
||||
let ivi = InpValInfo Nothing (mkAggRelName $ riName ri) Nothing $
|
||||
G.toGT $ mkTabAggOrdByTy $ riRTable ri
|
||||
in bool Nothing (Just ivi) isAggAllowed
|
||||
|
||||
|
@ -3,6 +3,7 @@ module Hasura.GraphQL.Validate.InputValue
|
||||
, jsonParser
|
||||
, valueParser
|
||||
, constValueParser
|
||||
, pPrintValueC
|
||||
) where
|
||||
|
||||
import Data.Scientific (fromFloatDigits)
|
||||
@ -14,6 +15,7 @@ import Data.Has
|
||||
import qualified Data.Aeson as J
|
||||
import qualified Data.HashMap.Strict as Map
|
||||
import qualified Data.HashMap.Strict.InsOrd as OMap
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Vector as V
|
||||
import qualified Language.GraphQL.Draft.Syntax as G
|
||||
|
||||
@ -134,6 +136,22 @@ valueParser =
|
||||
pScalar (G.VEnum _) = throwVE "unexpected enum for a scalar"
|
||||
pScalar v = pVal =<< toJValue v
|
||||
|
||||
pPrintValueC :: G.ValueConst -> Text
|
||||
pPrintValueC = \case
|
||||
G.VCInt i -> T.pack $ show i
|
||||
G.VCFloat f -> T.pack $ show f
|
||||
G.VCString (G.StringValue t) -> T.pack $ show t
|
||||
G.VCBoolean b -> bool "false" "true" b
|
||||
G.VCNull -> "null"
|
||||
G.VCEnum (G.EnumValue n) -> G.unName n
|
||||
G.VCList (G.ListValueG vals) -> withSquareBraces $ T.intercalate ", " $ map pPrintValueC vals
|
||||
G.VCObject (G.ObjectValueG objs) -> withCurlyBraces $ T.intercalate ", " $ map ppObjFld objs
|
||||
where
|
||||
ppObjFld (G.ObjectFieldG f v) = G.unName f <> ": " <> pPrintValueC v
|
||||
withSquareBraces t = "[" <> t <> "]"
|
||||
withCurlyBraces t = "{" <> t <> "}"
|
||||
|
||||
|
||||
toJValueC :: G.ValueConst -> J.Value
|
||||
toJValueC = \case
|
||||
G.VCInt i -> J.toJSON i
|
||||
@ -145,7 +163,7 @@ toJValueC = \case
|
||||
G.VCList (G.ListValueG vals) ->
|
||||
J.toJSON $ map toJValueC vals
|
||||
G.VCObject (G.ObjectValueG objs) ->
|
||||
J.toJSON . Map.fromList $ map toTup objs
|
||||
J.toJSON . OMap.fromList $ map toTup objs
|
||||
where
|
||||
toTup (G.ObjectFieldG f v) = (f, toJValueC v)
|
||||
|
||||
|
@ -98,10 +98,10 @@ fromEnumTyDef (G.EnumTypeDefinition descM n _ valDefs) loc =
|
||||
|
||||
data InpValInfo
|
||||
= InpValInfo
|
||||
{ _iviDesc :: !(Maybe G.Description)
|
||||
, _iviName :: !G.Name
|
||||
, _iviType :: !G.GType
|
||||
-- TODO, handle default values
|
||||
{ _iviDesc :: !(Maybe G.Description)
|
||||
, _iviName :: !G.Name
|
||||
, _iviDefVal :: !(Maybe G.ValueConst)
|
||||
, _iviType :: !G.GType
|
||||
} deriving (Show, Eq, TH.Lift)
|
||||
|
||||
instance EquatableGType InpValInfo where
|
||||
@ -109,8 +109,8 @@ instance EquatableGType InpValInfo where
|
||||
getEqProps ity = (,) (_iviName ity) (_iviType ity)
|
||||
|
||||
fromInpValDef :: G.InputValueDefinition -> InpValInfo
|
||||
fromInpValDef (G.InputValueDefinition descM n ty _) =
|
||||
InpValInfo descM n ty
|
||||
fromInpValDef (G.InputValueDefinition descM n ty defM) =
|
||||
InpValInfo descM n defM ty
|
||||
|
||||
type ParamMap = Map.HashMap G.Name InpValInfo
|
||||
|
||||
@ -317,8 +317,8 @@ defaultDirectives =
|
||||
[mkDirective "skip", mkDirective "include"]
|
||||
where
|
||||
mkDirective n = DirectiveInfo Nothing n args dirLocs
|
||||
args = Map.singleton "if" $ InpValInfo Nothing "if" $
|
||||
G.TypeNamed (G.Nullability True) $ G.NamedType $ G.Name "Boolean"
|
||||
args = Map.singleton "if" $ InpValInfo Nothing "if" Nothing $
|
||||
G.TypeNamed (G.Nullability False) $ G.NamedType $ G.Name "Boolean"
|
||||
dirLocs = map G.DLExecutable
|
||||
[G.EDLFIELD, G.EDLFRAGMENT_SPREAD, G.EDLINLINE_FRAGMENT]
|
||||
|
||||
|
@ -19,7 +19,7 @@ extra-deps:
|
||||
- git: https://github.com/hasura/pg-client-hs.git
|
||||
commit: f3d1e9e67bdfbfa3de85b7cbdb4c557dce7fd84d
|
||||
- git: https://github.com/hasura/graphql-parser-hs.git
|
||||
commit: 75782ae894cce05ed31e5b87fd696fc10e88baf9
|
||||
commit: ff95d9a96aa5ef9e5390f8712958e4118e3831f6
|
||||
- ginger-0.8.1.0
|
||||
|
||||
# for text-builder
|
||||
|
@ -6,6 +6,8 @@ import graphene
|
||||
|
||||
from webserver import RequestHandler, WebServer, MkHandlers, Response
|
||||
|
||||
from enum import Enum
|
||||
|
||||
def mkJSONResp(graphql_result):
|
||||
return Response(HTTPStatus.OK, graphql_result.to_dict(),
|
||||
{'Content-Type': 'application/json'})
|
||||
@ -151,11 +153,82 @@ class PersonGraphQL(RequestHandler):
|
||||
res = person_schema.execute(req.json['query'])
|
||||
return mkJSONResp(res)
|
||||
|
||||
class InpObjType(graphene.InputObjectType):
|
||||
|
||||
@classmethod
|
||||
def default(cls):
|
||||
meta = cls._meta
|
||||
fields = meta.fields
|
||||
default_fields = {name: field.default_value for name, field in fields.items()}
|
||||
container = meta.container
|
||||
return container(**default_fields)
|
||||
|
||||
class SizeObj(graphene.ObjectType):
|
||||
width = graphene.Int()
|
||||
height = graphene.Float()
|
||||
shape = graphene.String()
|
||||
hasTag = graphene.Boolean()
|
||||
class Color(Enum):
|
||||
RED = 1
|
||||
GREEN = 2
|
||||
BLUE = 3
|
||||
|
||||
GQColorEnum = graphene.Enum.from_enum(Color)
|
||||
|
||||
class SizeInput(InpObjType):
|
||||
width = graphene.Int(default_value=100)
|
||||
height = graphene.Float(default_value=100.1)
|
||||
shape = graphene.String(default_value="cube")
|
||||
hasTag = graphene.Boolean(default_value=False)
|
||||
|
||||
def asSizeObj(self):
|
||||
return SizeObj(width=self.width, height=self.height, shape=self.shape, hasTag=self.hasTag)
|
||||
|
||||
|
||||
class Echo(graphene.ObjectType):
|
||||
intFld = graphene.Int()
|
||||
listFld = graphene.List(graphene.String)
|
||||
objFld = graphene.Field(SizeObj)
|
||||
enumFld = graphene.Field(GQColorEnum)
|
||||
|
||||
class EchoQuery(graphene.ObjectType):
|
||||
echo = graphene.Field(
|
||||
Echo,
|
||||
int_input=graphene.Int( default_value=1234),
|
||||
list_input=graphene.Argument(graphene.List(graphene.String), default_value=["hi","there"]),
|
||||
obj_input=graphene.Argument(SizeInput, default_value=SizeInput.default()),
|
||||
enum_input=graphene.Argument(GQColorEnum, default_value=GQColorEnum.RED.name),
|
||||
)
|
||||
|
||||
def resolve_echo(self, info, int_input, list_input, obj_input, enum_input):
|
||||
#print (int_input, list_input, obj_input)
|
||||
return Echo(intFld=int_input, listFld=list_input, objFld=obj_input, enumFld=enum_input)
|
||||
|
||||
echo_schema = graphene.Schema(query=EchoQuery)
|
||||
|
||||
class EchoGraphQL(RequestHandler):
|
||||
def get(self, req):
|
||||
return Response(HTTPStatus.METHOD_NOT_ALLOWED)
|
||||
def post(self, req):
|
||||
if not req.json:
|
||||
return Response(HTTPStatus.BAD_REQUEST)
|
||||
res = echo_schema.execute(req.json['query'])
|
||||
respDict = res.to_dict()
|
||||
typesList = respDict.get('data',{}).get('__schema',{}).get('types',None)
|
||||
if typesList is not None:
|
||||
for t in filter(lambda ty: ty['name'] == 'EchoQuery', typesList):
|
||||
for f in filter(lambda fld: fld['name'] == 'echo', t['fields']):
|
||||
for a in filter(lambda arg: arg['name'] == 'enumInput', f['args']):
|
||||
a['defaultValue'] = 'RED'
|
||||
return Response(HTTPStatus.OK, respDict,
|
||||
{'Content-Type': 'application/json'})
|
||||
|
||||
handlers = MkHandlers({
|
||||
'/hello': HelloWorldHandler,
|
||||
'/hello-graphql': HelloGraphQL,
|
||||
'/user-graphql': UserGraphQL,
|
||||
'/country-graphql': CountryGraphQL,
|
||||
'/default-value-echo-graphql' : EchoGraphQL,
|
||||
'/person-graphql': PersonGraphQL
|
||||
})
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
import requests
|
||||
|
||||
from validate import check_query_f, check_query
|
||||
|
||||
@ -19,6 +20,14 @@ def mk_add_remote_q(name, url):
|
||||
}
|
||||
}
|
||||
|
||||
def mk_delete_remote_q(name):
|
||||
return {
|
||||
"type" : "remove_remote_schema",
|
||||
"args" : {
|
||||
"name": name
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TestRemoteSchemaBasic:
|
||||
""" basic => no hasura tables are tracked """
|
||||
@ -156,6 +165,62 @@ class TestAddRemoteSchemaTbls:
|
||||
hge_ctx.v1q({"type": "remove_remote_schema", "args": {"name": "person-graphql"}})
|
||||
assert st_code == 200, resp
|
||||
|
||||
|
||||
class TestAddRemoteSchemaCompareRootQueryFields:
|
||||
|
||||
remote = 'http://localhost:5000/default-value-echo-graphql'
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def transact(self, hge_ctx):
|
||||
st_code, resp = hge_ctx.v1q(mk_add_remote_q('default_value_test', self.remote))
|
||||
assert st_code == 200, resp
|
||||
yield
|
||||
st_code, resp = hge_ctx.v1q(mk_delete_remote_q('default_value_test'))
|
||||
assert st_code == 200, resp
|
||||
|
||||
def test_schema_check_arg_default_values_and_field_and_arg_types(self, hge_ctx):
|
||||
with open('queries/graphql_introspection/introspection.yaml') as f:
|
||||
query = yaml.load(f)
|
||||
st_code, introspect_hasura = check_query(hge_ctx, query)
|
||||
assert st_code == 200, introspect_hasura
|
||||
resp = requests.post(
|
||||
self.remote,
|
||||
json=query['query']
|
||||
)
|
||||
introspect_remote = resp.json()
|
||||
assert resp.status_code == 200, introspect_remote
|
||||
remote_root_ty_info = get_query_root_info(introspect_remote)
|
||||
hasura_root_ty_Info = get_query_root_info(introspect_hasura)
|
||||
hasFld=dict()
|
||||
for fr in remote_root_ty_info['fields']:
|
||||
hasFld[fr['name']] = False
|
||||
for fh in filter(lambda f: f['name'] == fr['name'], hasura_root_ty_Info['fields']):
|
||||
hasFld[fr['name']] = True
|
||||
assert fr['type'] == fh['type'], yaml.dump({
|
||||
'error' : 'Types do not match for fld ' + fr['name'],
|
||||
'remote_type' : fr['type'],
|
||||
'hasura_type' : fh['type']
|
||||
})
|
||||
hasArg=dict()
|
||||
for ar in fr['args']:
|
||||
arPath = fr['name'] + '(' + ar['name'] + ':)'
|
||||
hasArg[arPath] = False
|
||||
for ah in filter(lambda a: a['name'] == ar['name'], fh['args']):
|
||||
hasArg[arPath] = True
|
||||
assert ar['type'] == ah['type'], yaml.dump({
|
||||
'error' : 'Types do not match for arg ' + arPath,
|
||||
'remote_type' : ar['type'],
|
||||
'hasura_type' : ah['type']
|
||||
})
|
||||
assert ar['defaultValue'] == ah['defaultValue'], yaml.dump({
|
||||
'error' : 'Default values do not match for arg ' + arPath,
|
||||
'remote_default_value' : ar['defaultValue'],
|
||||
'hasura_default_value' : ah['defaultValue']
|
||||
})
|
||||
assert hasArg[arPath], 'Argument ' + arPath + ' in the remote schema root query type not found in Hasura schema'
|
||||
assert hasFld[fr['name']], 'Field ' + fr['name'] + ' in the remote shema root query type not found in Hasura schema'
|
||||
|
||||
|
||||
# def test_remote_query_variables(self, hge_ctx):
|
||||
# pass
|
||||
# def test_add_schema_url_from_env(self, hge_ctx):
|
||||
@ -170,6 +235,13 @@ def _map(f, l):
|
||||
def _filter(f, l):
|
||||
return list(filter(f, l))
|
||||
|
||||
def get_query_root_info(res):
|
||||
root_ty_name = res['data']['__schema']['queryType']['name']
|
||||
return list(filter(lambda ty: ty['name'] == root_ty_name, get_types(res) ))[0]
|
||||
|
||||
def get_types(res):
|
||||
return res['data']['__schema']['types']
|
||||
|
||||
def check_introspection_result(res, types, node_names):
|
||||
all_types = _map(lambda t: t['name'], res['data']['__schema']['types'])
|
||||
print(all_types)
|
||||
|
@ -101,11 +101,27 @@ def MkHandlers(handlers):
|
||||
self.send_response(resp.status)
|
||||
if resp.headers:
|
||||
self.append_headers(resp.headers)
|
||||
#Required for graphiql to work with the graphQL test server
|
||||
self.send_header('Access-Control-Allow-Origin', self.headers['Origin'])
|
||||
self.send_header('Access-Control-Allow-Credentials', 'true')
|
||||
self.send_header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS')
|
||||
self.end_headers()
|
||||
self.wfile.write(resp.get_body().encode('utf-8'))
|
||||
except KeyError:
|
||||
self.not_found()
|
||||
|
||||
def do_OPTIONS(self):
|
||||
self.send_response(204)
|
||||
#Required for graphiql to work with the graphQL test server
|
||||
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
|
||||
self.send_header('Access-Control-Max-Age', '1728000')
|
||||
self.send_header('Access-Control-Allow-Headers', 'content-type,x-apollo-tracing')
|
||||
self.send_header('Content-Type', 'text/plain charset=UTF-8')
|
||||
self.send_header('Access-Control-Allow-Credentials', 'true')
|
||||
self.send_header('Access-Control-Allow-Origin', self.headers['Origin'])
|
||||
self.send_header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS')
|
||||
self.end_headers()
|
||||
|
||||
return HTTPHandler
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user