This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-09
Channels
- # alda (5)
- # aleph (10)
- # bangalore-clj (1)
- # beginners (168)
- # cider (68)
- # cljs-dev (263)
- # clojars (4)
- # clojure (66)
- # clojure-brasil (25)
- # clojure-china (1)
- # clojure-dusseldorf (1)
- # clojure-greece (4)
- # clojure-italy (3)
- # clojure-russia (4)
- # clojure-spec (12)
- # clojure-uk (16)
- # clojurescript (36)
- # community-development (12)
- # cursive (9)
- # data-science (1)
- # datascript (8)
- # datomic (20)
- # defnpodcast (6)
- # emacs (2)
- # figwheel (2)
- # fulcro (51)
- # graphql (62)
- # immutant (14)
- # keyboards (1)
- # lein-figwheel (10)
- # leiningen (5)
- # lumo (15)
- # off-topic (4)
- # onyx (3)
- # pedestal (4)
- # portkey (13)
- # protorepl (1)
- # re-frame (8)
- # reagent (2)
- # reitit (4)
- # shadow-cljs (71)
- # spacemacs (7)
- # specter (33)
- # sql (9)
- # unrepl (75)
- # vim (7)
I have a question regarding Lacinia. I am wondering why resolver-map
is a function, in https://lacinia.readthedocs.io/en/latest/tutorial/init-schema.html#schema-namespace
It appears it is rather static, i.e. not requiring to be executed at run time. Any idea why the authors choose to make it a function anyway?
This is just the tutorial; I wrote it this way because I knew I would be changing it later. I want the tutorial to be, as much as possible, a slow, small drip of understandable changes, refactoringa, improvements, and introductions of new ideas. Read on.
@urzds you can, for example, on application init process, first connect to db, then call this resolver-map
that will be "dynamic generated" basead on database. After all this, start the HTTP server
Ok, so it is not required in this example, but there might be a use-case where it could be necessary to dynamically generate the resolver-map
?
Yes, for example if you consume from kafka and the schema is changed from int to long, and you went the app to stay running, or maybe more relevant you found a bug in the resolver and you want to deploy the fix in a repl, or still more relevant your developing and made an error so your not getting back the correct values?
But in the deploy-fix-via-REPL and developing-and-want-to-correct-something cases, I could as well re-execute a (def ...)
in the REPL, could I not?
Sorry if the question appears very basic, but I don't have that much experience in this area.
Could you maybe give me a practical example (i.e. some code), where the resolver-map is a function and cannot easily be a var?
Right now both the keys and the values of the resolver-map
do not seem like things that could not be def
ed. But as I said, I am probably just lacking the experience with more advanced use-cases.
I haven't really looked at them, I put my data in an atom matching the values, so didn't have to use resolvers at all.
Say, in lacinia can I rely on (:type-name context)
being the type I'm supposed to return from inside of a resolver?
Oh, oops, was looking at the wrong place in the data structure, hmm. In general is there an API I can use to get the return type that I've declared I'm returning for a given field / query / etc?
I seem to be able to get to it via (-> context :com.walmartlabs.lacinia.constants/parsed-query :selections first :field-definition :type :type)
but that seems like it's a little implementation-specific, plus I'm not sure which fragment my resolver is working on if there are multiple
Aha, I think you're right: http://lacinia.readthedocs.io/en/latest/resolve/type-tags.html#using-tag-with-type > When a field resolver is invoked, the context value for key :com.walmartlabs.lacinia/container-type-name will be the name of the concrete type (a keyword) for the resolved value.
is that useful to you @timgilbert?
Somewhat, yeah. I'm finding that the value is nil
in my top-level query resolver though
It's the type of the containing field, not the type of the field being resolved. At the top, there is no containing field so it is nil.
Lacinia doesn't expose this data and might have to expose it as a set (e.g., the members of a union or the implementers of an interface).
You want to be able to extract from the context, what the return type that the resolver result should be?
I'm using the same resolver for a few different queries that look for different things depending on some parameters I'm passing in the schema
For the most part it works fine without needing to specify types but in a few instances I might want slightly different behavior depending on the type
I might be able to do that, but I'd like to keep it somewhat DRY if I can
I suppose I'll file a github issue, it does seem slightly like a bug that the value is nil in top-level queries
Working on getting a small test case to work now, it's a little tough to extract from the rest of the code
Oh, that's just roughly:
(defn my-resolver
[unique-attribute]
(fn [context args value]
(let [arg (:slug args)
ref [unique-attribute arg]]
(log/spy (:com.walmartlabs.lacinia/container-type-name context))
{:my "thing"})))
(Minus some complex stuff, but the main thing is that (:com.walmartlabs.lacinia/container-type-name context)
is nil)
...then the schema resembles
:queries
{:get_person
{:type :Person
:args {:slug {:type (non-null ID)}}
:resolve [:Query/EntityBySlug :person/slug]}
On the back-end I'm hitting datomic, which takes a pretty dynamic-typing approach to data, so I can use this one resolver to look up a variety of fields that aren't necessarily the same type
What I'm attempting to work towards is an interface where the resolver figures out that it's returning a :Person
and its argument is a :slug
and then it queries datomic for the entity with :person/slug "whatever"
{:person/slug "thing}
Then wrap ur resolver with a multi method and dispatch off the ns of the key
I have something very similar to that working right now, yeah
I'm thinking that it is probably set for the slug
field if I query { get_person(slug: "foo") { slug } }
But not the top-level query
ie, the return value of get_person