diff --git a/src/JSON/Path.purs b/src/JSON/Path.purs new file mode 100644 index 0000000..92fd105 --- /dev/null +++ b/src/JSON/Path.purs @@ -0,0 +1,39 @@ +module JSON.Path where + +import Prelude + +import Data.Maybe (Maybe(..)) +import JSON (JSON) +import JSON as JSON +import JSON.Array as JArray +import JSON.Object as JObject + +data Path + = Top + | AtKey String Path + | AtIndex Int Path + +derive instance Eq Path +derive instance Ord Path + +instance Show Path where + show = case _ of + Top -> "Top" + AtKey key rest -> "(AtKey " <> show key <> " " <> show rest <> ")" + AtIndex ix rest -> "(AtIndex " <> show ix <> " " <> show rest <> ")" + +get :: Path -> JSON -> Maybe JSON +get path json = + case path of + Top -> Just json + AtKey key rest -> JObject.lookup key =<< JSON.toJObject =<< get rest json + AtIndex ix rest -> JArray.index ix =<< JSON.toJArray =<< get rest json + +print :: Path -> String +print path = "$" <> go path "" + where + go :: Path -> String -> String + go p acc = case p of + Top -> acc + AtKey k rest -> go rest ("." <> k <> acc) + AtIndex ix rest -> go rest ("[" <> show ix <> "]" <> acc) diff --git a/test/Main.purs b/test/Main.purs index d93408f..6cc136d 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -9,7 +9,8 @@ import Effect.Console (log) import JSON as J import JSON.Array as JA import JSON.Object as JO -import Test.Assert (assertTrue) +import JSON.Path as Path +import Test.Assert (assertEqual, assertTrue) main :: Effect Unit main = do @@ -43,3 +44,20 @@ main = do log "Check array concat" assertTrue $ JA.fromArray (J.fromInt <$> [ 1, 2 ]) <> JA.fromArray (J.fromInt <$> [ 2, 3 ]) == JA.fromArray (J.fromInt <$> [ 1, 2, 2, 3 ]) + + log "Check path printing" + assertEqual + { expected: "$.data[0].field" + , actual: Path.print (Path.AtKey "field" (Path.AtIndex 0 (Path.AtKey "data" Path.Top))) + } + + log "Check path get" + assertTrue $ Path.get Path.Top (J.fromString "hello") == Just (J.fromString "hello") + assertTrue $ Path.get Path.Top (J.fromJArray (JA.fromArray [ J.fromInt 42 ])) == Just (J.fromJArray (JA.fromArray [ J.fromInt 42 ])) + assertTrue $ Path.get (Path.AtIndex 0 Path.Top) (J.fromJArray (JA.fromArray [ J.fromInt 42, J.fromString "X", J.fromBoolean true ])) == Just (J.fromInt 42) + assertTrue $ Path.get (Path.AtIndex 1 Path.Top) (J.fromJArray (JA.fromArray [ J.fromInt 42, J.fromString "X", J.fromBoolean true ])) == Just (J.fromString "X") + assertTrue $ Path.get (Path.AtIndex 5 Path.Top) (J.fromJArray (JA.fromArray [ J.fromInt 42, J.fromString "X", J.fromBoolean true ])) == Nothing + assertTrue $ Path.get (Path.AtKey "a" Path.Top) (J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 1), Tuple "x" (J.fromBoolean false) ])) == Just (J.fromInt 1) + assertTrue $ Path.get (Path.AtKey "x" Path.Top) (J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 1), Tuple "x" (J.fromBoolean false) ])) == Just (J.fromBoolean false) + assertTrue $ Path.get (Path.AtKey "z" Path.Top) (J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 1), Tuple "x" (J.fromBoolean false) ])) == Nothing + assertTrue $ Path.get (Path.AtKey "x" (Path.AtIndex 1 Path.Top)) (J.fromJArray (JA.fromArray [ J.fromString "skip", (J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 1), Tuple "x" (J.fromBoolean false) ])) ])) == Just (J.fromBoolean false)