server: support single $ as root json path (#4482)

* support single $ json path

* support sql query with root json path

* update changelog

* update changelog

Co-authored-by: Karthikeyan Chinnakonda <karthikeyan@hasura.io>
Co-authored-by: Tirumarai Selvan <tiru@hasura.io>
This commit is contained in:
Toan Nguyen
2020-04-21 15:06:11 +07:00
committed by GitHub
parent 3517b3c73b
commit 5f84669568
5 changed files with 52 additions and 18 deletions

View File

@@ -13,6 +13,7 @@ import Data.Aeson.Internal (JSONPath, JSONPathElement (..))
import Data.Attoparsec.Text
parseJSONPath :: T.Text -> Either String JSONPath
parseJSONPath "$" = Right []
parseJSONPath txt = first (const invalidMessage) $
parseOnly (optional (char '$') *> many1' element <* endOfInput) txt
where

View File

@@ -35,20 +35,23 @@ import Hasura.RQL.Types
import Hasura.SQL.Types
import Hasura.SQL.Value
jsonPathToColExp :: (MonadError QErr m) => T.Text -> m S.SQLExp
jsonPathToColExp :: (MonadError QErr m) => T.Text -> m (Maybe S.SQLExp)
jsonPathToColExp t = case parseJSONPath t of
Left s -> throw400 ParseFailed $ T.pack $ "parse json path error: " ++ s
Right jPaths -> return $ S.SEArray $ map elToColExp jPaths
Right [] -> return Nothing
Right jPaths -> return $ Just $ S.SEArray $ map elToColExp jPaths
where
elToColExp (Key k) = S.SELit k
elToColExp (Index i) = S.SELit $ T.pack (show i)
argsToColOp :: (MonadReusability m, MonadError QErr m) => ArgsMap -> m (Maybe RS.ColOp)
argsToColOp args = maybe (return Nothing) toOp $ Map.lookup "path" args
where
toJsonPathExp = fmap (RS.ColOp S.jsonbPathOp) . jsonPathToColExp
toOp v = asPGColTextM v >>= traverse toJsonPathExp
argsToColOp args = case Map.lookup "path" args of
Nothing -> return Nothing
Just txt -> do
mColTxt <- asPGColTextM txt
mColExps <- maybe (return Nothing) jsonPathToColExp mColTxt
return $ RS.ColOp S.jsonbPathOp <$> mColExps
type AnnFlds = RS.AnnFldsG UnresolvedVal

View File

@@ -16,14 +16,20 @@ spec = describe "encode and parse JSONPath" $ do
forM_ generateTestEncodeJSONPath $ \(jsonPath, result) ->
encodeJSONPath jsonPath `shouldBe` result
it "JSONPath parser" $
withMaxSuccess 1000 $
forAll(resize 20 generateJSONPath) $ \jsonPath ->
let encPath = encodeJSONPath jsonPath
parsedJSONPathE = parseJSONPath $ T.pack encPath
in case parsedJSONPathE of
Left err -> counterexample (err <> ": " <> encPath) False
Right parsedJSONPath -> property $ parsedJSONPath == jsonPath
describe "JSONPath parser" $ do
it "Single $" $
parseJSONPath "$" `shouldBe` (Right [] :: Either String JSONPath)
it "Random json paths" $
withMaxSuccess 1000 $
forAll (resize 20 generateJSONPath) $ \jsonPath ->
let encPath = encodeJSONPath jsonPath
parsedJSONPathE = parseJSONPath $ T.pack encPath
in case parsedJSONPathE of
Left err -> counterexample (err <> ": " <> encPath) False
Right parsedJSONPath -> property $ parsedJSONPath == jsonPath
generateTestEncodeJSONPath :: [(JSONPath, String)]

View File

@@ -46,6 +46,17 @@ response:
hello world!: hi
objs:
- 你好: Hello!
c32_json_dollar:
a: b
obj:
c1: c2
arr: [1,2,3]
_underscore: 0
'!@#$%^': special
translations:
hello world!: hi
objs:
- 你好: Hello!
c32_json_child_prop: c2
c32_json_child_prop_no_dot: b
c32_json_array_item: 1
@@ -57,9 +68,20 @@ response:
c32_json_nested_special_array_double_quote_dot: Hello!
c33_jsonb:
c: d
arr: [4,5,6]
obj:
e1: e2
arr: [4,5,6]
e1: e2
objs:
- 你好: Hello!
'!@#$%^': special
_underscore: 0
translations:
hello world!: hi
c33_jsonb_dollar:
c: d
arr: [4,5,6]
obj:
e1: e2
objs:
- 你好: Hello!
'!@#$%^': special
@@ -130,6 +152,7 @@ query:
c30_inet
c31_macaddr
c32_json
c32_json_dollar: c32_json(path: "$")
c32_json_child_prop: c32_json(path: ".obj.c1")
c32_json_child_prop_no_dot: c32_json(path: "a")
c32_json_array_item: c32_json(path: "arr[0]")
@@ -140,6 +163,7 @@ query:
c32_json_nested_special_array_double_quote: c32_json(path: "objs[0][\"你好\"]")
c32_json_nested_special_array_double_quote_dot: c32_json(path: "objs[0].[\"你好\"]")
c33_jsonb
c33_jsonb_dollar: c33_jsonb(path: "$")
c33_jsonb_child_prop: c33_jsonb(path: ".obj.e1")
c33_jsonb_child_prop_no_dot: c33_jsonb(path: "c")
c33_jsonb_array_item: c33_jsonb(path: "arr[2]")