This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-06-20
Channels
- # announcements (1)
- # beginners (17)
- # calva (16)
- # cljfx (5)
- # clojure (94)
- # clojure-europe (1)
- # clojure-italy (2)
- # clojure-spec (4)
- # clojure-uk (1)
- # core-async (12)
- # datahike (3)
- # datomic (6)
- # depstar (4)
- # fulcro (30)
- # introduce-yourself (2)
- # malli (1)
- # off-topic (10)
- # re-frame (71)
- # shadow-cljs (15)
- # tools-deps (3)
- # xtdb (12)
the other day i asked about how to audit which query rules are satisfied and favila had a nice suggestion to use ground
to return some known value. that works when my "top level" rule returns a grounded value, however i'd like to also audit nested rules as well. any idea how i can aggregate some grounded values from each rule?
here is a non-working example that returns an empty result because i think the bound value of ?rule
in the parent rule fails to unify on the different bound values in the nested rules.
(let [rules '[[(is-blue ?item ?rule)
[(ground :is-blue) ?rule]
[?item :item/color "blue"]]
[(is-in-stock ?item ?rule)
[(ground :is-in-stock) ?rule]
[?item :item/inStock? true]]
[(blue-items-in-stock ?item ?rule)
[(ground :blue-items-in-stock) ?rule]
(is-blue ?item ?rule)
(is-in-stock ?item ?rule)]]]
(d/q '{:find [?item (distinct ?rule)]
:in [$ %]
:where [(blue-items-in-stock ?item ?rule)]}
(d/db conn) rules))
=> []
ideally i would end up with something like this:
=> [[92358976734084 #{:blue-items-in-stock :is-blue :is-in-stock}]]
@joshkh it's your lucky day 🙂
tl;dr, use clojure.core/tap>
and add however much tracing you want, whether it's just a single value or a map that you construct in your rule in order to capture the inputs.
The below snippet should be added to the siderail
(with whatever filename you want) of https://github.com/Datomic/ion-starter .
;; This assumes you're using dev-local, and have dev-local as a dependency.
;; Edit resources/datomic/ion/starter/config.edn to match your system
(require
'[clojure.data.json :as json]
'[clojure.edn :as edn]
'[ :as io]
'[clojure.pprint :as pp]
'[datomic.client.api :as d]
'[datomic.dev-local :as dl]
'[datomic.ion.starter :as starter]
'[datomic.ion.starter.attributes :as attrs]
'[datomic.ion.starter.edn :as s-edn]
'[datomic.ion.starter.lambdas :as lambdas]
'[datomic.ion.starter.http :as http]
'[datomic.ion.starter.inventory :as inventory]
'[datomic.ion.starter.utils :as utils])
(if-let [r (io/resource "datomic/ion/starter/config.edn")]
(dl/divert-system (edn/read-string (slurp r)))
(throw (RuntimeException. "You need to add a resource datomic/ion/starter/config.edn with your connection config")))
;; test that config works
(def client (starter/get-client))
;; create database and load sample data:
(starter/ensure-sample-dataset)
(def conn (starter/get-connection))
@(def db (d/db conn))
;; Does tap work in queries?
(def rules
'[[(trace> [?tracer])
[(java.util.Date.) ?nt]
[(assoc ?tracer :at ?nt) ?t]
[(tap> ?t) _]]
[(by-type [?type] ?e)
;pre
[(hash-map :phase :pre :rule 'by-type :type ?type :e ?e) ?pre]
(trace> ?pre)
;rule
[?e :inv/type ?type]
;post
[(hash-map :phase :post :rule 'by-type :type ?type :e ?e) ?post]
(trace> ?post)]
[(by-size [?size] ?e)
;pre
[(hash-map :phase :pre :rule 'by-size :size ?size :e ?e) ?pre]
(trace> ?pre)
;rule
[?e :inv/size ?size]
;post
[(hash-map :phase :post :rule 'by-size :size ?size :e ?e) ?post]
(trace> ?post)]
[(by-type-and-size [?type ?size] ?e)
;pre
[(hash-map :phase :pre :rule 'by-type-and-size :type ?type :size ?size) ?pre]
(trace> ?pre)
;rule
(by-type ?type ?e)
(by-size ?size ?e)
; post
[(hash-map :phase :post :rule 'by-type-and-size :type ?type :size ?size :e ?e) ?post]
(trace> ?post)
]])
(defn get-items-by-type-and-size
"Returns pull maps describing all items matching type"
[db type size pull-expr]
(d/q '[:find (pull ?e pull-expr)
:in $ % ?type ?size pull-expr
:where
(by-type-and-size ?type ?size ?e)]
db rules type size pull-expr))
(get-items-by-type-and-size db :shirt :small '[:inv/sku :inv/color :inv/size])
Attached is a screenshot showing the output in REBL after executing get-items-by-type-and-size
then browsing the tapped values as a collection of maps.well this is exactly what i was looking for. thank you @U0CJ19XAM!
NP, I just wish I would have thought of it sooner 😂 . Definitely could have used this over the years.
@joshkh it's your lucky day 🙂
tl;dr, use clojure.core/tap>
and add however much tracing you want, whether it's just a single value or a map that you construct in your rule in order to capture the inputs.
The below snippet should be added to the siderail
(with whatever filename you want) of https://github.com/Datomic/ion-starter .
;; This assumes you're using dev-local, and have dev-local as a dependency.
;; Edit resources/datomic/ion/starter/config.edn to match your system
(require
'[clojure.data.json :as json]
'[clojure.edn :as edn]
'[ :as io]
'[clojure.pprint :as pp]
'[datomic.client.api :as d]
'[datomic.dev-local :as dl]
'[datomic.ion.starter :as starter]
'[datomic.ion.starter.attributes :as attrs]
'[datomic.ion.starter.edn :as s-edn]
'[datomic.ion.starter.lambdas :as lambdas]
'[datomic.ion.starter.http :as http]
'[datomic.ion.starter.inventory :as inventory]
'[datomic.ion.starter.utils :as utils])
(if-let [r (io/resource "datomic/ion/starter/config.edn")]
(dl/divert-system (edn/read-string (slurp r)))
(throw (RuntimeException. "You need to add a resource datomic/ion/starter/config.edn with your connection config")))
;; test that config works
(def client (starter/get-client))
;; create database and load sample data:
(starter/ensure-sample-dataset)
(def conn (starter/get-connection))
@(def db (d/db conn))
;; Does tap work in queries?
(def rules
'[[(trace> [?tracer])
[(java.util.Date.) ?nt]
[(assoc ?tracer :at ?nt) ?t]
[(tap> ?t) _]]
[(by-type [?type] ?e)
;pre
[(hash-map :phase :pre :rule 'by-type :type ?type :e ?e) ?pre]
(trace> ?pre)
;rule
[?e :inv/type ?type]
;post
[(hash-map :phase :post :rule 'by-type :type ?type :e ?e) ?post]
(trace> ?post)]
[(by-size [?size] ?e)
;pre
[(hash-map :phase :pre :rule 'by-size :size ?size :e ?e) ?pre]
(trace> ?pre)
;rule
[?e :inv/size ?size]
;post
[(hash-map :phase :post :rule 'by-size :size ?size :e ?e) ?post]
(trace> ?post)]
[(by-type-and-size [?type ?size] ?e)
;pre
[(hash-map :phase :pre :rule 'by-type-and-size :type ?type :size ?size) ?pre]
(trace> ?pre)
;rule
(by-type ?type ?e)
(by-size ?size ?e)
; post
[(hash-map :phase :post :rule 'by-type-and-size :type ?type :size ?size :e ?e) ?post]
(trace> ?post)
]])
(defn get-items-by-type-and-size
"Returns pull maps describing all items matching type"
[db type size pull-expr]
(d/q '[:find (pull ?e pull-expr)
:in $ % ?type ?size pull-expr
:where
(by-type-and-size ?type ?size ?e)]
db rules type size pull-expr))
(get-items-by-type-and-size db :shirt :small '[:inv/sku :inv/color :inv/size])
Attached is a screenshot showing the output in REBL after executing get-items-by-type-and-size
then browsing the tapped values as a collection of maps.