(defn
add-rule
"Adds a rule to the given session."
[session rule]
(when
(get-in session [:rule-name->node-id (:name rule)])
(throw (ex-info (str (:name rule) " already exists in session") {})))
(let
[conditions
(:conditions rule)
session
(reduce add-condition session conditions)
leaf-node-id
(-> session :mem-node-ids last)
bindings
(:bindings session)
session
(reduce
(fn
[session mem-node-id]
(update-in
session
[:beta-nodes mem-node-id]
(fn
[mem-node]
(assoc
mem-node
:leaf-node-id
leaf-node-id
:what-fn
(:what-fn rule)))))
session
(:mem-node-ids session))
session
(reduce
(fn
[session join-node-id]
(update-in
session
[:beta-nodes join-node-id]
(fn
[join-node]
(let
[joined-key
(some
(fn [{:keys [field key]}] (when (= :value field) key))
(-> join-node :condition :bindings))
disable-fast-updates
(clojure.core/contains? (:joins bindings) joined-key)]
(when
(and
disable-fast-updates
(->
(get-in session [:beta-nodes (:child-id join-node)])
:condition
:opts
:then
first
(= :func)))
(throw
(ex-info
(str
"In "
(:name rule)
" you are making a join with the symbol `"
(symbol joined-key)
"`, "
"and passing a custom function in the {:then ...} option. This is not allowed due to "
"how the implementation works. Luckily, it's easy to fix! Get rid of this join in your :what "
"block by giving the symbol a different name, such as `"
(symbol (str (name joined-key) 2))
"`, "
"and then enforce the join in your :when block like this: "
(list
'=
(symbol joined-key)
(symbol (str (name joined-key) 2))))
{})))
(assoc
join-node
:id-key
(some
(fn
[{:keys [field key]}]
(when
(and
(= :id field)
(clojure.core/contains? (:joins bindings) key))
key))
(-> join-node :condition :bindings))
:disable-fast-updates
disable-fast-updates)))))
session
(:join-node-ids session))]
(->
session
(assoc-in [:beta-nodes leaf-node-id :when-fn] (:when-fn rule))
(assoc-in [:beta-nodes leaf-node-id :then-fn] (:then-fn rule))
(assoc-in
[:beta-nodes leaf-node-id :then-finally-fn]
(:then-finally-fn rule))
(assoc-in [:rule-name->node-id (:name rule)] leaf-node-id)
(assoc-in [:node-id->rule-name leaf-node-id] (:name rule))
(dissoc :mem-node-ids :join-node-ids :bindings))))