Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better support for Postgres Arrays #1767

Closed
wants to merge 10 commits into from
Prev Previous commit
Next Next commit
Fix errors on adding function etc
  • Loading branch information
nizar-m committed Mar 13, 2019
commit 92fd747022e47f7fca7664b2f84abfc77b1abd94
54 changes: 35 additions & 19 deletions server/src-lib/Hasura/GraphQL/Context.hs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ mkHsraObjFldInfo
mkHsraObjFldInfo descM name params pgTy ty =
ObjFldInfo descM name params pgTy ty HasuraType

mkHsraPGTyObjFld :: Maybe G.Description -> G.Name -> ParamMap -> PGColType -> ObjFldInfo
mkHsraPGTyObjFld descM name params colTy =
mkHsraObjFldInfo descM name params (Just $ PTCol colTy) $ mkPGColGTy colTy

mkHsraObjTyInfo
:: Maybe G.Description
-> G.NamedType
Expand Down Expand Up @@ -173,8 +177,19 @@ fromInpValL :: [InpValInfo] -> Map.HashMap G.Name InpValInfo
fromInpValL = mapFromL _iviName

mkCompExpName :: PGColType -> G.Name
mkCompExpName pgColTy =
G.Name $ pgColTyToScalar pgColTy <> "_comparison_exp"
mkCompExpName colTy =
G.Name $ colTyTxt colTy <> "_comparison_exp"
where
colTyTxt t = case pgColTyDetails t of
PGTyBase b
-> T.pack (show b)
PGTyDomain b
-> colTyTxt b
_
-> case getArrayBaseTy t of
Nothing -> qualTyToScalar (pgColTyName t)
-- Array type
Just b -> T.pack $ show b <> "_" <> show (getPGTyArrDim t) <> "d"

mkCompExpTy :: PGColType -> G.NamedType
mkCompExpTy =
Expand All @@ -195,12 +210,12 @@ stDWithinInpTy = G.NamedType "st_d_within_input"
mkCompExpInp :: PGColType -> InpObjTyInfo
mkCompExpInp colTy@(PGColType _ _ _ colDtls) =
InpObjTyInfo (Just tyDesc) (mkCompExpTy colTy) (fromInpValL $ concat
[ map (mk (Just $ PTCol colTy) colGQLTy) typedOps
[ map (mkPGTy colTy) typedOps
, map (mk (Just $ arrOfCol colTy) $ G.toLT colGQLTy) listOps
, bool [] (map (mk (Just $ PTCol $ baseBuiltInTy PGText) $ mkScalarBaseTy PGText) stringOps) isStringTy
, bool [] (map (mkPGTy $ baseTy PGText) stringOps) isStringTy
, bool [] (map jsonbOpToInpVal jsonbOps) isJsonbTy
, bool [] (stDWithinOpInpVal : map geomOpToInpVal geomOps) isGeometryTy
, [InpValInfo Nothing "_is_null" Nothing (Just $ PTCol $ baseBuiltInTy PGBoolean) $ G.TypeNamed (G.Nullability True) $ G.NamedType "Boolean"]
, [mkPGTyInpVal Nothing "_is_null" $ baseTy PGBoolean]
]) HasuraType
where
arrOfCol = PTArr . PTCol
Expand All @@ -209,14 +224,15 @@ mkCompExpInp colTy@(PGColType _ _ _ colDtls) =
, G.Description (T.pack $ show colTy)
, ". All fields are combined with logical 'AND'."
]
baseTy = case colDtls of
bTy = case colDtls of
PGTyBase b -> return b
_ -> Nothing
isStringTy = case baseTy of
isStringTy = case bTy of
Just PGVarchar -> True
Just PGText -> True
_ -> False
mk pt t n = InpValInfo Nothing n Nothing pt $ G.toGT t
mkPGTy ty = mk (Just $ PTCol ty) $ mkPGColGTy ty
colGQLTy = mkPGColGTy colTy
-- colScalarListTy = GA.GTList colGTy
typedOps =
Expand All @@ -231,45 +247,45 @@ mkCompExpInp colTy@(PGColType _ _ _ colDtls) =
, "_similar", "_nsimilar"
]

