Dave Owens
Dave Owens

Reputation: 121

Defining datalog query components outside of (datomic.api/q '[])

I am working with clojure's datomic.api. I wish to refactor a somewhat complex datalog query such as this:

(datomic.api/q '[:find [?value ...] :in $ ?uid ?component :where
                [...some clause...]
                [...some other clause...]
                (or-join [?entitlement ?component]
                         (and [...some conditional stuff...])
                         (and [...some other conditional stuff...]))]
                db uid component)

...into something more readable. My desire is to locally bind the (and...) components of the query inside a let and refer to them by a name inside of the datalog list. Like so:

(datomic.api/q '[:find [?value ...] :in $ ?uid ?component :where
                [...some clause...]
                [...some other clause...]
                (or-join [?entitlement ?component]
                         entitled-for-component
                         entitled-for-application)]
                db uid component)

Various quoting in let (and unquoting inside of datomic.api/q's list) have not worked. Any suggestions?

Upvotes: 2

Views: 314

Answers (1)

Dave Owens
Dave Owens

Reputation: 121

Datomic uses rules to solve this problem.

Datomic datalog allows you to package up sets of :where clauses into named rules. These rules make query logic reusable, and also composable, meaning that you can bind portions of a query's logic at query time.

Rulesets are defined as a list of lists, then used as an additional input with datomic.api/q bound to the % character.

(def rules [[(name-for-id restaurant-id?)
             [restaurant-id? :restaurant/name name?]]])

(datomic.api/q '[:find ?name . :in $ % ?restaurant-id :where
                 (name-for-id restaurant-id?)] db rules 42)

=> "Milliways"

Note that datomic.api/q expects a rule set, passing a single rule will not work.

The first list in a rule defines the rule name as the first item, followed by one or more parameters. The subsequent vectors contain one or more :where clauses.

Also,

As with other where clauses, you may specify a database before the rule-name to scope the rule to that database. Databases cannot be used as arguments in a rule.

Upvotes: 2

Related Questions