redplanetlabs/specter

Nil as "not found" marker and nil as value. Is it possible to somehow distinguish between the two cases?

char16t opened this issue · 6 comments

Hello.
I have two examples that return nil. In the first case, the data structure I'm looking for contains nil. In the second, I try to get in the same data structure value on a nonexistent path.

First:

(sp/select [:a :ab] {:a {:aa 1 :ab nil}}) ;; => [nil]

Second:

(sp/select [:a :ac] {:a {:aa 1 :ab nil}}) ;; => [nil]

Question: Is it possible to somehow distinguish between the two cases? How do I verify that the requested path exists in the data structure?

I tried this:

(let [p [:a :ab]
      c {:a {:aa 1 :ab nil}}]
  (sp/select
   (sp/if-path (apply sp/must p) p sp/STOP)
   c)) ;; => [nil]

(let [p [:a :ac]
      c {:a {:aa 1 :ab nil}}]
  (sp/select
   (sp/if-path (apply sp/must p) p sp/STOP)
   c)) ;; => []

But this solution returns [] when path is [sp/ALL] for example.


With the suggested solution is the same:

(defn f [p c]
  (sp/select
   (apply sp/must p)
   c))

;; OK
;; not selectable
(empty?
 (f [:a :ac]
    {:a {:aa 1 :ab nil}})) ;; => true

;; OK
;; selectable
(empty?
 (f [:a :ab]
    {:a {:aa 1 :ab nil}})) ;; => false

;; selectable
;; Failed
;; expected false because f should return [:ab]
(empty?
 (f [:a sp/ALL sp/ALL #(= :ab %)]
   {:a {:aa 1 :ab nil}})) ;; => true

I mean that

(sp/select
  [:a sp/ALL sp/ALL #(= :ab %)]
  {:a {:aa 1 :ab nil}}) ;; => [:ab]

and

(sp/select
  (sp/must :a sp/ALL sp/ALL #(= :ab %))
  {:a {:aa 1 :ab nil}}) ;; => []

Not any specter path will be correctly verified by such a solution.

Thanks