isJsonbTy = case baseTy of
isJsonbTy = case bTy of
Just PGJSONB -> True
_ -> False
jsonbOpToInpVal (op, ty, desc) = InpValInfo (Just desc) op Nothing (Just $ PTCol $ baseBuiltInTy PGJSONB) ty
jsonbOpToInpVal (op, pgTy, desc) = InpValInfo (Just desc) op Nothing (Just pgTy) $ pgTyAnnToGTy pgTy
jsonbOps =
[ ( "_contains"
, G.toGT $ mkScalarBaseTy PGJSONB
, PTCol $ baseTy PGJSONB
, "does the column contain the given json value at the top level"
)
, ( "_contained_in"
, G.toGT $ mkScalarBaseTy PGJSONB
, PTCol $ baseTy PGJSONB
, "is the column contained in the given json value"
)
, ( "_has_key"
, G.toGT $ mkScalarBaseTy PGText
, PTCol $ baseTy PGText
, "does the string exist as a top-level key in the column"
)
, ( "_has_keys_any"
, G.toGT $ G.toLT $ G.toNT $ mkScalarBaseTy PGText
, PTArr $ PTCol $ baseTy PGText
, "do any of these strings exist as top-level keys in the column"
)
, ( "_has_keys_all"
, G.toGT $ G.toLT $ G.toNT $ mkScalarBaseTy PGText
, PTArr $ PTCol $ baseTy PGText
, "do all of these strings exist as top-level keys in the column"
)
]

-- Geometry related ops
stDWithinOpInpVal =
InpValInfo (Just stDWithinDesc) "_st_d_within" Nothing (Just $ PTCol $ baseBuiltInTy PGGeometry) $ G.toGT stDWithinInpTy
InpValInfo (Just stDWithinDesc) "_st_d_within" Nothing Nothing $ G.toGT stDWithinInpTy
stDWithinDesc =
"is the column within a distance from a geometry value"

isGeometryTy = case baseTy of
isGeometryTy = case bTy of
Just PGGeometry -> True
_ -> False

