Что-то, на что я наткнулся, пытаясь использовать Compassus:
Допустим, у вас есть сложный запрос на объединение/объединение, который включает параметрические подзапросы. Что-то вроде этого:
`[({:foo/info
{:foo/header [:foo-id :name]
:foo/details [:id :description :title]}} {:foo-id ~'?foo-id
:foo-desc ~'?foo-desc})]
Теперь предположим, что вы хотите установить параметры, чтобы на сервере вы могли проанализировать их с помощью om/parser и увидеть эти параметры как 3-й аргумент отправки read
. Конечно, можно написать функцию, которая найдет в запросе все необходимые параметры и установит значения. Однако это непросто, и, как я уже сказал, представьте, что ваши запросы могут быть довольно сложными.
Итак, что вы можете сделать, так это модифицировать ast, так как ast включает в себя ключ :children :params
. Предположим, что фактические значения для :foo-id
и :foo-desc
находятся в атоме состояния под ключом :route-params
:
(defn set-ast-params [children params]
"traverses given vector of `children' in an AST and sets `params`"
(mapv
(fn [c]
(let [ks (clojure.set/intersection (-> params keys set)
(-> c :params keys set))]
(update-in c [:params] #(merge % (select-keys params (vec ks))))))
children))
(defmethod readf :foo/info
[{:keys [state query ast] :as env} k params]
(let [{:keys [route-params] :as st} @state
ast' (-> ast
(update :children #(set-ast-params % route-params))
om/ast->query
om.next.impl.parser/expr->ast)]
{:value (get st k)
:remote ast'}))
Итак, в основном вы: - захватываете ast - изменяете его с фактическими значениями, которые, как вы думаете, возможно, вы можете отправить их на сервер прямо сейчас. Увы, нет! Еще нет. Дело в том, что когда вы делаете {:remote ast}
, Ом берет :query
часть аста, составляет из него аст и потом отправляет на сервер. Итак, вам действительно нужно: превратить ваш измененный ast в запрос, а затем снова преобразовать его обратно в ast.
Примечания:
set-ast-params
в этом примере будет работать только для первого уровня (если у вас есть вложенные параметризованные запросы - не будет работать), сделайте рекурсивным - это не сложно
есть два разных способа превратить ast в запрос и наоборот:
(om/ast->query) ;; retrieves query from ast and sets the params based
;; of `:params` key of the ast, BUT. it modifies the query,
;; if you have a join query it takes only the first item in it. e.g. :
[({:foo/foo [:id]
:bar/bar [:id]} {:id ~'?id})]
;; will lose its `:bar` part
(om.next.impl.parser/ast->expr) ;; retrieves query from an ast,
;; but doesn't set query params based on `:params` keys of the ast.
;; there are also
(om/query->ast) ;; and
(om.next.impl.parser/expr->ast)
person
iLemming
schedule
22.10.2016