Are nested lookup refs in composite tuples supported in datomic?

Viewed 139

I'm using Datomic Ions to develop an application. In my schema I use composite tuples to guarantee uniqueness: shelves have books and the shelf+book combination must be unique. This is my schema:

{:db/ident :shelf/name
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one
  :db/unique :db.unique/value
  :db/doc "A shelf is a grouping of books"}

 ;; Books

 {:db/ident :book/shelf
  :db/valueType :db.type/ref
  :db/isComponent true
  :db/cardinality :db.cardinality/one
  :db/doc "Shelf this book belongs to"}

 {:db/ident :book/id
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one
  :db/doc "The book identifier"}

 ;; Shelf + Book combination must be unique
 {:db/ident :book/shelf+book
  :db/valueType :db.type/tuple
  :db/tupleAttrs [:book/shelf :book/id]
  :db/cardinality :db.cardinality/one
  :db/unique :db.unique/identity}

With the schema above I can do the following pull/queries:

(d/pull db '[*] [:shelf/name "my-shelf"])

Returns: {:db/id 74766790688854, :shelf/name "my-shelf"}

And:

(d/q '[:find ?b ?id
       :in $ ?shelf+book
       :where [?b :book/shelf+book ?shelf+book]
              [?b :book/id ?id]]
     db [74766790688854 "book-1"])

Returns: [[101155069755527 "book-1"]].

However I would like to use a lookup ref to resolve the shelf reference in a single query to avoid having to do a separate query to get the shelf reference, something like:

(d/q '[:find ?b ?id
       :in $ ?shelf+book
       :where
       [?b :book/shelf+book ?shelf+book]
       [?b :book/id ?id]]
     db [[:shelf/name "my-shelf"] "book-1"])

But the above returns []. Is it possible to nest lookup refs like the above example?

1 Answers

I never tried this with composite tuples, but this is how it works in principle:

You can use the pull API inside normal queries like so:

(d/q '[:find ?id (pull ?b [:shelf/name])
       :in $ ?shelf+book
       :where
       [?b :book/shelf+book ?shelf+book]
       [?b :book/id ?id]]
 db [[:shelf/name "my-shelf"] "book-1"])

I use this a lot for querying graphs inside datomic. Here's an example from my application:

(d/q '[:find
       ?id
       (pull ?t [:db/ident])
       (pull ?target-node [:my.graph.node/id
                           :my.graph.node/label])
       :where
       [?e :my.graph.edge/id ?id]
       [?e :my.graph.edge/type ?t]
       [?e :my.graph.edge/target ?target-node]]
       db)

Where my.graph.edge/target is a :ref and my.graph.edge/type is the value of an enum.

An example output would be

 [[#uuid"8e5fb3a4-1cac-40e2-ab8f-33352b6cabb3"
   #:db{:ident :my.graph.edge.type/relationship}
   #:my.graph.node{:label "Some node"}]
  ...]
Related