Skip to content

Commit

Permalink
Init
Browse files Browse the repository at this point in the history
  • Loading branch information
souenzzo committed Jun 8, 2020
0 parents commit b727874
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.idea/
*.iml
.nrepl-port
target/
.cpcache/
15 changes: 15 additions & 0 deletions .idea/runConfigurations/REPL.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# eql-inspect

Utility functions to get information about queries and data.

## Usage

Add to your `deps.edn`
```clojure
net.molequedeideias/eql-inspect {:git/url "https://github.com/molequedeideias/eql-inspect"
:sha "..."}
```

> TIP: This isn't "eql validation".
### Quick example:

```clojure
(require '[net.molequedeideias.eql-inspect :as eql-inspect])

(eql-inspect/explain-data {::eql-inspect/value {:a 42 :b 42}
::eql-inspect/alias-key :as
::eql-inspect/query [:a {:b [:c]} :d {:e [:f]}]})
=> {:net.molequedeideias.eql-inspect/value {:a 42, :b 42},
:net.molequedeideias.eql-inspect/alias-key :as,
:net.molequedeideias.eql-inspect/query [:a {:b [:c]} :d {:e [:f]}],
:net.molequedeideias.eql-inspect/problems ({:property :c,
:dispatch-key :c,
:path [:b],
:value 42,
:problem :net.molequedeideias.eql-inspect/expect-collection}
{:property :d,
:dispatch-key :d,
:path [],
:problem :net.molequedeideias.eql-inspect/missing-value}
{:property :e,
:dispatch-key :e,
:path [],
:query [:f],
:problem :net.molequedeideias.eql-inspect/missing-value})}
```

Checkout `test` dir for more exaples

### Real World usage

My current usage is on a REST API.

My REST HANDLERS describe which data it need in `EQL`

Once this handle throws, I use this library to give a better error to my API Consumer.
5 changes: 5 additions & 0 deletions deps.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{:deps {edn-query-language/eql {:mvn/version "1.0.0"}}
:aliases {:dev {:extra-paths ["test"]
:extra-deps {com.wsscode/pathom {:mvn/version "2.2.30"}
org.clojure/clojure {:mvn/version "1.10.1"}
org.clojure/test.check {:mvn/version "0.10.0"}}}}}
47 changes: 47 additions & 0 deletions src/net/molequedeideias/eql_inspect.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
(ns net.molequedeideias.eql-inspect
(:require [edn-query-language.core :as eql]))

(defn explain-query-xf
[{::keys [value path alias-key]
:or {path []}
:as opts}]
(comp (map (fn [{:keys [dispatch-key children params] :as node}]
(let [property (if (contains? opts ::alias-key)
(get params alias-key dispatch-key)
dispatch-key)
problem (cond-> {:property property
:dispatch-key dispatch-key
:path path}
children (assoc :query (eql/ast->query {:type :root :children children})))]
(cond
(map? value) (if-not (contains? value property)
[(assoc problem
:problem ::missing-value)]
(sequence
(explain-query-xf (assoc opts
::value (get value property)
::path (conj path property)))
children))
(coll? value) (into []
(comp (map-indexed
(fn [idx value]
(sequence
(explain-query-xf (assoc opts
::value value
::path (conj path idx)))
[node])))
cat)
value)
:else [(assoc problem
:value value
:problem ::expect-collection)]))))
cat))

(defn explain-data
[{::keys [query] :as opts}]
(let [problems (sequence
(explain-query-xf opts)
(:children (eql/query->ast query)))]
(when-not (empty? problems)
(assoc opts
::problems problems))))
111 changes: 111 additions & 0 deletions test/net/molequedeideias/eql_inspect_test.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
(ns net.molequedeideias.eql-inspect-test
(:require [clojure.test :refer [deftest is testing]]
[net.molequedeideias.eql-inspect :as eql-inspect]))

(defn problems
[query value]
(some-> (eql-inspect/explain-data {::eql-inspect/value value
::eql-inspect/alias-key :as
::eql-inspect/query query})
#_(doto clojure.pprint/pprint)
::eql-inspect/problems
vec))

(deftest explain-query
(testing
"simple"
(is (= [{:dispatch-key :b
:path []
:problem ::eql-inspect/missing-value
:property :b}]
(problems [:a :b]
{:a 1}))))
(testing
"coll of coll of coll"
(is (= [{:property :b
:dispatch-key :b
:problem ::eql-inspect/missing-value
:path [0 0 0]}]
(problems [:a :b]
[[[{:a 1}]]]))))
(testing
"nested"
(is (= [{:dispatch-key :d
:property :d
:problem ::eql-inspect/missing-value
:path [:b]}]
(problems [:a {:b [:c :d]}]
{:a 1
:b {:c 42}}))))
(testing
"nested with coll"
(is (= [{:dispatch-key :c
:problem ::eql-inspect/missing-value
:property :c
:path [:b 1]}
{:dispatch-key :d
:property :d
:problem ::eql-inspect/missing-value
:path [:b 0]}]
(problems [:a {:b [:c :d]}]
{:a 1
:b [{:c 42}
{:d 42}]}))))
(testing
"nested with coll and join"
(is (= [{:dispatch-key :c
:problem ::eql-inspect/missing-value
:path [:b 1]
:property :c}
{:dispatch-key :d
:problem ::eql-inspect/missing-value
:path [:b 0]
:property :d
:query [:e :f]}
{:dispatch-key :f
:problem ::eql-inspect/missing-value
:path [:b 1 :d 0]
:property :f}]
(problems [:a {:b [:c {:d [:e :f]}]}]
{:a 1
:b [{:c 42}
{:d [{:e 42}]}]}))))
(testing
"nested with root missing"
(is (= [{:dispatch-key :b
:path []
:property :b
:problem ::eql-inspect/missing-value
:query [:c :d]}]
(problems [:a {:b [:c :d]}]
{:a 1}))))
(testing
"simple with alias"
(is (= [{:dispatch-key :b
:property :c
:problem ::eql-inspect/missing-value
:path []}]
(problems `[:a (:b {:as :c})]
{:a 1}))))
(testing
"join with alias"
(is (= [{:dispatch-key :d
:problem ::eql-inspect/missing-value
:property :e
:path [:c]}]
(problems `[:a
{(:b {:as :c})
[(:d {:as :e})]}]
{:a 42
:c {:d 42}}))))
(testing
"join with value"
(is (= [{:dispatch-key :c
:property :c
:problem ::eql-inspect/expect-collection
:value 42
:path [:b]}]
(problems `[:a
{:b [:c]}]
{:a 42
:b 42})))))

0 comments on commit b727874

Please sign in to comment.