Подтвердить что ты не робот

Получить все поля из объекта Datomic

В разделе "Встроенный" документа Datomic Queries and Rules говорится:

Языки запросов, такие как SQL, ориентированы вокруг модели клиент-сервер где, в одном разговоре, вы будете иметь оба:

  • Ответьте на свой основной вопрос, например. который купил носки в этом месяце.
  • Восстановить любую дополнительную информацию, необходимую для отчетности и обработки, например. каковы их имена и адреса электронной почты.

Последнее на самом деле не вопрос, это просто механическая навигация к соответствующей информации.

В то время как я ценю, как ортогональность двух различных упомянутых аспектов соблюдается, я думаю, что мне часто нужно получить целую сущность, в зависимости от ее атрибутов.

Насколько я знаю, запросы обычно имеют такую ​​форму:

(datomic.api/q '[:find ?name ?age ?email
                 :where
                 [?e :myapp/name ?name]
                 [?e :myapp/age ?age]
                 [?e :myapp/email ?email]]
               (db conn))

Если бы я хотел получить объекты, у которых есть N атрибутов, я бы хотел, чтобы они перечисляли их все в каждом запросе, что кажется утомительным и подверженным ошибкам.

Как сообщить Datomic для получения объектов со всеми полями, в которых они были сохранены, без необходимости явно указывать их?

4b9b3361

Ответ 1

datomic.api/entity предоставляет такую ​​функциональность.

У него просто есть gotcha, что возвращенная карта имеет собственное представление, которое скрывает все поля, но :db/id. Можно получить доступ к этим полям, но для их печати требуется слияние карты с обычной картой Clojure.

Ответ 2

Наличие объекта (id) из запроса типа:

=> (def eid (d/q '[:find ?e :where [?e :myapp/name "Fred"]] (db conn)))

вы можете получить EntityMap:

=> (def ent (d/entity (db conn) (ffirst eid)))

чтобы вы могли получать доступ к полям/атрибутам без дополнительного запроса:

=> (seq ent)
;; ([:myapp/name "Fred"] [:myapp/age 16] [:myapp/email "[email protected]"])

однако сначала проще получить ключи:

=> (keys ent)
;; (:myapp/name :myapp/age :myapp/email)

Вы даже можете получить обратные ключи ( "внешние" атрибуты ref, указывающие на этот объект), используя следующий трюк:

=> (.touch ent)
=> (keys (.cache ent))

Ответ 3

datomic.api/touch функция

Существует специальная функция datomic.api/touch, чтобы просто "коснуться" всех атрибутов объекта. Объект, возвращаемый функцией entity, ленив, и значение атрибута возвращается только при доступе, < функция href= "http://docs.datomic.com/clojure/#datomic.api/touch" > touch с готовностью извлекает все атрибуты сущности.

Пример:

(let [entity (d/entity db-val (ffirst (d/q '[:find ?e :in $ ?email
                                             :where [?e :user/email ?email]]
                                            db-val email))]
    ;;then just d/touch the entity returned by the d/entity fn
    (d/touch entity))
=> {:user/username "gretchen", :user/email "[email protected]", :user/password "xxxxxx", :db/id 17592186046433}

Ответ 4

Вы можете использовать pull, чтобы получить все поля от сущности или даже только выбор. Используя '[*], поскольку шаблон для pull будет извлекать все поля

См. документация по pull и пояснения.

Чтобы получить все поля из объекта с id eid, используйте:

(d/pull (db conn) '[*] eid)

Pull также может использоваться в запросах:

(datomic.api/q '[:find (pull ?e [*])
                 :where
                 [?e :myapp/name]
               (db conn))

Ответ 5

Я не тестировал его, но если я правильно помню, вы можете просто поместить переменную в качестве имени атрибута

(datomic.api/q '[:find ?key ?value
             :where
             [?e ?key ?value]]
           (db conn))