Mild bikeshedding: how do you typically go about documenting rules in production? Just comments where they're defined? Mostly in tests? Or some other scheme?
Each rule is a var, so you can add docstrings to them? Then assemble the rule set selectively. Maybe even have some EDN files to keep the rules?
I would treat rules as source code.
Same with schema. They are all source code.
Ah that would be nicer, I've been defining them in the one big quoted-list so far, breaking them up would probably be neater :^) ty!
Going through and trying to more thoroughly test my rules, and trying to wrap my head around an interaction here: Given the DB
(def rule-tst-conn
(d/get-conn "/var/tmp/datalevin/rule-test-db"
{:rel/from {:db/valueType :db.type/ref}
:rel/type {:db/valueType :db.type/keyword}
:rel/to {:db/valueType :db.type/ref}
:company/name {:db/valueType :db.type/string, :db/unique :db.unique/identity}}))
(d/transact! rule-tst-conn
[{:db/id 1 :company/name "A"}
{:db/id 2 :company/name "B"}
{:db/id 3 :company/name "Lonely"}
{:rel/from 1 :rel/type :alias :rel/to 2}])
And the following rule, trying to model bidirectional relationships
(def tst-rules
'[[(bidirectional-rel ?type ?a ?b)
[?rel :rel/from ?a]
[?rel :rel/type ?type]
[?rel :rel/to ?b]]
[(bidirectional-rel ?type ?a ?b)
[?rel :rel/from ?b]
[?rel :rel/type ?type]
[?rel :rel/to ?a]]])
This query returns what I think I'd expect, the two presentations of the bidirectional relationship between entity 1 and 2, the only one in the DB:
(d/q
'[:find ?c1 ?type ?c2
:in $ %
:where
(bidirectional-rel ?type ?c1 ?c2)]
(d/db rule-tst-conn)
tst-rules)
;; => #{[2 :alias 1] [1 :alias 2]}
But this one, when using an entity which should have no relationship, confuses me:
(d/q
'[:find ?c1 ?type ?c2
:in $ %
:where
[?c1 :company/name "Lonely"]
(bidirectional-rel ?type ?c1 ?c2)]
(d/db rule-tst-conn)
tst-rules)
;; => #{[3 :alias 1]}
Why does my bidirectional-rel rule have a 'match' for Lonely here?This is a bug in the optimizer. We pull out non-recursive rules and expand multi-branch rules into or-join, and there's a bug in there. I will find a fix.
It's an edge case in the query engine. Projection is dropping empty relation when that relation doesn't have exported or-join variables. Shouldn't drop it. Fixed in master.