geomOpToInpVal (op, desc) =
InpValInfo (Just desc) op Nothing (Just $ PTCol $ baseBuiltInTy PGGeometry) $ G.toGT $ mkScalarBaseTy PGGeometry
mkPGTyInpVal (Just desc) op $ baseTy PGGeometry
geomOps =
[
( "_st_contains"
Expand Down Expand Up @@ -376,8 +392,8 @@ mkGCtx tyAgg (RootFlds flds) insCtxMap =
stDWithinInpM = bool Nothing (Just stDWithinInp) (PGTyBase PGGeometry `elem` map pgColTyDetails colTys)
stDWithinInp =
mkHsraInpTyInfo Nothing stDWithinInpTy $ fromInpValL
[ InpValInfo Nothing "from" Nothing (Just $ PTCol $ baseBuiltInTy PGGeometry) $ G.toGT $ G.toNT $ mkScalarBaseTy PGGeometry
, InpValInfo Nothing "distance" Nothing (Just $ PTCol $ baseBuiltInTy PGGeometry) $ G.toNT $ G.toNT $ mkScalarBaseTy PGFloat
[ mkPGTyInpValNT Nothing "from" $ baseTy PGGeometry
, mkPGTyInpValNT Nothing "distance" $ baseTy PGFloat
]

emptyGCtx :: GCtx
Expand Down
34 changes: 16 additions & 18 deletions server/src-lib/Hasura/GraphQL/Schema.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{-# LANGUAGE TemplateHaskell #-}
module Hasura.GraphQL.Schema
( mkGCtxMap
, GCtxMap
Expand Down Expand Up @@ -185,8 +186,8 @@ mkPGColFld (PGColInfo colName colTy isNullable) =
mkSelArgs :: QualifiedTable -> [InpValInfo]
mkSelArgs tn =
[ InpValInfo (Just whereDesc) "where" Nothing Nothing $ G.toGT $ mkBoolExpTy tn
, InpValInfo (Just limitDesc) "limit" Nothing Nothing $ G.toGT $ mkScalarBaseTy PGInteger
, InpValInfo (Just offsetDesc) "offset" Nothing Nothing $ G.toGT $ mkScalarBaseTy PGInteger
, mkPGTyInpVal (Just limitDesc) "limit" $ baseTy PGInteger
, mkPGTyInpVal (Just offsetDesc) "offset" $ baseTy PGInteger
, InpValInfo (Just orderByDesc) "order_by" Nothing Nothing $ G.toGT $ G.toLT $ G.toNT $
mkOrdByTy tn
, InpValInfo (Just distinctDesc) "distinct_on" Nothing Nothing $ G.toGT $ G.toLT $
Expand Down Expand Up @@ -322,13 +323,13 @@ mkTableAggFldsObj tn numCols compCols =
desc = G.Description $
"aggregate fields of " <>> tn

countFld = mkHsraObjFldInfo Nothing "count" countParams (Just $ PTCol $ baseBuiltInTy PGInteger) $ G.toGT $ mkScalarBaseTy PGInteger
countFld = mkHsraPGTyObjFld Nothing "count" countParams $ baseTy PGInteger

countParams = fromInpValL [countColInpVal, distinctInpVal]

countColInpVal = InpValInfo Nothing "columns" Nothing Nothing $ G.toGT $
G.toLT $ G.toNT $ mkSelColumnInpTy tn
distinctInpVal = InpValInfo Nothing "distinct" Nothing (Just $ PTCol $ baseBuiltInTy PGBoolean) $ G.toGT $ mkScalarBaseTy PGBoolean
distinctInpVal = mkPGTyInpVal Nothing "distinct" $ baseTy PGBoolean

numFlds = bool (map mkColOpFld numAggOps) [] $ null numCols
compFlds = bool (map mkColOpFld compAggOps) [] $ null compCols
Expand All @@ -346,7 +347,7 @@ type table_<agg-op>_fields{
mkTableColAggFldsObj
:: QualifiedTable
-> G.Name
-> (PGColType -> G.NamedType)
-> (PGColType -> PGColType)
-> [PGColInfo]
-> ObjTyInfo
mkTableColAggFldsObj tn op f cols =
Expand All @@ -356,8 +357,8 @@ mkTableColAggFldsObj tn op f cols =
desc = G.Description $ "aggregate " <> G.unName op <> " on columns"

mkColObjFld c = let colTy = pgiType c in
mkHsraObjFldInfo Nothing (G.Name $ getPGColTxt $ pgiName c)
Map.empty (Just $ PTCol colTy) $ G.toGT $ f colTy
mkHsraPGTyObjFld Nothing (G.Name $ getPGColTxt $ pgiName c)
Map.empty $ f colTy

{-

Expand Down Expand Up @@ -511,8 +512,7 @@ mkMutRespObj tn sel nestAlwd =
objDesc = G.Description $
"response of any mutation on the table " <>> tn
affectedRowsFld =
mkHsraObjFldInfo (Just desc) "affected_rows" Map.empty (Just $ PTCol $ baseBuiltInTy PGInteger) $
G.toGT $ G.toNT $ mkScalarBaseTy PGInteger
mkHsraPGTyObjFld (Just desc) "affected_rows" Map.empty $ baseTy PGInteger
where
desc = "number of affected rows by the mutation"
returningFld =
Expand Down Expand Up @@ -752,20 +752,18 @@ 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) Nothing (Just $ PTCol $ baseBuiltInTy PGText) $
G.toGT $ G.NamedType "String"
deleteKeyInpVal c = mkPGTyInpVal Nothing (G.Name $ getPGColTxt c) $ baseTy PGText

deleteElemInpObj =
mkHsraInpTyInfo (Just deleteElemDesc) (mkJSONOpTy tn deleteElemOp) $
fromInpValL $ map deleteElemInpVal jsonbColNames
deleteElemInpVal c = InpValInfo Nothing (G.Name $ getPGColTxt c) Nothing (Just $ PTCol $ baseBuiltInTy PGInteger) $
G.toGT $ G.NamedType "Int"
deleteElemInpVal c = mkPGTyInpVal Nothing (G.Name $ getPGColTxt c) $ baseTy PGInteger

deleteAtPathInpObj =
mkHsraInpTyInfo (Just deleteAtPathDesc) (mkJSONOpTy tn deleteAtPathOp) $
fromInpValL $ map deleteAtPathInpVal jsonbColNames
deleteAtPathInpVal c = InpValInfo Nothing (G.Name $ getPGColTxt c) Nothing (Just $ PTCol $ baseBuiltInTy PGText) $
G.toGT $ G.toLT $ G.NamedType "String"
deleteAtPathInpVal c = InpValInfo Nothing (G.Name $ getPGColTxt c) Nothing (Just $ PTArr $ PTCol $ baseTy PGText) $
G.toGT $ G.toLT $ mkPGColGTy $ baseTy PGText

{-

Expand Down Expand Up @@ -1401,16 +1399,16 @@ mkGCtxRole' tn allCols insPermM selPermM updColsM

getNumCols = onlyNumCols . lefts
getCompCols = onlyComparableCols . lefts
onlyFloat = const $ mkScalarBaseTy PGFloat
onlyFloat = const $ baseTy PGFloat

mkTypeMaker "sum" = mkScalarTy
mkTypeMaker "sum" = id
mkTypeMaker _ = onlyFloat

mkColAggFldsObjs flds =
let numCols = getNumCols flds
compCols = getCompCols flds
mkNumObjFld n = mkTableColAggFldsObj tn n (mkTypeMaker n) numCols
mkCompObjFld n = mkTableColAggFldsObj tn n mkScalarTy compCols
mkCompObjFld n = mkTableColAggFldsObj tn n id compCols
numFldsObjs = bool (map mkNumObjFld numAggOps) [] $ null numCols
compFldsObjs = bool (map mkCompObjFld compAggOps) [] $ null compCols
in numFldsObjs <> compFldsObjs
Expand Down
28 changes: 12 additions & 16 deletions server/src-lib/Hasura/GraphQL/Validate.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module Hasura.GraphQL.Validate

import Data.Has
import Hasura.Prelude
import Data.Aeson.Internal (JSONPathElement(..))

import qualified Data.HashMap.Strict as Map
import qualified Language.GraphQL.Draft.Syntax as G
Expand Down Expand Up @@ -61,7 +62,7 @@ getVarVals
)
=> [G.VariableDefinition]
-> VariableValues
-> m VarVals
-> m VarValsMap
getVarVals varDefsL inpVals = do

varDefs <- onLeft (mkMapWith G._vdVariable varDefsL) $ \dups ->
Expand All @@ -80,20 +81,10 @@ getVarVals varDefsL inpVals = do
-- check that the variable is defined on input types
when (isObjTy baseTyInfo) $ throwVE $ objTyErrMsg baseTy

let defM' = bool (defM <|> Just G.VCNull) defM $ G.isNotNull ty
let defM' = bool defM (defM <|> Just G.VCNull) $ G.isNotNull ty
let inpValM = Map.lookup var inpVals
when (isNothing inpValM && isNothing defM') $ throwVE $ "expecting a value for non-null type: " <> G.showGT ty <> " in variableValues"
when (isNothing inpValM && isNothing defM' && G.isNotNull ty) $ throwVE $ "expecting a value for non-null type: " <> G.showGT ty <> " in variableValues"
return (ty,defM',inpValM)
--let annValF pgTy = do
-- annDefM <- withPathK "defaultValue" $
-- mapM (validateInputValue constValueParser ty pgTy) defM'

-- annInpValM <- withPathK "variableValues" $
-- mapM (validateInputValue jsonParser ty pgTy) inpValM

-- let annValM = annInpValM <|> annDefM
-- onNothing annValM $ throwVE $ "expecting a value for non-null type: " <> G.showGT ty <> " in variableValues"
--return annValF
where
objTyErrMsg namedTy =
"variables can only be defined on input types"
Expand Down Expand Up @@ -135,7 +126,7 @@ validateGQ (QueryParts opDef opRoot fragDefsL varValsM) = do
-- onNothing (_gSubRoot ctx) $ throwVE "no subscriptions exist"

-- annotate the variables of this operation
annVarVals <- getVarVals (G._todVariableDefinitions opDef) $
varVals <- getVarVals (G._todVariableDefinitions opDef) $
fromMaybe Map.empty varValsM

-- annotate the fragments
Expand All @@ -145,16 +136,21 @@ validateGQ (QueryParts opDef opRoot fragDefsL varValsM) = do
annFragDefs <- mapM validateFrag fragDefs

-- build a validation ctx
let valCtx = ValidationCtx (_gTypes ctx) annVarVals annFragDefs
let valCtx = ValidationCtx (_gTypes ctx) varVals annFragDefs

selSet <- flip runReaderT valCtx $ denormSelSet [] opRoot $
selSet <- flip runReaderT valCtx $ pathFromRoot $ denormSelSet [] opRoot $
G._todSelectionSet opDef

when (G._todType opDef == G.OperationTypeSubscription && length selSet > 1) $
throwVE "subscription must select only one top level field"

return (G._todType opDef, selSet)

pathFromRoot :: (MonadError QErr m) => m a -> m a
pathFromRoot f = f `catchError` (throwError . fromRoot)
where
fromRoot q = q { qePath = frp $ qePath q}
where frp = reverse . takeWhile (/= Key "$") . reverse

getQueryParts
:: ( MonadError QErr m, MonadReader GCtx m)
Expand Down
2 changes: 1 addition & 1 deletion server/src-lib/Hasura/GraphQL/Validate/Context.hs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ data ValidationCtx
= ValidationCtx
{ _vcTypeMap :: !TypeMap
-- these are in the scope of the operation
, _vcVarVals :: !VarVals
, _vcVarVals :: !VarValsMap
-- all the fragments
, _vcFragDefMap :: !FragDefMap
} deriving (Show, Eq)
Expand Down
2 changes: 1 addition & 1 deletion server/src-lib/Hasura/GraphQL/Validate/Field.hs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ processArgs fldParams argsL = do
inpArgs <- forM args $ \(G.Argument argName argVal) ->
withPathK (G.unName argName) $ do
argTy <- getArgTy argName
validateInputValue (valueParser $ _iviPGTyAnn argTy) (_iviType argTy) (_iviPGTyAnn argTy) argVal
validateInputValue valueParser (_iviType argTy) (_iviPGTyAnn argTy) argVal

forM_ requiredParams $ \argDef -> do
let param = _iviName argDef
Expand Down
Loading