diff --git a/server/src-lib/Hasura/GraphQL/Resolve/BoolExp.hs b/server/src-lib/Hasura/GraphQL/Resolve/BoolExp.hs index 524fbcad014..c307cd37d73 100644 --- a/server/src-lib/Hasura/GraphQL/Resolve/BoolExp.hs +++ b/server/src-lib/Hasura/GraphQL/Resolve/BoolExp.hs @@ -83,10 +83,11 @@ parseOpExps annVal = do parseAsSTDWithinObj obj = do distanceVal <- onNothing (OMap.lookup "distance" obj) $ throw500 "expected \"distance\" input field in st_d_within_input ty" - distSQL <- uncurry toTxtValue <$> asPGColVal distanceVal + dist <- asPGColVal distanceVal fromVal <- onNothing (OMap.lookup "from" obj) $ throw500 "expected \"from\" input field in st_d_within_input ty" - ASTDWithin distSQL <$> asPGColVal fromVal + from <- asPGColVal fromVal + return $ ASTDWithin $ WithinOp dist from parseAsEqOp :: (MonadError QErr m) diff --git a/server/src-lib/Hasura/RQL/DDL/Permission/Internal.hs b/server/src-lib/Hasura/RQL/DDL/Permission/Internal.hs index b76e4ac0547..5c65e13070f 100644 --- a/server/src-lib/Hasura/RQL/DDL/Permission/Internal.hs +++ b/server/src-lib/Hasura/RQL/DDL/Permission/Internal.hs @@ -20,6 +20,7 @@ import Hasura.RQL.GBoolExp import Hasura.RQL.Types import Hasura.Server.Utils import Hasura.SQL.Types +import Hasura.SQL.Value (withGeoVal) import qualified Database.PG.Query as Q import qualified Hasura.SQL.DML as S @@ -182,10 +183,7 @@ getDependentHeaders (BoolExp boolExp) = | otherwise -> [] _ -> [] parseObject o = - concatMap parseOnlyString (M.elems o) - -- if isRQLOp k - -- then parseOnlyString v - -- else [] + concatMap parseValue (M.elems o) valueParser :: (MonadError QErr m) => PGColType -> Value -> m S.SQLExp valueParser columnType = \case @@ -198,9 +196,9 @@ valueParser columnType = \case val -> txtRHSBuilder columnType val where curSess = S.SEUnsafe "current_setting('hasura.user')::json" - fromCurSess hdr = + fromCurSess hdr = withAnnTy $ withGeoVal columnType $ S.SEOpApp (S.SQLOp "->>") [curSess, S.SELit $ T.toLower hdr] - `S.SETyAnn` (S.AnnType $ T.pack $ show columnType) + withAnnTy v = S.SETyAnn v $ S.AnnType $ T.pack $ show columnType injectDefaults :: QualifiedTable -> QualifiedTable -> Q.Query injectDefaults qv qt = diff --git a/server/src-lib/Hasura/RQL/GBoolExp.hs b/server/src-lib/Hasura/RQL/GBoolExp.hs index ed5d22260fb..cb1e3d2e192 100644 --- a/server/src-lib/Hasura/RQL/GBoolExp.hs +++ b/server/src-lib/Hasura/RQL/GBoolExp.hs @@ -24,75 +24,111 @@ parseOpExp -> FieldInfoMap -> PGColInfo -> (T.Text, Value) -> m (OpExpG a) -parseOpExp parser fim (PGColInfo cn colTy _) (opStr, val) = case opStr of - "$eq" -> parseEq - "_eq" -> parseEq +parseOpExp parser fim (PGColInfo cn colTy _) (opStr, val) = withErrPath $ + case opStr of + "$eq" -> parseEq + "_eq" -> parseEq - "$ne" -> parseNe - "_ne" -> parseNe - "$neq" -> parseNe - "_neq" -> parseNe + "$ne" -> parseNe + "_ne" -> parseNe + "$neq" -> parseNe + "_neq" -> parseNe - "$in" -> parseIn - "_in" -> parseIn + "$in" -> parseIn + "_in" -> parseIn - "$nin" -> parseNin - "_nin" -> parseNin + "$nin" -> parseNin + "_nin" -> parseNin - "$gt" -> parseGt - "_gt" -> parseGt + "$gt" -> parseGt + "_gt" -> parseGt - "$lt" -> parseLt - "_lt" -> parseLt + "$lt" -> parseLt + "_lt" -> parseLt - "$gte" -> parseGte - "_gte" -> parseGte + "$gte" -> parseGte + "_gte" -> parseGte - "$lte" -> parseLte - "_lte" -> parseLte + "$lte" -> parseLte + "_lte" -> parseLte - "$like" -> parseLike - "_like" -> parseLike + "$like" -> parseLike + "_like" -> parseLike - "$nlike" -> parseNlike - "_nlike" -> parseNlike + "$nlike" -> parseNlike + "_nlike" -> parseNlike - "$ilike" -> parseIlike - "_ilike" -> parseIlike + "$ilike" -> parseIlike + "_ilike" -> parseIlike - "$nilike" -> parseNilike - "_nilike" -> parseNilike + "$nilike" -> parseNilike + "_nilike" -> parseNilike - "$similar" -> parseSimilar - "_similar" -> parseSimilar - "$nsimilar" -> parseNsimilar - "_nsimilar" -> parseNsimilar + "$similar" -> parseSimilar + "_similar" -> parseSimilar + "$nsimilar" -> parseNsimilar + "_nsimilar" -> parseNsimilar - "$is_null" -> parseIsNull - "_is_null" -> parseIsNull + "$is_null" -> parseIsNull + "_is_null" -> parseIsNull - "$ceq" -> parseCeq - "_ceq" -> parseCeq + -- jsonb type + "_contains" -> jsonbOnlyOp $ AContains <$> parseOne + "$contains" -> jsonbOnlyOp $ AContains <$> parseOne + "_contained_in" -> jsonbOnlyOp $ AContainedIn <$> parseOne + "$contained_in" -> jsonbOnlyOp $ AContainedIn <$> parseOne + "_has_key" -> jsonbOnlyOp $ AHasKey <$> parseWithTy PGText + "$has_key" -> jsonbOnlyOp $ AHasKey <$> parseWithTy PGText - "$cne" -> parseCne - "_cne" -> parseCne - "$cneq" -> parseCne - "_cneq" -> parseCne + --FIXME:- Parse a session variable as text array values + --TODO:- Add following commented operators after fixing above said + -- "_has_keys_any" -> jsonbOnlyOp $ AHasKeysAny <$> parseVal + -- "$has_keys_any" -> jsonbOnlyOp $ AHasKeysAny <$> parseVal + -- "_has_keys_all" -> jsonbOnlyOp $ AHasKeysAll <$> parseVal + -- "$has_keys_all" -> jsonbOnlyOp $ AHasKeysAll <$> parseVal - "$cgt" -> parseCgt - "_cgt" -> parseCgt + -- geometry type + "_st_contains" -> parseGeometryOp ASTContains + "$st_contains" -> parseGeometryOp ASTContains + "_st_crosses" -> parseGeometryOp ASTCrosses + "$st_crosses" -> parseGeometryOp ASTCrosses + "_st_equals" -> parseGeometryOp ASTEquals + "$st_equals" -> parseGeometryOp ASTEquals + "_st_intersects" -> parseGeometryOp ASTIntersects + "$st_intersects" -> parseGeometryOp ASTIntersects + "_st_overlaps" -> parseGeometryOp ASTOverlaps + "$st_overlaps" -> parseGeometryOp ASTOverlaps + "_st_touches" -> parseGeometryOp ASTTouches + "$st_touches" -> parseGeometryOp ASTTouches + "_st_within" -> parseGeometryOp ASTWithin + "$st_within" -> parseGeometryOp ASTWithin + "_st_d_within" -> parseSTDWithinObj + "$st_d_within" -> parseSTDWithinObj - "$clt" -> parseClt - "_clt" -> parseClt + "$ceq" -> parseCeq + "_ceq" -> parseCeq - "$cgte" -> parseCgte - "_cgte" -> parseCgte + "$cne" -> parseCne + "_cne" -> parseCne + "$cneq" -> parseCne + "_cneq" -> parseCne - "$clte" -> parseClte - "_clte" -> parseClte + "$cgt" -> parseCgt + "_cgt" -> parseCgt - x -> throw400 UnexpectedPayload $ "Unknown operator : " <> x + "$clt" -> parseClt + "_clt" -> parseClt + + "$cgte" -> parseCgte + "_cgte" -> parseCgte + + "$clte" -> parseClte + "_clte" -> parseClte + + x -> throw400 UnexpectedPayload $ "Unknown operator : " <> x where + withErrPath = withPathK (getPGColTxt cn) . withPathK opStr + parseEq = AEQ False <$> parseOne -- equals parseNe = ANE False <$> parseOne -- <> parseIn = AIN <$> parseMany -- in an array @@ -109,7 +145,8 @@ parseOpExp parser fim (PGColInfo cn colTy _) (opStr, val) = case opStr of parseNsimilar = textOnlyOp colTy >> ANSIMILAR <$> parseOne parseIsNull = bool ANISNOTNULL ANISNULL -- is null - <$> decodeValue val + <$> parseVal + parseCeq = CEQ <$> decodeAndValidateRhsCol parseCne = CNE <$> decodeAndValidateRhsCol parseCgt = CGT <$> decodeAndValidateRhsCol @@ -117,8 +154,21 @@ parseOpExp parser fim (PGColInfo cn colTy _) (opStr, val) = case opStr of parseCgte = CGTE <$> decodeAndValidateRhsCol parseClte = CLTE <$> decodeAndValidateRhsCol + jsonbOnlyOp m = case colTy of + PGJSONB -> m + ty -> throwError $ buildMsg ty [PGJSONB] + + parseGeometryOp f = + geometryOnlyOp colTy >> f <$> parseOne + + parseSTDWithinObj = do + WithinOp distVal fromVal <- parseVal + dist <- withPathK "distance" $ parser PGFloat distVal + from <- withPathK "from" $ parser colTy fromVal + return $ ASTDWithin $ WithinOp dist from + decodeAndValidateRhsCol = - decodeValue val >>= validateRhsCol + parseVal >>= validateRhsCol validateRhsCol rhsCol = do let errMsg = "column operators can only compare postgres columns" @@ -128,11 +178,19 @@ parseOpExp parser fim (PGColInfo cn colTy _) (opStr, val) = case opStr of "incompatible column types : " <> cn <<> ", " <>> rhsCol else return rhsCol - parseOne = parser colTy val + geometryOnlyOp PGGeometry = return () + geometryOnlyOp ty = + throwError $ buildMsg ty [PGGeometry] + + parseWithTy ty = parser ty val + parseOne = parseWithTy colTy parseMany = do vals <- runAesonParser parseJSON val indexedForM vals (parser colTy) + parseVal :: (FromJSON a, QErrM m) => m a + parseVal = decodeValue val + parseOpExps :: (MonadError QErr m) => ValueParser m a @@ -197,8 +255,8 @@ annColExp valueParser colInfoMap (ColExp fieldName colVal) = do case colInfo of FIColumn (PGColInfo _ PGJSON _) -> throwError (err400 UnexpectedPayload "JSON column can not be part of where clause") - FIColumn (PGColInfo _ PGJSONB _) -> - throwError (err400 UnexpectedPayload "JSONB column can not be part of where clause") + -- FIColumn (PGColInfo _ PGJSONB _) -> + -- throwError (err400 UnexpectedPayload "JSONB column can not be part of where clause") FIColumn pgi -> AVCol pgi <$> parseOpExps valueParser colInfoMap pgi colVal FIRelationship relInfo -> do @@ -252,7 +310,7 @@ txtRHSBuilder :: (MonadError QErr m) => PGColType -> Value -> m S.SQLExp txtRHSBuilder ty val = - txtEncoder <$> pgValParser ty val + toTxtValue ty <$> pgValParser ty val mkColCompExp :: S.Qual -> PGCol -> OpExpG S.SQLExp -> S.BoolExp @@ -279,14 +337,14 @@ mkColCompExp qual lhsCol = \case AHasKeysAny keys -> S.BECompare S.SHasKeysAny lhs $ toTextArray keys AHasKeysAll keys -> S.BECompare S.SHasKeysAll lhs $ toTextArray keys - ASTContains val -> mkGeomOpBe "ST_Contains" val - ASTCrosses val -> mkGeomOpBe "ST_Crosses" val - ASTDWithin r val -> applySQLFn "ST_DWithin" [lhs, val, r] - ASTEquals val -> mkGeomOpBe "ST_Equals" val - ASTIntersects val -> mkGeomOpBe "ST_Intersects" val - ASTOverlaps val -> mkGeomOpBe "ST_Overlaps" val - ASTTouches val -> mkGeomOpBe "ST_Touches" val - ASTWithin val -> mkGeomOpBe "ST_Within" val + ASTContains val -> mkGeomOpBe "ST_Contains" val + ASTCrosses val -> mkGeomOpBe "ST_Crosses" val + ASTEquals val -> mkGeomOpBe "ST_Equals" val + ASTIntersects val -> mkGeomOpBe "ST_Intersects" val + ASTOverlaps val -> mkGeomOpBe "ST_Overlaps" val + ASTTouches val -> mkGeomOpBe "ST_Touches" val + ASTWithin val -> mkGeomOpBe "ST_Within" val + ASTDWithin (WithinOp r val) -> applySQLFn "ST_DWithin" [lhs, val, r] ANISNULL -> S.BENull lhs ANISNOTNULL -> S.BENotNull lhs diff --git a/server/src-lib/Hasura/RQL/Types.hs b/server/src-lib/Hasura/RQL/Types.hs index 2dc3fd8b891..e01af551135 100644 --- a/server/src-lib/Hasura/RQL/Types.hs +++ b/server/src-lib/Hasura/RQL/Types.hs @@ -51,6 +51,7 @@ import Hasura.RQL.Types.Permission as R import Hasura.RQL.Types.RemoteSchema as R import Hasura.RQL.Types.SchemaCache as R import Hasura.RQL.Types.Subscribe as R + import Hasura.SQL.Types import qualified Hasura.GraphQL.Context as GC diff --git a/server/src-lib/Hasura/RQL/Types/BoolExp.hs b/server/src-lib/Hasura/RQL/Types/BoolExp.hs index f72ab075850..0befa97bf54 100644 --- a/server/src-lib/Hasura/RQL/Types/BoolExp.hs +++ b/server/src-lib/Hasura/RQL/Types/BoolExp.hs @@ -4,6 +4,7 @@ module Hasura.RQL.Types.BoolExp , gBoolExpToJSON , parseGBoolExp + , WithinOp(..) , OpExpG(..) , AnnBoolExpFld(..) @@ -22,7 +23,9 @@ import qualified Hasura.SQL.DML as S import Hasura.SQL.Types import Data.Aeson +import Data.Aeson.Casing import Data.Aeson.Internal +import Data.Aeson.TH import qualified Data.Aeson.Types as J import qualified Data.HashMap.Strict as M import Instances.TH.Lift () @@ -90,6 +93,13 @@ foldBoolExp f (BoolNot notExp) = foldBoolExp f (BoolFld ce) = f ce +data WithinOp a = + WithinOp + { woDistance :: !a + , woFrom :: !a + } deriving (Show, Eq, Functor, Foldable, Traversable) +$(deriveJSON (aesonDrop 2 snakeCase) ''WithinOp) + data OpExpG a = AEQ !Bool !a | ANE !Bool !a @@ -119,7 +129,7 @@ data OpExpG a | ASTContains !a | ASTCrosses !a - | ASTDWithin !S.SQLExp !a + | ASTDWithin !(WithinOp a) | ASTEquals !a | ASTIntersects !a | ASTOverlaps !a @@ -168,7 +178,7 @@ opExpToJPair f = \case ASTContains a -> ("_st_contains", f a) ASTCrosses a -> ("_st_crosses", f a) - ASTDWithin _ a -> ("_st_d_within", f a) + ASTDWithin o -> ("_st_d_within", toJSON $ f <$> o) ASTEquals a -> ("_st_equals", f a) ASTIntersects a -> ("_st_intersects", f a) ASTOverlaps a -> ("_st_overlaps", f a) diff --git a/server/src-lib/Hasura/SQL/Value.hs b/server/src-lib/Hasura/SQL/Value.hs index ba712346f52..d5de51ea235 100644 --- a/server/src-lib/Hasura/SQL/Value.hs +++ b/server/src-lib/Hasura/SQL/Value.hs @@ -188,29 +188,27 @@ iresToEither (ISuccess a) = return a pgValFromJVal :: (FromJSON a) => Value -> Either String a pgValFromJVal = iresToEither . ifromJSON -applyGeomFromGeoJson :: S.SQLExp -> S.SQLExp -applyGeomFromGeoJson v = - S.SEFnApp "ST_GeomFromGeoJSON" [v] Nothing +withGeoVal :: PGColType -> S.SQLExp -> S.SQLExp +withGeoVal ty v = + bool v applyGeomFromGeoJson isGeoTy + where + applyGeomFromGeoJson = + S.SEFnApp "ST_GeomFromGeoJSON" [v] Nothing -isGeoTy :: PGColType -> Bool -isGeoTy = \case - PGGeometry -> True - PGGeography -> True - _ -> False + isGeoTy = case ty of + PGGeometry -> True + PGGeography -> True + _ -> False toPrepParam :: Int -> PGColType -> S.SQLExp -toPrepParam i = - bool prepVal (applyGeomFromGeoJson prepVal) . isGeoTy - where - prepVal = S.SEPrep i +toPrepParam i ty = + withGeoVal ty $ S.SEPrep i toTxtValue :: PGColType -> PGColValue -> S.SQLExp toTxtValue ty val = S.annotateExp txtVal ty where - txtVal = withGeoVal $ txtEncoder val - withGeoVal v = - bool v (applyGeomFromGeoJson v) $ isGeoTy ty + txtVal = withGeoVal ty $ txtEncoder val pgColValueToInt :: PGColValue -> Maybe Int pgColValueToInt (PGValInteger i) = Just $ fromIntegral i diff --git a/server/tests-py/queries/graphql_query/permissions/setup.yaml b/server/tests-py/queries/graphql_query/permissions/setup.yaml index f0d288be96b..1e5dfaf8ad4 100644 --- a/server/tests-py/queries/graphql_query/permissions/setup.yaml +++ b/server/tests-py/queries/graphql_query/permissions/setup.yaml @@ -260,4 +260,133 @@ args: name: search_tracks schema: public +#Permission based on PostGIS operators +- type: run_sql + args: + sql: | + CREATE EXTENSION IF NOT EXISTS postgis; +- type: run_sql + args: + sql: | + CREATE EXTENSION IF NOT EXISTS postgis_topology; + +#Create table +- type: run_sql + args: + sql: | + CREATE TABLE geom_table( + id SERIAL PRIMARY KEY, + type TEXT NOT NULL, + geom_col geometry NOT NULL + ); + +- type: track_table + args: + name: geom_table + schema: public + +#Create select permission using postgis operator +- type: create_select_permission + args: + table: geom_table + role: user1 + permission: + columns: + - id + - type + - geom_col + filter: + geom_col: + $st_d_within: + distance: 1 + from: + type: Polygon + coordinates: + - - - 2 + - 0 + - - 2 + - 1 + - - 3 + - 1 + - - 3 + - 0 + - - 2 + - 0 +#Create select permission using postgis operator and session variables +- type: create_select_permission + args: + table: geom_table + role: user2 + permission: + columns: + - id + - type + - geom_col + filter: + geom_col: + $st_d_within: + distance: X-Hasura-Geom-Dist + from: X-Hasura-Geom-Val +#Insert data +- type: run_sql + args: + sql: | + INSERT INTO geom_table (type, geom_col) + VALUES + ('point', ST_GeomFromText('POINT(1 2)')), + ('linestring', ST_GeomFromText('LINESTRING(0 0, 0.5 1, 1 2, 1.5 3)')), + ('linestring', ST_GeomFromText('LINESTRING(1 0, 0.5 0.5, 0 1)')), + ('polygon', ST_GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')), + ('polygon', ST_GeomFromText('POLYGON((2 0, 2 1, 3 1, 3 0, 2 0))')) + ; + + +#Permission based on JSONB operators +- type: run_sql + args: + sql: | + CREATE TABLE jsonb_table( + id SERIAL PRIMARY KEY, + jsonb_col jsonb NOT NULL + ); +- type: track_table + args: + name: jsonb_table + schema: public + +#Create select permission using jsonb operator +- type: create_select_permission + args: + table: jsonb_table + role: user1 + permission: + columns: + - id + - jsonb_col + filter: + jsonb_col: + $has_key: age + +- type: create_select_permission + args: + table: jsonb_table + role: user2 + permission: + columns: + - id + - jsonb_col + filter: + jsonb_col: + $has_key: X-Hasura-Has-Key + +#Insert data +- type: insert + args: + table: jsonb_table + objects: + - jsonb_col: + name: Hasura + age: 7 + - jsonb_col: + name: Cross diff --git a/server/tests-py/queries/graphql_query/permissions/teardown.yaml b/server/tests-py/queries/graphql_query/permissions/teardown.yaml index 53eaa8fb40e..11b1adc7d04 100644 --- a/server/tests-py/queries/graphql_query/permissions/teardown.yaml +++ b/server/tests-py/queries/graphql_query/permissions/teardown.yaml @@ -1,26 +1,12 @@ type: bulk args: - - type: run_sql args: sql: | - drop table article - cascade: true - -- type: run_sql - args: - sql: | - drop table author - cascade: true - -- type: run_sql - args: - sql: | - drop table "Track" cascade - cascade: true - -- type: run_sql - args: - sql: | - drop table "Artist" + DROP TABLE article; + DROP TABLE author; + DROP TABLE "Track" cascade; + DROP TABLE "Artist"; + DROP TABLE geom_table; + DROP TABLE jsonb_table; cascade: true diff --git a/server/tests-py/queries/graphql_query/permissions/user_can_query_geometry_values_filter.yaml b/server/tests-py/queries/graphql_query/permissions/user_can_query_geometry_values_filter.yaml new file mode 100644 index 00000000000..1dad6959d83 --- /dev/null +++ b/server/tests-py/queries/graphql_query/permissions/user_can_query_geometry_values_filter.yaml @@ -0,0 +1,59 @@ +description: User can query geometry values which satisfies filter in select permission +url: /v1alpha1/graphql +status: 200 +headers: + X-Hasura-Role: user1 +response: + data: + geom_table: + - id: 3 + type: linestring + geom_col: + type: LineString + coordinates: + - - 1 + - 0 + - - 0.5 + - 0.5 + - - 0 + - 1 + - id: 4 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 0 + - 0 + - - 0 + - 1 + - - 1 + - 1 + - - 1 + - 0 + - - 0 + - 0 + - id: 5 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 2 + - 0 + - - 2 + - 1 + - - 3 + - 1 + - - 3 + - 0 + - - 2 + - 0 + +query: + query: | + query { + geom_table{ + id + type + geom_col + } + } diff --git a/server/tests-py/queries/graphql_query/permissions/user_can_query_geometry_values_filter_session_vars.yaml b/server/tests-py/queries/graphql_query/permissions/user_can_query_geometry_values_filter_session_vars.yaml new file mode 100644 index 00000000000..e325bc49cbf --- /dev/null +++ b/server/tests-py/queries/graphql_query/permissions/user_can_query_geometry_values_filter_session_vars.yaml @@ -0,0 +1,61 @@ +description: User can query geometry values which satisfies filter in select permission using session variables +url: /v1alpha1/graphql +status: 200 +headers: + X-Hasura-Role: user2 + X-Hasura-Geom-Dist: '1' + X-Hasura-Geom-Val: '{"type":"Polygon","coordinates":[[[2,0],[2,1],[3,1],[3,0],[2,0]]]}' +response: + data: + geom_table: + - id: 3 + type: linestring + geom_col: + type: LineString + coordinates: + - - 1 + - 0 + - - 0.5 + - 0.5 + - - 0 + - 1 + - id: 4 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 0 + - 0 + - - 0 + - 1 + - - 1 + - 1 + - - 1 + - 0 + - - 0 + - 0 + - id: 5 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 2 + - 0 + - - 2 + - 1 + - - 3 + - 1 + - - 3 + - 0 + - - 2 + - 0 + +query: + query: | + query { + geom_table{ + id + type + geom_col + } + } diff --git a/server/tests-py/queries/graphql_query/permissions/user_can_query_jsonb_values_filter.yaml b/server/tests-py/queries/graphql_query/permissions/user_can_query_jsonb_values_filter.yaml new file mode 100644 index 00000000000..7c2bd68d9ab --- /dev/null +++ b/server/tests-py/queries/graphql_query/permissions/user_can_query_jsonb_values_filter.yaml @@ -0,0 +1,20 @@ +description: User can query geometry values which satisfies filter in select permission +url: /v1alpha1/graphql +status: 200 +headers: + X-Hasura-Role: user1 +response: + data: + jsonb_table: + - id: 1 + jsonb_col: + name: Hasura + age: 7 +query: + query: | + query { + jsonb_table{ + id + jsonb_col + } + } diff --git a/server/tests-py/queries/graphql_query/permissions/user_can_query_jsonb_values_filter_session_vars.yaml b/server/tests-py/queries/graphql_query/permissions/user_can_query_jsonb_values_filter_session_vars.yaml new file mode 100644 index 00000000000..912c63835ca --- /dev/null +++ b/server/tests-py/queries/graphql_query/permissions/user_can_query_jsonb_values_filter_session_vars.yaml @@ -0,0 +1,21 @@ +description: User can query geometry values which satisfies filter in select permission +url: /v1alpha1/graphql +status: 200 +headers: + X-Hasura-Role: user2 + X-Hasura-Has-Key: age +response: + data: + jsonb_table: + - id: 1 + jsonb_col: + name: Hasura + age: 7 +query: + query: | + query { + jsonb_table{ + id + jsonb_col + } + } diff --git a/server/tests-py/queries/v1/select/boolexp/jsonb/select_article_author_jsonb_contained_in_bestseller_latest.yaml b/server/tests-py/queries/v1/select/boolexp/jsonb/select_article_author_jsonb_contained_in_bestseller_latest.yaml new file mode 100644 index 00000000000..cdb2364d88a --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/jsonb/select_article_author_jsonb_contained_in_bestseller_latest.yaml @@ -0,0 +1,40 @@ +description: Nested select on article +url: /v1/query +status: 200 +response: +- content: Sample article content 2 + author: + name: Author 1 + id: 1 + id: 2 + title: Article 2 + tags: + - bestseller + - latest +- content: Sample article content 3 + author: + name: Author 2 + id: 2 + id: 3 + title: Article 3 + tags: + - latest + +query: + type: select + args: + table: article + columns: + - id + - title + - content + - tags + - name: author + columns: + - id + - name + where: + tags: + $contained_in: + - bestseller + - latest diff --git a/server/tests-py/queries/v1/select/boolexp/jsonb/select_article_author_jsonb_contained_in_latest.yaml b/server/tests-py/queries/v1/select/boolexp/jsonb/select_article_author_jsonb_contained_in_latest.yaml new file mode 100644 index 00000000000..99f7cd535c2 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/jsonb/select_article_author_jsonb_contained_in_latest.yaml @@ -0,0 +1,32 @@ +description: Nested select on article +url: /v1/query +status: 200 +response: +- content: Sample article content 3 + author: + name: Author 2 + id: 2 + id: 3 + title: Article 3 + tags: + - latest +query: + variables: + tags: + - latest + type: select + args: + table: article + where: + tags: + $contained_in: + - latest + columns: + - id + - title + - content + - tags + - name: author + columns: + - id + - name diff --git a/server/tests-py/queries/v1/select/boolexp/jsonb/select_article_author_jsonb_contains_latest.yaml b/server/tests-py/queries/v1/select/boolexp/jsonb/select_article_author_jsonb_contains_latest.yaml new file mode 100644 index 00000000000..583fa07dd71 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/jsonb/select_article_author_jsonb_contains_latest.yaml @@ -0,0 +1,37 @@ +description: Select author and their articles +url: /v1/query +status: 200 +response: +- content: Sample article content 2 + author: + name: Author 1 + id: 1 + id: 2 + title: Article 2 + tags: + - bestseller + - latest +- content: Sample article content 3 + author: + name: Author 2 + id: 2 + id: 3 + title: Article 3 + tags: + - latest +query: + type: select + args: + table: article + where: + tags: + $contains: latest + columns: + - id + - title + - content + - tags + - name: author + columns: + - id + - name diff --git a/server/tests-py/queries/v1/select/boolexp/jsonb/select_author_article_jsonb_contains_bestseller.yaml b/server/tests-py/queries/v1/select/boolexp/jsonb/select_author_article_jsonb_contains_bestseller.yaml new file mode 100644 index 00000000000..3160dfe04a8 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/jsonb/select_author_article_jsonb_contains_bestseller.yaml @@ -0,0 +1,34 @@ +description: Select author and their articles +url: /v1/query +status: 200 +response: +- id: 1 + name: Author 1 + articles: + - id: 1 + title: Article 1 + content: Sample article content 1 + tags: + - id: 2 + title: Article 2 + content: Sample article content 2 + tags: + - bestseller + - latest +query: + type: select + args: + table: author + where: + articles: + tags: + $contains: bestseller + columns: + - id + - name + - name: articles + columns: + - id + - title + - content + - tags diff --git a/server/tests-py/queries/v1/select/boolexp/jsonb/select_product_jsonb_has_key_sim_type.yaml b/server/tests-py/queries/v1/select/boolexp/jsonb/select_product_jsonb_has_key_sim_type.yaml new file mode 100644 index 00000000000..05618009498 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/jsonb/select_product_jsonb_has_key_sim_type.yaml @@ -0,0 +1,28 @@ +description: Select products having key 'SIM type' in spec +url: /v1/query +status: 200 +response: +- id: 3 + category: Mobile + name: mobile1 + spec: + Operating System Type: osType1 + Weight: 200g + Processor: processor2 + SIM type: DualSim + Sensors: Accelerometer sensor, E-compass, Proximity sensor + Network type: 4G + RAM: 3GB + Touchscreen: true +query: + type: select + args: + table: product + where: + spec: + $has_key: SIM type + columns: + - id + - category + - name + - spec diff --git a/server/tests-py/queries/v1/select/boolexp/jsonb/select_product_jsonb_has_keys_all_ram_touchscreen.yaml b/server/tests-py/queries/v1/select/boolexp/jsonb/select_product_jsonb_has_keys_all_ram_touchscreen.yaml new file mode 100644 index 00000000000..6709565592e --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/jsonb/select_product_jsonb_has_keys_all_ram_touchscreen.yaml @@ -0,0 +1,40 @@ +description: Select products having key 'SIM type' in spec +url: /v1/query +status: 200 +response: +- id: 2 + category: Laptop + name: laptop2 + spec: + Disk: 128GB + Weight: 1.2Kg + OS: os2 + Processor: processor2 + RAM: 16GB + Touchscreen: true +- id: 3 + category: Mobile + name: mobile1 + spec: + Operating System Type: osType1 + Weight: 200g + SIM type: DualSim + Sensors: Accelerometer sensor, E-compass, Proximity sensor + Network type: 4G + Processor: processor2 + RAM: 3GB + Touchscreen: true +query: + type: select + args: + table: product + where: + spec: + $has_keys_all: + - Touchscreen + - RAM + columns: + - id + - category + - name + - spec diff --git a/server/tests-py/queries/v1/select/boolexp/jsonb/select_product_jsonb_has_keys_any_os_operating_system.yaml b/server/tests-py/queries/v1/select/boolexp/jsonb/select_product_jsonb_has_keys_any_os_operating_system.yaml new file mode 100644 index 00000000000..82f88dff968 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/jsonb/select_product_jsonb_has_keys_any_os_operating_system.yaml @@ -0,0 +1,37 @@ +description: Select products having key 'SIM type' in spec +url: /v1/query +status: 200 +response: +- id: 1 + category: Laptop + name: laptop1 + spec: + Disk: 128GB + Weight: 1.2Kg + Processor: processor1 + Operating System: os1 + RAM: 8GB +- id: 2 + category: Laptop + name: laptop2 + spec: + Disk: 128GB + Weight: 1.2Kg + Processor: processor2 + OS: os2 + RAM: 16GB + Touchscreen: true +query: + type: select + args: + table: product + where: + spec: + $has_keys_any: + - OS + - Operating System + columns: + - id + - category + - name + - spec diff --git a/server/tests-py/queries/v1/select/boolexp/jsonb/setup.yaml b/server/tests-py/queries/v1/select/boolexp/jsonb/setup.yaml new file mode 100644 index 00000000000..1910ada4d8f --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/jsonb/setup.yaml @@ -0,0 +1,144 @@ +type: bulk +args: + +#Author table +- type: run_sql + args: + sql: | + create table author( + id serial primary key, + name text unique + ); +- type: track_table + args: + schema: public + name: author + +#Article table +- type: run_sql + args: + sql: | + CREATE TABLE article ( + id SERIAL PRIMARY KEY, + title TEXT, + content TEXT, + author_id INTEGER REFERENCES author(id), + is_published BOOLEAN, + published_on TIMESTAMP, + tags JSONB + ) +- type: track_table + args: + schema: public + name: article + +- type: run_sql + args: + sql: | + CREATE TABLE product ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + category TEXT NOT NULL, + spec JSONB NOT NULL + ); +- type: track_table + args: + schema: public + name: product + + +#Object relationship +- type: create_object_relationship + args: + table: article + name: author + using: + foreign_key_constraint_on: author_id + +#Array relationship +- type: create_array_relationship + args: + table: author + name: articles + using: + foreign_key_constraint_on: + table: article + column: author_id + + +#Insert values +- type: run_sql + args: + sql: | + insert into author (name) + values + ('Author 1'), + ('Author 2') + +- type: insert + args: + table: article + objects: + - title: Article 1 + content: Sample article content 1 + author_id: 1 + + - title: Article 2 + content: Sample article content 2 + author_id: 1 + tags: + - bestseller + - latest + + - title: Article 3 + content: Sample article content 3 + author_id: 2 + tags: + - latest + + +- type: insert + args: + table: product + objects: + + - category: Laptop + name: laptop1 + spec: + Operating System: os1 + RAM: 8GB + Disk: 128GB + Weight: 1.2Kg + Processor: processor1 + + - category: Laptop + name: laptop2 + spec: + OS: os2 + RAM: 16GB + Disk: 128GB + Weight: 1.2Kg + Processor: processor2 + Touchscreen: yes + + - category: Mobile + name: mobile1 + spec: + Operating System Type: osType1 + RAM: 3GB + Weight: 200g + Processor: processor2 + Network type: 4G + SIM type: DualSim + Sensors: Accelerometer sensor, E-compass, Proximity sensor + Touchscreen: yes + + - category: Electric kettle + name: kettle1 + spec: + power: 1500W + capacity: 1.5L + dimensions: + width: 20cm + height: 19cm + depth: 18cm diff --git a/server/tests-py/queries/v1/select/boolexp/jsonb/teardown.yaml b/server/tests-py/queries/v1/select/boolexp/jsonb/teardown.yaml new file mode 100644 index 00000000000..aef876a8609 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/jsonb/teardown.yaml @@ -0,0 +1,22 @@ +type: bulk +args: +#Drop relationship first +- type: drop_relationship + args: + relationship: articles + table: + schema: public + name: author + +- type: run_sql + args: + sql: | + drop table article +- type: run_sql + args: + sql: | + drop table author +- type: run_sql + args: + sql: | + drop table product diff --git a/server/tests-py/queries/v1/select/boolexp/postgis/query_not_st_intersects.yaml b/server/tests-py/queries/v1/select/boolexp/postgis/query_not_st_intersects.yaml new file mode 100644 index 00000000000..07972b95da7 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/postgis/query_not_st_intersects.yaml @@ -0,0 +1,65 @@ +description: Query data from geom_table using postgis op $st_intersects in bool exp +url: /v1/query +status: 200 +response: +- id: 3 + type: linestring + geom_col: + type: LineString + coordinates: + - - 1 + - 0 + - - 0.5 + - 0.5 + - - 0 + - 1 +- id: 4 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 0 + - 0 + - - 0 + - 1 + - - 1 + - 1 + - - 1 + - 0 + - - 0 + - 0 +- id: 5 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 2 + - 0 + - - 2 + - 1 + - - 3 + - 1 + - - 3 + - 0 + - - 2 + - 0 +query: + type: select + args: + table: geom_table + where: + $not: + geom_col: + $st_intersects: + type: LineString + coordinates: + - - -1 + - 0 + - - 0 + - 1.5 + - - 1 + - 2 + columns: + - id + - type + - geom_col diff --git a/server/tests-py/queries/v1/select/boolexp/postgis/query_st_contains.yaml b/server/tests-py/queries/v1/select/boolexp/postgis/query_st_contains.yaml new file mode 100644 index 00000000000..d5ebafec008 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/postgis/query_st_contains.yaml @@ -0,0 +1,39 @@ +description: Query data from geom_table using postgis op $st_contains in bool exp +url: /v1/query +status: 200 +response: +- id: 1 + type: point + geom_col: + type: Point + coordinates: + - 1 + - 2 +- id: 2 + type: linestring + geom_col: + type: LineString + coordinates: + - - 0 + - 0 + - - 0.5 + - 1 + - - 1 + - 2 + - - 1.5 + - 3 +query: + type: select + args: + table: geom_table + where: + geom_col: + $st_contains: + type: Point + coordinates: + - 1 + - 2 + columns: + - id + - type + - geom_col diff --git a/server/tests-py/queries/v1/select/boolexp/postgis/query_st_d_within.yaml b/server/tests-py/queries/v1/select/boolexp/postgis/query_st_d_within.yaml new file mode 100644 index 00000000000..ac3a35e22ec --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/postgis/query_st_d_within.yaml @@ -0,0 +1,70 @@ +description: Query data from geom_table using postgis op $st_d_within in bool exp +url: /v1/query +status: 200 +response: +- id: 3 + type: linestring + geom_col: + type: LineString + coordinates: + - - 1 + - 0 + - - 0.5 + - 0.5 + - - 0 + - 1 +- id: 4 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 0 + - 0 + - - 0 + - 1 + - - 1 + - 1 + - - 1 + - 0 + - - 0 + - 0 +- id: 5 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 2 + - 0 + - - 2 + - 1 + - - 3 + - 1 + - - 3 + - 0 + - - 2 + - 0 +query: + type: select + args: + table: geom_table + where: + geom_col: + $st_d_within: + distance: 1 + from: + type: Polygon + coordinates: + - - - 2 + - 0 + - - 2 + - 1 + - - 3 + - 1 + - - 3 + - 0 + - - 2 + - 0 + columns: + - id + - type + - geom_col diff --git a/server/tests-py/queries/v1/select/boolexp/postgis/query_st_equals.yaml b/server/tests-py/queries/v1/select/boolexp/postgis/query_st_equals.yaml new file mode 100644 index 00000000000..af965a5fcd1 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/postgis/query_st_equals.yaml @@ -0,0 +1,27 @@ +description: Query data from geom_table using postgis op $st_equals in bool exp +url: /v1/query +status: 200 +response: +- id: 1 + type: point + geom_col: + type: Point + coordinates: + - 1 + - 2 +query: + type: select + args: + table: geom_table + where: + geom_col: + $st_equals: + type: Point + coordinates: + - 1 + - 2 + columns: + - id + - type + - geom_col + diff --git a/server/tests-py/queries/v1/select/boolexp/postgis/query_st_touches.yaml b/server/tests-py/queries/v1/select/boolexp/postgis/query_st_touches.yaml new file mode 100644 index 00000000000..cc146750395 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/postgis/query_st_touches.yaml @@ -0,0 +1,43 @@ +description: Query data from geom_table using postgis op $st_touches in bool exp +url: /v1/query +status: 200 +response: +- id: 1 + type: point + geom_col: + type: Point + coordinates: + - 1 + - 2 +- id: 2 + type: linestring + geom_col: + type: LineString + coordinates: + - - 0 + - 0 + - - 0.5 + - 1 + - - 1 + - 2 + - - 1.5 + - 3 +query: + type: select + args: + table: geom_table + where: + geom_col: + $st_touches: + type: LineString + coordinates: + - - -1 + - 0 + - - 0 + - 1.5 + - - 1 + - 2 + columns: + - id + - type + - geom_col diff --git a/server/tests-py/queries/v1/select/boolexp/postgis/setup.yaml b/server/tests-py/queries/v1/select/boolexp/postgis/setup.yaml new file mode 100644 index 00000000000..60a534c4b79 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/postgis/setup.yaml @@ -0,0 +1,38 @@ +type: bulk +args: +- type: run_sql + args: + sql: | + CREATE EXTENSION IF NOT EXISTS postgis; + +- type: run_sql + args: + sql: | + CREATE EXTENSION IF NOT EXISTS postgis_topology; + +#Create table +- type: run_sql + args: + sql: | + CREATE TABLE geom_table( + id SERIAL PRIMARY KEY, + type TEXT NOT NULL, + geom_col geometry NOT NULL + ); +- type: track_table + args: + name: geom_table + schema: public + +#Insert data +- type: run_sql + args: + sql: | + INSERT INTO geom_table (type, geom_col) + VALUES + ('point', ST_GeomFromText('POINT(1 2)')), + ('linestring', ST_GeomFromText('LINESTRING(0 0, 0.5 1, 1 2, 1.5 3)')), + ('linestring', ST_GeomFromText('LINESTRING(1 0, 0.5 0.5, 0 1)')), + ('polygon', ST_GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')), + ('polygon', ST_GeomFromText('POLYGON((2 0, 2 1, 3 1, 3 0, 2 0))')) + ; diff --git a/server/tests-py/queries/v1/select/boolexp/postgis/teardown.yaml b/server/tests-py/queries/v1/select/boolexp/postgis/teardown.yaml new file mode 100644 index 00000000000..e440c971c69 --- /dev/null +++ b/server/tests-py/queries/v1/select/boolexp/postgis/teardown.yaml @@ -0,0 +1,6 @@ +type: bulk +args: +- type: run_sql + args: + sql: | + DROP TABLE geom_table; diff --git a/server/tests-py/queries/v1/select/permissions/setup.yaml b/server/tests-py/queries/v1/select/permissions/setup.yaml index 09b1509e0f1..48035d7a52c 100644 --- a/server/tests-py/queries/v1/select/permissions/setup.yaml +++ b/server/tests-py/queries/v1/select/permissions/setup.yaml @@ -167,3 +167,133 @@ args: content: Sample article content 4 author_id: 3 is_published: false + +#Permission based on PostGIS operators +- type: run_sql + args: + sql: | + CREATE EXTENSION IF NOT EXISTS postgis; + +- type: run_sql + args: + sql: | + CREATE EXTENSION IF NOT EXISTS postgis_topology; + +#Create table +- type: run_sql + args: + sql: | + CREATE TABLE geom_table( + id SERIAL PRIMARY KEY, + type TEXT NOT NULL, + geom_col geometry NOT NULL + ); + +- type: track_table + args: + name: geom_table + schema: public + +#Create select permission using postgis operator +- type: create_select_permission + args: + table: geom_table + role: user1 + permission: + columns: + - id + - type + - geom_col + filter: + geom_col: + $st_d_within: + distance: 1 + from: + type: Polygon + coordinates: + - - - 2 + - 0 + - - 2 + - 1 + - - 3 + - 1 + - - 3 + - 0 + - - 2 + - 0 +#Create select permission using postgis operator and session variables +- type: create_select_permission + args: + table: geom_table + role: user2 + permission: + columns: + - id + - type + - geom_col + filter: + geom_col: + $st_d_within: + distance: X-Hasura-Geom-Dist + from: X-Hasura-Geom-Val +#Insert data +- type: run_sql + args: + sql: | + INSERT INTO geom_table (type, geom_col) + VALUES + ('point', ST_GeomFromText('POINT(1 2)')), + ('linestring', ST_GeomFromText('LINESTRING(0 0, 0.5 1, 1 2, 1.5 3)')), + ('linestring', ST_GeomFromText('LINESTRING(1 0, 0.5 0.5, 0 1)')), + ('polygon', ST_GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')), + ('polygon', ST_GeomFromText('POLYGON((2 0, 2 1, 3 1, 3 0, 2 0))')) + ; + +#Permission based on JSONB operators +- type: run_sql + args: + sql: | + CREATE TABLE jsonb_table( + id SERIAL PRIMARY KEY, + jsonb_col jsonb NOT NULL + ); +- type: track_table + args: + name: jsonb_table + schema: public + +#Create select permission using jsonb operator +- type: create_select_permission + args: + table: jsonb_table + role: user1 + permission: + columns: + - id + - jsonb_col + filter: + jsonb_col: + $has_key: age + +- type: create_select_permission + args: + table: jsonb_table + role: user2 + permission: + columns: + - id + - jsonb_col + filter: + jsonb_col: + $has_key: X-Hasura-Has-Key + +#Insert data +- type: insert + args: + table: jsonb_table + objects: + - jsonb_col: + name: Hasura + age: 7 + - jsonb_col: + name: Cross diff --git a/server/tests-py/queries/v1/select/permissions/teardown.yaml b/server/tests-py/queries/v1/select/permissions/teardown.yaml index 2b72c359b5a..93746a56e78 100644 --- a/server/tests-py/queries/v1/select/permissions/teardown.yaml +++ b/server/tests-py/queries/v1/select/permissions/teardown.yaml @@ -1,14 +1,10 @@ type: bulk args: - - type: run_sql args: sql: | - drop table article - cascade: true - -- type: run_sql - args: - sql: | - drop table author + DROP TABLE article; + DROP TABLE author; + DROP TABLE geom_table; + DROP TABLE jsonb_table; cascade: true diff --git a/server/tests-py/queries/v1/select/permissions/user_can_query_geometry_values_filter.yaml b/server/tests-py/queries/v1/select/permissions/user_can_query_geometry_values_filter.yaml new file mode 100644 index 00000000000..99aabc477ee --- /dev/null +++ b/server/tests-py/queries/v1/select/permissions/user_can_query_geometry_values_filter.yaml @@ -0,0 +1,55 @@ +description: User can query geometry values which satisfies filter in select permission +url: /v1/query +status: 200 +headers: + X-Hasura-Role: user1 +response: +- id: 3 + type: linestring + geom_col: + type: LineString + coordinates: + - - 1 + - 0 + - - 0.5 + - 0.5 + - - 0 + - 1 +- id: 4 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 0 + - 0 + - - 0 + - 1 + - - 1 + - 1 + - - 1 + - 0 + - - 0 + - 0 +- id: 5 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 2 + - 0 + - - 2 + - 1 + - - 3 + - 1 + - - 3 + - 0 + - - 2 + - 0 +query: + type: select + args: + table: geom_table + columns: + - id + - type + - geom_col diff --git a/server/tests-py/queries/v1/select/permissions/user_can_query_geometry_values_filter_session_vars.yaml b/server/tests-py/queries/v1/select/permissions/user_can_query_geometry_values_filter_session_vars.yaml new file mode 100644 index 00000000000..c81270c94bf --- /dev/null +++ b/server/tests-py/queries/v1/select/permissions/user_can_query_geometry_values_filter_session_vars.yaml @@ -0,0 +1,57 @@ +description: User can query geometry values which satisfies filter in select permission using session variables +url: /v1/query +status: 200 +headers: + X-Hasura-Role: user2 + X-Hasura-Geom-Dist: '1' + X-Hasura-Geom-Val: '{"type":"Polygon","coordinates":[[[2,0],[2,1],[3,1],[3,0],[2,0]]]}' +response: +- id: 3 + type: linestring + geom_col: + type: LineString + coordinates: + - - 1 + - 0 + - - 0.5 + - 0.5 + - - 0 + - 1 +- id: 4 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 0 + - 0 + - - 0 + - 1 + - - 1 + - 1 + - - 1 + - 0 + - - 0 + - 0 +- id: 5 + type: polygon + geom_col: + type: Polygon + coordinates: + - - - 2 + - 0 + - - 2 + - 1 + - - 3 + - 1 + - - 3 + - 0 + - - 2 + - 0 +query: + type: select + args: + table: geom_table + columns: + - id + - type + - geom_col diff --git a/server/tests-py/queries/v1/select/permissions/user_can_query_jsonb_values_filter.yaml b/server/tests-py/queries/v1/select/permissions/user_can_query_jsonb_values_filter.yaml new file mode 100644 index 00000000000..e9c1a8fda16 --- /dev/null +++ b/server/tests-py/queries/v1/select/permissions/user_can_query_jsonb_values_filter.yaml @@ -0,0 +1,17 @@ +description: User can query geometry values which satisfies filter in select permission +url: /v1/query +status: 200 +headers: + X-Hasura-Role: user1 +response: +- id: 1 + jsonb_col: + name: Hasura + age: 7 +query: + type: select + args: + table: jsonb_table + columns: + - id + - jsonb_col diff --git a/server/tests-py/queries/v1/select/permissions/user_can_query_jsonb_values_filter_session_vars.yaml b/server/tests-py/queries/v1/select/permissions/user_can_query_jsonb_values_filter_session_vars.yaml new file mode 100644 index 00000000000..fecddfbe544 --- /dev/null +++ b/server/tests-py/queries/v1/select/permissions/user_can_query_jsonb_values_filter_session_vars.yaml @@ -0,0 +1,18 @@ +description: User can query geometry values which satisfies filter in select permission using session variables +url: /v1/query +status: 200 +headers: + X-Hasura-Role: user2 + X-Hasura-Has-Key: age +response: +- id: 1 + jsonb_col: + name: Hasura + age: 7 +query: + type: select + args: + table: jsonb_table + columns: + - id + - jsonb_col diff --git a/server/tests-py/test_graphql_queries.py b/server/tests-py/test_graphql_queries.py index dcd15e1cc4c..9275a57c8f6 100644 --- a/server/tests-py/test_graphql_queries.py +++ b/server/tests-py/test_graphql_queries.py @@ -200,6 +200,18 @@ class TestGraphqlQueryPermissions(DefaultTestSelectQueries): def test_user_cannot_access_remarks_col(self, hge_ctx): check_query_f(hge_ctx, self.dir() + '/user_cannot_access_remarks_col.yaml') + def test_user_can_query_geometry_values_filter(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/user_can_query_geometry_values_filter.yaml') + + def test_user_can_query_geometry_values_filter_session_vars(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/user_can_query_geometry_values_filter_session_vars.yaml') + + def test_user_can_query_jsonb_values_filter(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/user_can_query_jsonb_values_filter.yaml') + + def test_user_can_query_jsonb_values_filter_session_vars(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/user_can_query_jsonb_values_filter_session_vars.yaml') + def test_artist_select_query_Track_fail(self, hge_ctx): check_query_f(hge_ctx, self.dir() + '/artist_select_query_Track_fail.yaml') diff --git a/server/tests-py/test_v1_queries.py b/server/tests-py/test_v1_queries.py index a8f27ab352a..dfc6ba97b07 100644 --- a/server/tests-py/test_v1_queries.py +++ b/server/tests-py/test_v1_queries.py @@ -158,6 +158,54 @@ class TestV1SelectBoolExpSearch(DefaultTestSelectQueries): def dir(cls): return 'queries/v1/select/boolexp/search' +class TestV1SelectBoolExpJSONB(DefaultTestSelectQueries): + + def test_select_article_author_jsonb_contained_in_bestseller_latest(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/select_article_author_jsonb_contained_in_bestseller_latest.yaml') + + def test_select_article_author_jsonb_contained_in_latest(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/select_article_author_jsonb_contained_in_latest.yaml') + + def test_select_article_author_jsonb_contains_latest(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/select_article_author_jsonb_contains_latest.yaml') + + def test_select_author_article_jsonb_contains_bestseller(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/select_author_article_jsonb_contains_bestseller.yaml') + + # TODO:- Uncomment the following after adding has_keys_all and has_keys_any operators + # def test_select_product_jsonb_has_keys_all_ram_touchscreen(self, hge_ctx): + # check_query_f(hge_ctx, self.dir() + '/select_product_jsonb_has_keys_all_ram_touchscreen.yaml') + + # def test_select_product_jsonb_has_keys_any_os_operating_system(self, hge_ctx): + # check_query_f(hge_ctx, self.dir() + '/select_product_jsonb_has_keys_any_os_operating_system.yaml') + + def test_select_product_jsonb_has_key_sim_type(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/select_product_jsonb_has_key_sim_type.yaml') + + @classmethod + def dir(cls): + return 'queries/v1/select/boolexp/jsonb' + +class TestV1SelectBoolExpPostGIS(DefaultTestSelectQueries): + + def test_query_st_equals(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/query_st_equals.yaml') + + def test_query_st_contains(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/query_st_contains.yaml') + + def test_query_st_touches(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/query_st_touches.yaml') + + def test_query_not_st_intersects(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/query_not_st_intersects.yaml') + + def test_query_st_d_within(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/query_st_d_within.yaml') + + @classmethod + def dir(cls): + return 'queries/v1/select/boolexp/postgis' class TestV1SelectPermissions(DefaultTestSelectQueries): @@ -173,6 +221,18 @@ class TestV1SelectPermissions(DefaultTestSelectQueries): def test_user_cannot_access_remarks_col(self, hge_ctx): check_query_f(hge_ctx, self.dir() + '/user_cannot_access_remarks_col.yaml') + def test_user_can_query_geometry_values_filter(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/user_can_query_geometry_values_filter.yaml') + + def test_user_can_query_geometry_values_filter_session_vars(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/user_can_query_geometry_values_filter_session_vars.yaml') + + def test_user_can_query_jsonb_values_filter(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/user_can_query_jsonb_values_filter.yaml') + + def test_user_can_query_jsonb_values_filter_session_vars(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + '/user_can_query_jsonb_values_filter_session_vars.yaml') + @classmethod def dir(cls): return 'queries/v1/select/permissions'