Composable datalog queries - eponai/sulolive GitHub Wiki
We created a small libraries to easier create and compose datomic queries. Our datomic queries are maps all the way until the query is executed.
Format
{:find <find-pattern>
:where <where-clauses>
:symbols <map-from-symbol-to-value>
:with <with-symbol>
:fulltext <seq of maps describing a full text search>
:rules <seq of functions returning rules>}
Example
;; Given a first name and keywords describing the person, create a
;; query finding users matching the description.
(def query
{:where '[[?e :user/first-name ?first-name]
[?e :user/description ?description]]
:symbols {'?first-name "Jessica"
'[?keywords ...] ["clojure" "dev"]}
:fulltext '[{:attr :user/description
:arg ?keywords
:return [?e ?description _ ?score](/eponai/sulolive/wiki/?e-?description-_-?score)}]}
;; Given this query, we can now use it in different ways.
(require '[eponai.common.database :as db])
;; Gets the first match by adding :find clause '[?e .]
(db/one-with db query)
;; Gets all matches by adding :find clause '[?e ...](/eponai/sulolive/wiki/?e-...)
(db/all-with db query)
;; Specify our own find pattern:
(db/find-with db (db/merge-query query
{:find '[?user ?description (max ?score)](/eponai/sulolive/wiki/?user-?description-(max-?score))})
;; Note: db/merge-query can merge any of the keys, so we can for example
;; more symbols, where-clauses or fulltext searches, any time we want.
Library properties
- Queries can be merged with other queries using
(merge-query base addition). - Values normally passed as extra arguments to
datomic.api/qis passed to the:symbolsmap. - Rules are passed as 0-arity functions that return rules. They are deduped before query is executed.
- Separate and combined functions for pull:
(db/pull db pattern id)(db/pull-many db pattern ids)(db/pull-one-with db pattern query)(db/pull-all-with db pattern query)
- Fulltext search works for both datomic and (normally not supported) datascript. The key takes a list of searches, where each search is a map with
#{:attr :arg :return :db}where:dbis optional.- :attr - the attribute to search values for
- :arg - symbol providing search string
- :return - a where clause describing the return value with format
'[?entity-id ?value ?tx ?relevance-score](/eponai/sulolive/wiki/?entity-id-?value-?tx-?relevance-score) - :db - optional db symbol, defaults to
$
Omitting :find from queries
We found that we usually just want to return one or many datoms matching the query, so we usually don't supply a find pattern, and instead call our functions one-with or all-with, which adds the [?e .] or [?e ...](/eponai/sulolive/wiki/?e-...) find pattern respectively.
Using one-with and all-with reads quite nicely in the code as well. If you want to use your own find-pattern, use (db/find-with db query).
The functions in the entire eponai.common.database library is made to work with both datomic and datascript. The functions will do protocol dispatch on the database-connection or database-value argument.