oracle-samples/clara-rules

This CLJS code refuses to work: The query ... is invalid or not included in the rule base

DjebbZ opened this issue · 2 comments

Hello,

I'm reporting what I thing is a bug. My colleague wrote this code, and it fails to run the query part.

Dependencies:
CLJS 1.10.339
clara rules 0.18.0

Context:
We want to use Clara rules to create easy to read/write/maintain/evolve rules to determine when to inject some trackers (think Google Analytics) in our website. For now the rules are simple and could be implemented in pure ClojureScript with ifs but the plan is to have much more complex rules, in which case in our opinion Clara rules will shine.

CLJS Code: (the complete code that fails, so you should normally be able to reproduce it)

(ns trackers.tracking-rules
  (:require [clara.rules :refer [insert retract fire-rules query insert! retract!]
                         :refer-macros [defrule defquery defsession]]
            [clara.tools.tracing :refer [with-tracing get-trace]]))

(defrecord Navigation [id-user page-type])
(defrecord Adblock [id-user adblock])
(defrecord Tracker [id-user tracker])
(defrecord Entity [id-user entity])

(defn create-navigation
  [hash typ]
  (let [{:keys [id-user page-type now-page landing referrer adblock entity]} hash
        tracker :init]

    (cond
      (= typ :nav) (->Navigation id-user page-type)
      (= typ :adb) (->Adblock id-user adblock)
      (= typ :ent) (->Entity id-user entity)
      (= typ :track) (->Tracker id-user tracker))))

;;;;;;;;;;;;;
;;; RULES ;;;
;;;;;;;;;;;;;

(defrule position-wt2
  "Always true"
  [Navigation (= ?id id-user)]
  =>
  (insert! (->Tracker ?id :wt2)))

(defrule position-ga
  "Test if analytics is active"
  [Adblock (= ?id id-user) (= adblock "no")]
  =>
  (insert! (->Tracker ?id :analytics))
  )

(defrule position-facebook
  "Test if facebook is active"
  [Now (= ?id id-user) (= ?now-page now-page)]
  [Adblock (= ?id id-user) (= adblock "no")]
  [:test (= id-user now-page)];test impossible, pas facebook
  =>
  (insert! (->Tracker ?id :facebook))
  )

(defrule position-admo
  "Test if admo is active"
  [Entity (= ?id id-user) (= ?entity entity)]
  [or [:test (= ?entity "fr")]
   [:test (= ?entity "es")]]
  =>
  (insert! (->Tracker ?id :admo ))
  )

(defrule position-tradelab
  "Test if quantcast is active"
  [Entity (= ?id id-user) (= ?entity entity)]
  [Navigation (= ?id id-user) (= ?position page-type)]
  [:test (= ?entity "es")]
  [:test (not (= ?position "shop-step5"))]
  =>
  (insert! (->Tracker ?id :tradelab ))
  )

(defrule position-tradelab2
  "Test if quantcast is active"
  [Entity (= ?id id-user) (= ?entity entity)]
  [Navigation (= ?id id-user) (= ?position page-type)]
  [:test (= ?entity "es")]
  [:test (= ?position "shop-step5")]
  =>
  (insert! (->Tracker ?id :tradelabpanier))
  )

(defrule position-iadvize
  "Test if iadvize is active"
  [Entity (= ?id id-user) (= ?entity entity)]
  [:test (= ?entity "fr")]
  =>
  (insert (->Tracker ?id :iadvize)))

(defrule position-zendesk
  "Test if zendesk is active"
  [Entity (= ?id id-user) (= ?entity entity)]
  [:test (= ?entity "es")]
  =>
  (insert (->Tracker ?id :zendesk)))

(defrule position-bing2
  "Test if bing is active"
  [Navigation (= ?id id-user) (= ?position page-type)]
  [:test (= ?position "shop-step5")]
  =>
  (insert! (->Tracker ?id :bingpanier ))
  )

(defrule position-bing
  "Test if bing is active"
  [Navigation (= ?id id-user) (= ?position page-type)]
  [:test (not (= ?position "shop-step5"))]
  =>
  (insert! (->Tracker ?id :bing ))
  )
(defrule position-adwords
  "Test if adwords is active"
  [Navigation (= ?id id-user) (= ?position page-type)]
  [:test (not (= ?position "shop-step5"))]
  =>
  (insert! (->Tracker ?id :adwords))
  )

