This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-02-02
Channels
- # announcements (3)
- # asami (29)
- # babashka (62)
- # beginners (131)
- # biff (7)
- # calva (31)
- # cider (5)
- # clerk (14)
- # clj-kondo (3)
- # cljsrn (12)
- # clojars (18)
- # clojure (72)
- # clojure-austin (17)
- # clojure-dev (6)
- # clojure-europe (31)
- # clojure-indonesia (1)
- # clojure-nl (1)
- # clojure-norway (18)
- # clojure-sweden (11)
- # clojure-uk (6)
- # clr (47)
- # conjure (42)
- # cursive (88)
- # datalevin (2)
- # datomic (25)
- # emacs (42)
- # exercism (1)
- # fulcro (10)
- # funcool (8)
- # gratitude (2)
- # honeysql (16)
- # introduce-yourself (5)
- # jobs-discuss (26)
- # leiningen (5)
- # lsp (31)
- # malli (21)
- # matcher-combinators (14)
- # missionary (2)
- # nbb (1)
- # off-topic (40)
- # pathom (38)
- # portal (2)
- # re-frame (7)
- # reagent (18)
- # reitit (1)
- # releases (5)
- # shadow-cljs (62)
- # sql (12)
- # testing (4)
- # xtdb (37)
How can I write a resolver that puts a new key into a collection returned by another resolver? This is what I’m trying to get working:
(pco/defresolver new-key-resolver [{:keys [outside coll]}]
{::pco/input [:outside {:coll [:inside]}]
::pco/output [{:coll [:new-key]}]}
{:coll (map (fn [{:keys [inside]}]
{:new-key (+ inside outside)})
coll)})
But when I try this:
(p.eql/process (pci/register [new-key-resolver])
{:outside 2
:coll [{:inside 1}
{:inside 2}
{:inside 3}]}
[{:coll [:new-key]}])
I get
Execution error (ExceptionInfo) at com.wsscode.pathom3.connect.planner/verify-plan!* (planner.cljc:1688).
Pathom can't find a path for the following elements in the query: [:new-key] at path [:coll 0]
But calling the resolver as a function works:
(new-key-resolver
{:outside 2
:coll [{:inside 2}
{:inside 3}
{:inside 4}]})
; => {:coll ({:new-key 4} {:new-key 5} {:new-key 6})}
You need to feed :outside into the :coll the first time you get the coll
for example a fetch-coll-by-id resolver. Would fetch the coll and insert the :outside key into it right there
:outside
in the particular case I’m working on is a minimum value taken from the items in :coll
It’s a limitation in Pathom3. Nested resolvers can’t reach up or go backwards. You can only pass data down. This unfortunately ends up in coupling
I’m working on something to address this though.
It treats nested entities as references and tracks data with those references as a graph executes. Then you can do reverse lookups
(deftest product-with-order-test
(testing "Product has a relationship with the order it belongs to"
(let [env (ordering/create-env)]
(is (= {:com.example.order/products
[{:com.example.product/title "Green Apple"
:com.example/order
{:com.example.order.price/discount 0.1
:com.example/id "order-1"}}]}
(p.eql/process
env
{:com.example/id "order-1"
:com.example.order.price/discount 0.1
:com.example.order/products
[{:com.example/id "green-apple"
:com.example.product/title "Green Apple"
:com.example.product/quantity 4
:com.example.product/price 5.0}]}
[{:com.example.order/products
[:com.example.product/title
{:com.example/order
[:com.example/id
:com.example.order.price/discount]}]}]))))))
For example, this query starts at an order, nests into the products of the order and then nests further (with a reverse-lookup) to access discount
And the resolvers to make that work look like this:
(pco/defresolver reverse-lookup-for-products-is-an-order
[_env input]
{::pco/input [{:com.example.order/_products [:com.example/id]}]
::pco/output [{:com.example/order [:com.example/id]}]}
(let [{[{:com.example/keys [id]}] :com.example.order/_products} input]
{:com.example/order {:com.example/id id}}))
I have to use a plugin and generate some resolvers to make this work
All entities must have a com.example/id
attribute in this example
For example, the entity we pass in originally is this:
{:com.example/id "order-1"
:com.example.order.price/discount 0.1
:com.example.order/products
[{:com.example/id "green-apple"
:com.example.product/title "Green Apple"
:com.example.product/quantity 4
:com.example.product/price 5.0}]}
This is the magic plugin that makes it work:
(p.plugin/defplugin transact-entity
{::pcr/wrap-merge-attribute
(fn [original]
(fn [{:com.example.db/keys [schema] :as env} {:com.example/keys [id] :as out} k v]
(let [env (update env :com.example/db
(fn [db]
(d/db-with (or db (d/empty-db schema))
[{:com.example/id id k v}])))]
(original env out k v))))
::pcr/wrap-root-run-graph!
(fn [original]
(fn [{:com.example.db/keys [schema] :as env} ast-or-graph entity-tree*]
(let [env (update env :com.example/db
(fn [db]
(d/db-with (or db (d/empty-db schema))
[@entity-tree*])))]
(original env ast-or-graph entity-tree*))))})
It’s very experimental atm.
Hi! Do you have any tips for authorization of mutations? I was thinking about using a :wrap-mutation plugin. Ideally I would be able to attach some kind of “metadata” to each mutation (e.g. :allowd-roles #{..}) and retrieve that info in the plugin to allow/deny it…
Take a look at https://github.com/souenzzo/eql-style-guide/issues/4 regarding auth in pathom.
You can add your own custom attributes to the config map for resolvers and mutations and access them in a variety of ways.
As far as implementation goes, you could:
1. Use the https://github.com/souenzzo/eql-style-guide/issues/4 feature which works for mutations too.
2. Use a plugin like ::pcr/wrap-mutate
3. Sanitise the EQL query before processing.
4. Filter the index and remove unauthorised resolvers before processing
You also mention “metadata” which I just wanted to clarify would most likely be attributes within the resolver/mutation config map, along-side ::pco/input & ::pco/output
Thanks a lot, Caleb!
this may also be relevant. The person working on this is around here, and its not finished AFAIK but good reference maybe
Thank you, Tommy!