-
-
Notifications
You must be signed in to change notification settings - Fork 62
Dispatch helpers
Wilker Lúcio edited this page Sep 24, 2017
·
1 revision
Using multi-methods is a good way to make open readers, pathom
provides helpers for two common dispatch strategies:
key-dispatch
and entity-dispatch
. Here is a pattern that I often use on parsers:
(ns pathom-docs.dispatch-helpers
(:require [com.wsscode.pathom.core :as p]))
(def cities
{"Recife" {:city/name "Recife" :city/country "Brazil"}
"São Paulo" {:city/name "São Paulo" :city/country "Brazil"}})
(def city->neighbors
{"Recife" [{:neighbor/name "Boa Viagem"}
{:neighbor/name "Piedade"}
{:neighbor/name "Casa Amarela"}]})
; this will dispatch according to the ast dispatch-key
(defmulti computed p/key-dispatch)
; use virtual attributes to handle data not present on the maps, like computed attributes, relationships, and globals
(defmethod computed :city/neighbors [env]
(let [name (p/entity-attr! env :city/name)]
(p/join-seq env (city->neighbors name))))
; an example of global, same as before but without any dependency on the entity
(defmethod computed :city/all [env]
(p/join-seq env (vals cities)))
; remember to return ::p/continue by default so non-handled cases can flow
(defmethod computed :default [_] ::p/continue)
; just to make easy to re-use, our base entity reader consists of a map reader + virtual attributes
(def entity-reader [p/map-reader computed])
; dispatch for entity keys, eg: [:user/by-id 123]
(defmulti entity-lookup p/entity-dispatch)
(defmethod entity-lookup :city/by-name [env]
; the ident-value helper extracts the value part from the ident, as "Recife" in [:city/by-name "Recife"]
(let [city (get cities (p/ident-value env))]
(p/join city env)))
(defmethod entity-lookup :default [_] ::p/continue)
(def parser
(p/parser {::p/plugins [(p/env-plugin {::p/reader [p/map-reader computed entity-lookup]})]}))
(parser {} [{:city/all [:city/name]}
{[:city/by-name "Recife"] [:city/neighbors]}])
; =>
;{:city/all [#:city{:name "Recife"} #:city{:name "São Paulo"}]
; [:city/by-name "Recife"] #:city{:neighbors [#:neighbor{:name "Boa Viagem"}
; #:neighbor{:name "Piedade"}
; #:neighbor{:name "Casa Amarela"}]}}