(defrule position-gtm
  "Test if gtm is active"
  [Adblock (= ?id id-user) (= adblock "no")]
  =>
  (insert (->Tracker ?id :gtm)))

(defrule position-kenshoo
  "Test if kenshoo is active"
  [Navigation (= ?id id-user) (= ?position page-type)]
  [:test (= ?position "shop-step5")]
  =>
  (insert! (->Tracker ?id :kenshoo))
  )

(defrule position-olark
  "Test if olark is active"
  [Entity (= ?id id-user) (= ?entity entity)]
  [:test (= ?entity "us")]
  =>
  (insert! (->Tracker ?id :kenshoo))
  )

(defquery get-active-tracker
  "get the list of active tracker"
  []
  [?tracking <- Tracker])

(defn construction-list
  [user]
  (->> user
       (map (fn [x] (list (:tracker x))))
       (reduce concat)))

(defn formatage
  [{:keys [page-type entity]
    {{{:keys [client-id]} :ids} :user } :session-data}]
  {:id-user   client-id,
   :page-type page-type,
   :entity    entity
   :adblock   "no"})

(defn validate-trackers
  [params session]
  (try (let [type-page     (create-navigation (formatage params) :nav)
             ok-to-track   (create-navigation (formatage params) :adb)
             tracker-page  (create-navigation (formatage params) :track)
             entity-user   (create-navigation (formatage params) :ent)
             session       (-> session #_(with-tracing session)
                               (insert type-page)
                               (insert ok-to-track)
                               (insert tracker-page)
                               (insert entity-user)
                               (fire-rules)
                               #_(get-trace))]
         ;(prn session)
         ;#{}
         (into #{} (construction-list (into [] (map :?tracking (query session get-active-tracker))))))
       (catch :default e
         (println params)
         (throw e))))

(defsession my-session 'tracking-rules)

(defn list-of-active-tracker
  [params]
  (validate-trackers params my-session))

The call that fails (and shouldn't)

(trackers.tracking-rules/list-of-active-tracker {:page-type "gt"})

I executed this code in several CLJS REPL (the new cljs.main, the new figwheel-main, and with boot-cljs/boot-cljs-repl), and I always got this error:

The query {:lhs [{:type trackers.tracking-rules/Tracker, :constraints [], :fact-binding :?tracking}], :params #{}, :name "trackers.tracking-rules/get-active-tracker", :doc "get the list of active tracker"} is invalid or not included in the rule base.

If you observe the validate-trackers code (towards the end) I included clara.rules.tracing to see if the facts were properly added. Here is the output if I uncomment and use the tracing code instead:

[{:type :add-facts, :node nil, :token nil, :facts (#trackers.tracking-rules.Navigation{:id-user nil, :page-type "gt"})} 
 {:type :add-facts, :node nil, :token nil, :facts (#trackers.tracking-rules.Adblock{:id-user nil, :adblock "no"})} 
 {:type :add-facts, :node nil, :token nil, :facts (#trackers.tracking-rules.Tracker{:id-user nil, :tracker :init})} 
 {:type :add-facts, :node nil, :token nil, :facts (#trackers.tracking-rules.Entity{:id-user nil, :entity nil})}]

I'm no clara-rules expert but the output looks pretty correct to us. It seems that the query defined with defquery isn't working.

Another thing that may be related: in all the REPLs environments cited above, as soon as we edit the code the recompilation fails with this error (this precise output is from Boot-cljs but the message is the same in all REPLs):

java.lang.RuntimeException: Unable to resolve symbol: defrule in this context
clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: Unable to resolve symbol: defrule in this context, compiling:(trackers/tracking_rules.cljc:31:1)

Thanks in advance for looking at this.

  • I think the 'tracking-rules in mk-session here should be 'trackers.tracking-rules, that is the full namespace name. I'd expect this as is to result in a session with no rules or queries, the input here should probably be validated. Can post code links later, on mobile now.
  • "insert" is used outside the rules session, insert! is used in the call stack of a rule RHS (right-hand side).
  • I don't see a definition of your Now record.

Try that and post if that fixes it.

It worked! I did the changes this afternoon after a long period off of this problem. We can move on to more complex rules now.

Thanks a lot!