If you use the accumulator function of clara-rules, you can realize something like an aggregate function in sql, so try it this time. I will see it.
--Use the one in the clara.rules.accumulators
namespace
--Min / max / sum etc. are provided by default
--You can also create your own accumulator (accum function)
--Can be used in defquery
on the left side of defrule
[<variable name to bind> <-<accumulator>: from [<fact> + <constraint>]]
I tried the following code.
(ns clara-rules.accumulator
(:require [clara.rules :refer [fire-rules insert mk-session query defquery]]
[clara.rules.accumulators :as acc]))
(defrecord SomeAmount [id amt])
(defquery test-query
[]
[?largest-amt <- (acc/max :amt) :from [SomeAmount]]
[?total <- (acc/sum :amt) :from [SomeAmount]]
[?grouped <- (acc/grouping-by :id) :from [SomeAmount]]
;;Total by groups
[?grouped-and-summed
<- (acc/grouping-by :id (fn [m]
;;Accepts map key=field for grouping
;;value=seq of maps of records that were grouped
(map (fn [[k seq-of-records]]
{k (reduce + (map :amt seq-of-records))})
m)))
:from [SomeAmount]])
(-> (mk-session)
(insert (->SomeAmount :a 4)
(->SomeAmount :a 8)
(->SomeAmount :b 32)
(->SomeAmount :b 21)
(->SomeAmount :c 1)
(->SomeAmount :c 9))
(fire-rules)
(query test-query))
;; => ({:?largest-amt 32,
;; :?total 75,
;; :?grouped {:a [#clara_rules.accumulator.SomeAmount{:id :a, :amt 4}
;; #clara_rules.accumulator.SomeAmount{:id :a, :amt 8}],
;; :b [#clara_rules.accumulator.SomeAmount{:id :b, :amt 32}
;; #clara_rules.accumulator.SomeAmount{:id :b, :amt 21}],
;; :c [#clara_rules.accumulator.SomeAmount{:id :c, :amt 1}
;; #clara_rules.accumulator.SomeAmount{:id :c, :amt 9}]},
;; :?grouped-and-summed ({:a 12} {:b 53} {:c 10})})
Recommended Posts