This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-04-10
Channels
- # aleph (3)
- # announcements (1)
- # architecture (16)
- # bangalore-clj (1)
- # beginners (65)
- # biff (5)
- # calva (23)
- # clj-kondo (6)
- # clj-otel (12)
- # clojure-austin (2)
- # clojure-europe (11)
- # clojure-norway (7)
- # clojure-uk (1)
- # clojuredesign-podcast (2)
- # clojurescript (18)
- # conjure (3)
- # datomic (1)
- # deps-new (18)
- # events (1)
- # hyperfiddle (14)
- # java (4)
- # malli (5)
- # off-topic (10)
- # pathom (13)
- # polylith (10)
- # practicalli (1)
- # re-frame (3)
- # reitit (16)
- # releases (1)
- # rum (5)
- # shadow-cljs (17)
Hello Pathom experts! I have a question on data abstraction in pathom3 (moved to thread)
In the following example, I have a toy database (a key-value store), which can hold values of arbitraty "types" (in this case users and companies). I'd like to explain to pathom just once how to get values out of the database by key, and separately define what "types" of data can be found in the database. This is what I tried at first, so far so good
(def store {1 {:user {:name "Alice"}
:company/id 2}
2 {:company {:name "Acme"}}})
(p3-conn-op/defresolver store-fetch [{:keys [store]} {:store/keys [key]}]
{:store/val (get store key)})
; query 1
(p3-iface-eql/process
(-> (p3-conn-idx/register
[store-fetch])
(assoc :store store))
{:store/key 1}
[:store/val])
;; => #:store{:val {:user {:name "Alice"}, :company/id 2}}
; query 2
(def user<->keyval [(p3-builtin-resolvers/alias-resolver :user/id :store/key)
(p3-builtin-resolvers/alias-resolver :store/val :user)])
(p3-conn-op/defresolver user [{:keys [user]}]
{::p3-conn-op/output [:user/name :company/id]}
user)
(p3-iface-eql/process
(-> (p3-conn-idx/register
[store-fetch
user<->keyval
user])
(assoc :store store))
{:user/id 1}
[:company/id])
;; => #:company{:id 2}
However, when I try to join users and companies, this happens. Understandably, because the planner finds that it can already resolve a :user/id
to a :store/val
via a shorter path without performing the join.
; query 3
(def company<->keyval [(p3-builtin-resolvers/alias-resolver :company/id :store/key)
(p3-builtin-resolvers/alias-resolver :store/val :company)])
(p3-iface-eql/process
(-> (p3-conn-idx/register
[store-fetch
user<->keyval
user
company<->keyval])
(assoc :store store))
{:user/id 1}
[:company])
;; => {:company {:user {:name "Alice"}, :company/id 2}}
So this is what I came up with to get the planner to behave the way I want
; query 4
(defn store-fetch-maker [in out]
(p3-conn-op/resolver {::p3-conn-op/op-name (symbol in)
::p3-conn-op/input [in]
::p3-conn-op/output [out]
::p3-conn-op/resolve (fn [{:keys [store]} input]
(->> in
(get input)
(get store)
(assoc {} out)))}))
(p3-iface-eql/process
(-> (p3-conn-idx/register
[(store-fetch-maker :user/id :user)
(store-fetch-maker :company/id :company)
user])
(assoc :store store))
{:user/id 1}
[:company])
;; => {:company {:company {:name "Acme"}}}
Is there a more idiomatic way?
Thanks!
p.s. here's the :require
, in case you'd like to run some of this code
(:require [com.wsscode.pathom3.interface.eql :as p3-iface-eql]
[com.wsscode.pathom3.connect.indexes :as p3-conn-idx]
[com.wsscode.pathom3.connect.built-in.resolvers :as p3-builtin-resolvers]
[com.wsscode.pathom3.connect.operation :as p3-conn-op])
Basically I'd need to tell pathom "either use both rules in user<->keyval
or neither" (same for company<->keyval
)
So I have some polymorphic resolvers but they simply resolve to a concrete identifier that is unique for a particular concrete class.
I think you want to resolve using eg :company/id and if you want a polymorphic generic id to resolve then build that on top? Eg for some of my resolvers I can tell the type by looking at the identifier and then resolve on that.
Intesting, thanks for answering! > resolve to a concrete identifier that is unique for a particular concrete class At resolver-declaration-time I imagine, or rather in the pathom execution phase? If the latter, how does the query planner have enough output info to do its job? > if you want a polymorphic generic id to resolve then build that on top? I am not sure I get this; as before, do you mean something that does this resolution ahead of time (that is, at resolver-declaration-time)?
For my use, the dynamic side is mostly at execution phase so my resolver looks at a generic id and turns it into a more concrete lookup based on the format of the identifier. But you can generate your resolvers dynamically as well based on information sourced from a database or equivalent. Eg https://github.com/wardle/deprivare/blob/main/src/com/eldrix/deprivare/graph.clj That code is generating a single resolver and telling Pathom the properties that can be resolved using it given the inputs.
Hi! I need help using a JSON interface to a working Pathom 3 implementation. What is the best way to do this? I had transit before but now I am implementing in a language that doesn’t have trnasit and I want to use application/json
for both mutations and resolvers. I want to avoid GraphQL as I don’t have a lot of time. Any suggestions? Thanks in advance!
https://github.com/wilkerlucio/edn-json is a lossless edn<->json converter made for cases like this where you intend to actually manipulate the data structure on the json side, could be a good fit
Thanks @U74MQ2347. Unfortunately, the client is not written in CLJS.