mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
support jsonb and postgis operators in permissions (#1461)
* support jsonb and geometry operators on RQL bool exps, close #1408 * add tests for jsonb operators in /v1/query TODO:- -> add tests for geometry (postgis) operators * support parsing session variables for st_d_within and has_key ops -> Add tests for boolExp operators and select permissions * improve parsing $st_d_within op's json value logic
This commit is contained in:
parent
c6e5add28a
commit
3caff9b924
@ -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)
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
144
server/tests-py/queries/v1/select/boolexp/jsonb/setup.yaml
Normal file
144
server/tests-py/queries/v1/select/boolexp/jsonb/setup.yaml
Normal file
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
38
server/tests-py/queries/v1/select/boolexp/postgis/setup.yaml
Normal file
38
server/tests-py/queries/v1/select/boolexp/postgis/setup.yaml
Normal file
@ -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))'))
|
||||
;
|
@ -0,0 +1,6 @@
|
||||
type: bulk
|
||||
args:
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
DROP TABLE geom_table;
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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')
|
||||
|
||||
|
@ -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'
|
||||
|
Loading…
Reference in New Issue
Block a user