Skip to content

Commit 0288650

Browse files
oakmaccburgmer
authored andcommitted
support literal true and false in boolean expressions
1 parent e1c1d51 commit 0288650

File tree

2 files changed

+69
-24
lines changed

2 files changed

+69
-24
lines changed

src/json_path/walker.clj

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,32 @@
77
(and (map? m)
88
(contains? m :value)))
99

10-
;; NOTE: this function produces a runtime error when comparing things of different types
11-
;; ie: (< 3 "foo")
12-
;; Will need to coerce the types in order to get the "Filter expression with boolean or operator and value false"
13-
;; test case to pass
10+
;; 'and' and 'or' are macros in Clojure, so we wrap them in functions here so they
11+
;; can be passed to apply and tested for equality
12+
(defn and* [a b]
13+
(and a b))
14+
15+
(defn or* [a b]
16+
(or a b))
17+
1418
(defn eval-bool-expr [comp-fn context operands]
15-
(boolean (apply comp-fn (map #(eval-expr % context) operands))))
19+
(boolean
20+
(apply
21+
(fn [a b]
22+
(cond
23+
;; allow less-than, greater-than comparisons if both args are Numbers or Strings
24+
(and (contains? #{< <= > >=} comp-fn)
25+
(or (and (number? a) (number? b))
26+
(and (string? a) (string? b))))
27+
(comp-fn a b)
28+
29+
;; always allow equality comparisons as well as 'and' and 'or'
30+
(contains? #{= not= and* or*} comp-fn)
31+
(comp-fn a b)
32+
33+
;; else the two values cannot be compared: return false
34+
:else false))
35+
(map #(eval-expr % context) operands))))
1636

1737
(def boolean-ops
1838
"expression operands that result in a boolean result"
@@ -22,9 +42,9 @@
2242
:lt-eq <=
2343
:gt >
2444
:gt-eq >=
25-
;; NOTE: 'and' and 'or' are macros in Clojure, so we need to wrap them in functions here
26-
:and #(and %1 %2)
27-
:or #(or %1 %2)})
45+
;; NOTE: see comment above, these macros are wrapped as functions
46+
:and and*
47+
:or or*})
2848

2949
(defn eval-expr [[expr-type & operands :as expr] context]
3050
(cond

test/json_path/test/json_path_test.clj

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@
55

66
(unfinished)
77

8+
(def keys-of-many-types
9+
[{:key 1}
10+
{:key 3}
11+
{:key "nice"}
12+
{:key true}
13+
{:key nil}
14+
{:key false}
15+
{:key {}}
16+
{:key []}
17+
{:key -1}
18+
{:key 0}
19+
{:key ""}])
20+
821
(facts
922
(at-path "$" ...json...) => ...json...
1023
(at-path "$.hello" {:hello "world"}) => "world"
@@ -28,25 +41,37 @@
2841
{:id 45, :text "hello"}]}) => ["hello"]
2942
(at-path "$.foo[*].bar[*].baz"
3043
{:foo [{:bar [{:baz "hello"}]}]}) => ["hello"]
44+
;; Filter expression with boolean and operator
3145
(at-path "$[?(@.key>42 && @.key<44)]"
3246
[{:key 42}, {:key 43}, {:key 44}]) => [{:key 43}]
47+
;; Filter expression with boolean and operator and value false
48+
(at-path "$[?(@.key>0 && false)]"
49+
keys-of-many-types) => []
50+
;; Filter expression with boolean and operator and value true
51+
(at-path "$[?(@.key>0 && true)]"
52+
keys-of-many-types) => [{:key 1}, {:key 3}]
53+
;; Filter expression with boolean or operator
3354
(at-path "$[?(@.key>43 || @.key<43)]"
34-
[{:key 42}, {:key 43}, {:key 44}]) => [{:key 42}, {:key 44}])
35-
36-
;; TODO: add this case, comparator is blowing up comparing against different types
37-
;; "Filter expression with boolean or operator and value false"
38-
; (at-path "$[?(@.key>0 && false)]"
39-
; [{:key 1}
40-
; {:key 3}
41-
; {:key "nice"}
42-
; {:key true}
43-
; {:key nil}
44-
; {:key false}
45-
; {:key {}}
46-
; {:key []}
47-
; {:key -1}
48-
; {:key 0}
49-
; {:key ""}]) => []
55+
[{:key 42}, {:key 43}, {:key 44}]) => [{:key 42}, {:key 44}]
56+
;; Filter expression with boolean or operator and value false
57+
(at-path "$[?(@.key>0 || false)]"
58+
keys-of-many-types) => [{:key 1}, {:key 3}]
59+
;; Filter expression with boolean or operator and value true
60+
(at-path "$[?(@.key>0 || true)]"
61+
keys-of-many-types) => keys-of-many-types)
62+
;; TODO: Filter expression with different grouped operators
63+
;; NOTE: the parser will need to be updated in order to get this test to work
64+
; (at-path "$[?(@.a && (@.b || @.c))]"
65+
; [{:a true}
66+
; {:a true, :b true}
67+
; {:a true, :b true, :c true}
68+
; {:b true, :c true}
69+
; {:a true, :c true}
70+
; {:c true}
71+
; {:b true}])
72+
; => [{:a true, :b true}
73+
; {:a true, :b true, :c true}
74+
; {:a true, :c true}])
5075

5176
(facts
5277
(-> (query "$.hello"

0 commit comments

Comments
 (0)