This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-08-02
Channels
- # announcements (11)
- # aws (3)
- # babashka (34)
- # beginners (20)
- # biff (2)
- # calva (3)
- # cherry (29)
- # cider (6)
- # cljs-dev (9)
- # clojure (124)
- # clojure-europe (12)
- # clojure-norway (5)
- # clojure-uk (2)
- # clojurescript (32)
- # conjure (11)
- # datalevin (1)
- # datomic (16)
- # deps-new (1)
- # etaoin (6)
- # holy-lambda (10)
- # honeysql (28)
- # hyperfiddle (21)
- # jackdaw (2)
- # jobs (2)
- # leiningen (15)
- # missionary (12)
- # off-topic (132)
- # other-languages (1)
- # pathom (13)
- # rdf (10)
- # re-frame (8)
- # reagent (5)
- # releases (1)
- # remote-jobs (4)
- # shadow-cljs (32)
- # tools-deps (6)
- # vim (15)
- # xtdb (24)
I'd like the input maps to resolvers be smart maps so I can pass the input to internal functions which can extract any data they need out of the environment and other resolvers. I wrote the following plugin:
(p.plugin/defplugin smart-map-plugin
{::pcr/wrap-resolve (fn [resolver]
(fn [env input]
(let [smart-input (if (psm/smart-map? input)
input
(psm/smart-map (-> env
(pcp/reset-env)
(psm/with-error-mode ::psm/error-mode-loud))
input))]
(resolver env smart-input))))})
Probably not surprisingly, this results in a stack overflow when I try some basic EQL queries. What should this plugin do in order for the wrapped resolver to receive a smart map as input?Instead of resolvers pulling their dependent data out of a smart map, why not declare the dependent attributes in the arglist of the resolver?
Locality and convenience. That approach would require updating all resolvers using a function when that function's parameters change
I don't quite follow. Do you have a concrete example that we could refer to?
I'm looking at your other message here and it looks like there's a dependency cycle implied here:
(pco/defresolver id->user [{id :acme.user/id :as input}]
(println (:acme.user/birth-year input))
{:acme.user/name "Mark"})
(pco/defresolver name->birth-year [{name :acme.user/name}]
{:acme.user/birth-year 1970})
:acme.user/name
explicitly depends on :acme.user/id
and implicitly depends on :acme.user/birth-year
, but :acme.user/birth-year
explicitly depends on acme.user/name
. So if we have an id
we can't resolve either a name
or birth-year
because there's no path to get one without the other.Good point. Does it surprise you that it completes at all?
> I don’t quite follow. Do you have a concrete example that we could refer to? I don’t have a concrete example at hand. Suppose I have two resolvers, R1 and R2. These two resolvers call function F which takes a kw-args map as a parameter. In order to make this code function, I must duplicate the keywords from F’s parameter into the inputs of R1 and R2. If F’s parameters change, then I must update both R1 and R2. However, if I can pass a smart map into F and all of F’s parameters can be computed from the environment, then there is no code duplication and I don’t have to remember to update R1 and R2 when F changes.
Why not make F a resolver also?
If Pathom is a system for managing function dependencies, and F has a new dependency, then I think it makes sense to expose those dependencies to Pathom for Pathom to manage them instead.
Currently, my code is structured like that: Lots of internal functions are resolvers. This approach definitely works but introduces unnecessary abstractions. Under this approach, F needs a name and an output key. The output key is superfluous and my meager brain gets overloaded.
R1 and R2 instead of calling F directly, they can put F's return attribute in their input signature.
In addition, there are plenty of times when F only called after some condition is true. If F is a resolver, then F can be executed unnecessarily .
This little sample program works. The execution is a little surprising. There are many printlns when I would have expected a stack overflow