This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-10-22
Channels
- # 100-days-of-code (3)
- # announcements (7)
- # beginners (147)
- # cider (22)
- # cljdoc (24)
- # cljs-dev (71)
- # cljsrn (8)
- # clojars (3)
- # clojure (45)
- # clojure-conj (11)
- # clojure-dev (1)
- # clojure-italy (21)
- # clojure-nl (2)
- # clojure-spec (76)
- # clojure-sweden (2)
- # clojure-uk (100)
- # clojurebridge (3)
- # clojurescript (15)
- # cursive (7)
- # data-science (2)
- # datomic (7)
- # emacs (9)
- # events (2)
- # figwheel-main (4)
- # fulcro (117)
- # jobs (2)
- # jobs-discuss (21)
- # leiningen (184)
- # nyc (4)
- # off-topic (50)
- # planck (6)
- # re-frame (14)
- # reagent (25)
- # ring-swagger (5)
- # shadow-cljs (96)
- # spacemacs (5)
- # sql (26)
- # tools-deps (12)
- # uncomplicate (1)
- # yada (3)
So, I’m fixing incubator’s pmutate!
@currentoor and @wilkerlucio, and I realize that the error-marker
should really be something that can be seen during loading as well…so I’m going to rename it. I normally would not make such a change to a released API, but since it was just released yesterday I think it’ll be ok.
0.0.4 is on clojars already and works, but 0.0.5 is coming in a few minutes, and will rename error-marker
.
Just release 0.0.5 of Incubator to clojars. The improved pmutate!
is now working correctly with hard errors, is better documented, and has proper way to distinguish interaction for components that share idents.
I think this version is pretty darn good, and includes clear targeting and merging support for the mutation response (the older versions sort of did as well, but it was implemented by side-effecting in the remote and was unclear how to use correctly). The new technique works more like load
’s targeting/merging, and doesn’t violate Fulcro’s rules of mutation implementation.
yeah…github is having issues…so, if the README you’re seeing says anything about error-marker
, then github hasn’t updated…my repo says the commits are pushed, and now github reload of the page is crashing.
Updated 25 minutes ago: We continue working to repair a data storage system for . You may see inconsistent results during this process.
Check our status site and @githubstatus on Twitter for updates.
The released code uses ::pm/key
instead, which is now visible in all phases…and ::pm/returning
and ::pm/target
now go in pmutate!
params. They are a component class and df/load targets for the mutation response (if you want that response merged and targeted).
Nice I’ll try it tomorrow 😃
http://book.fulcrologic.com/#Unions If I have a tree of data (say, an AST representing some language) and nodes don’t have any notion of an ID (they’re just nodes in the tree of a given “type” (i.e. they have have different sets of facts attached to them). What should the indent be?
Here’s an example of such a tree:
#:elogic.core.binary-compound{:connective :implication,
:left-operand #:elogic.core.predicate{:name "P", :arguments nil},
:right-operand #:elogic.core.unary-compound{:connective :negation,
:operand #:elogic.core.predicate{:name "Q",
:arguments nil}}}
I would like to build a set of components to render this tree, essentially one component per node “type”, with a query pulling the relevant facts for a specific node
basically, my question is: can I use unions without the child components having an ident?
(to be clear: the reason why I can’t see components rendering individual nodes having an ident is because those nodes don’t really have an “identity”, and as far as I understand Fulcro’s idea of an “ident” is to assign an identity to a part of the data tree and denormalise it. Here the “identity” of these nodes is just the place where they appear in the tree; the “same node” never appears in two places in the tree)
So, you don’t have to normalize, and if you never “mutate” the node, there is no reason to
the nodes will have to have unique identity to use union queries, though, because union queries work off of idents
but if you have a tree and just want to render it as a tree, the query will be really light, and unions aren’t really necessary…just “switch” off of the node type
@tony.kay correct me if I am wrong but I don’t have access to the props in the query though, right? (the full query is built before the data flows in), so how can I switch the query based on some “type” depending on the props?
I can switch the rendering based on the node “type”, but the query will have to pull all the data for every node “type” then
> otherwise, give them UUIDs I thought about this but then (I think?) Fulcro would normalise my whole expression tree. I’ll have a lot of such expressions, so this would be wasteful performance-wise and useless (since nodes are never referenced in different places, I never mutate them and don’t have a notion of identity, it makes little sense)
To summarise: the part I am still unclear about after your answer is what the query should look like if I just wish to render it as a tree, without ident on the nodes. I won’t be able to specify on a per-component basis the properties I want to pull out, right? (i.e. :elogic.core.predicate/name
when rendering a predicate, etc)
right, yeah, that’s the solution I was thinking of. I was hoping I could use queries somehow
@tony.kay completely unrelated question but may I ask what inspired you when you developed Fulcro? I have never used Om but from what I gather you definitely took inspiration from there. Are there any other projects (perhaps beyond clojure) that guided your design?
@hmaurer There’s quite a bit I’ve written and talked about on the website and other places. I did a Defn podcast, which is a good resource, and the website has some history.
It really is an extension of the work David Nolen started on Om Next, and quite a bit of Om Next code is actually part of the code base.
A lot was going on then: Elm, Om Next, other “pure” systems…I wanted FP, and a good answer for the problems that plague full-stack apps. But a lot of the decisions I’ve made in Fulcro itself had more to do with an aim for good developer experience. I’ve seen way too many projects “hit the wall” when the constructs of their libraries and tools cause them to be unable to cope with their code anymore. Some of that you jsut can’t fix (developers do need to have decent chops and some dedication to not making a mess), but certain ways of doing things that some libraries encourage just don’t scale…so I’ve always had an eye towards solutions that can scale to larger programs, and over time.
https://github.com/fulcrologic/fulcro-incubator
I just pushed 0.0.6, with a small bump that lets you use declared mutations (declare-mutation) with pmutate!
without the need for quoting.
pmutate!
is awesome but one thing that concerns me is composing mutations together, for example i have this
(prim/ptransact!
this
`[(a.mutations/start-loading)
(a.mutations/upsert-vehicle
~{:wash-id id
:img-src (:img-src unconfirmed-vehicle)
:make (:make unconfirmed-vehicle)
:plate (:plate unconfirmed-vehicle)})
(cc-terminal/sale
~{:amount (::package/price package)
:wash-id id})
(a.mutations/start-loading)
(a.m.mutations/handle-payment-response
~{:wash-id id})
(a.mutations/finish-loading)])
maybe something like this could work?
(pmutate! this {:pre `[(a.mutations/start-loading)
(a.mutations/upsert-vehicle
~{:wash-id id
:img-src (:img-src unconfirmed-vehicle)
:make (:make unconfirmed-vehicle)
:plate (:plate unconfirmed-vehicle)})
(cc-terminal/sale
~{:amount (::package/price package)
:wash-id id})
(a.mutations/start-loading)]
:ok `[(a.m.mutations/handle-ok-payment
~{:wash-id id})
(a.mutations/finish-loading)]
:error `[(a.m.mutations/handle-payment-error
~{:wash-id id})
(a.mutations/finish-loading)]})
but that’s pretty verbose too
yeah, that can easily be combined
yeah upsert and sale are two distinct mutations that should probably stay separate
so make two calls to pmutate!
?
and the errors are really different…one is a network/db error (rare), the other is CC, whcih is “common”
but then again, why split it out so much? You can make helpers on the server to do each task, but why not make a single server-interaction mutation for the combo as an abstract wrapper for all of the server things that have to succeed?
that is a good point
possibly, but in this case no, both happen on the same server
lol this is why i prefer JVM to node
So, pmutate!
is using ptransact
underneath…so it is safe to put calls of it in the ok-action and error-action areas
yeah…
The point of pmutate!
is that is associates the progress and result data with a component in the UI
actually, now that I think of it…I probably won’t. Mainly because there is branching inherent in the problem
as soon as you need a chain, there is a branch, whcih needs logic (at least if
), and that is not going into the tx notation 🙂
The best you can do in async land where each step possibly has an error is to code it sort of like js-land (callbacks for each branch of possible outcome), and possibly combine as much into one call as possible to minimize the length of the chain.
yeah i see…
so right now i didn’t even bother having error handling logic for the upsert-vehicle, i just assumed that would always work
shouldn’t auto-retry take care of that?
auto retry stops trying if the server communication is ok, but the server refuses an action
ah i see
this is probably a bad idea, but might be clean to have a conciser notation for chaining mutations via nested transact! calls
or nested pmutate!
calls
@currentoor the motivation for me to create pmutate!
was because here pretty much every mutation is sensitive and needs to check if it worked fine, specially in an environment were things get deployed all the time and services might have bugs, so we can't "hope for the best", if somethign bad happens the user needs to know
so to avoid all this boilerplate all around the code, this function encapsulates de process so its easy to have this process everywhere
@wilkerlucio makes sense, but how do you compose logic? just make aggregate mutations?
what you mean by compose logic? most of times what we need is to send some info to the server and sometimes update the local db with some response, that's not a lot to it
and you can always have a single mutation that does everything you need in the DB
this mutation can re-use simple functions if you need to repeat things around
yeah that’s what i meant
makes sense
its better to have a single mutation doing a lot of things in a single atomic change, than trying to compose using multiple mutations, that's been true IME
agreed, but in some cases, for example a sequence that requires talking to two remotes, you are forced to compose at this level
yeah you’re right, it’s just tempting to build abstractions at the mutation level, since transact! let’s combine them and it’s easier to name them separately
and I have not tried it, but :component
should be in env
, so you can pull it for the next call (`pmutate!`’s first arg is this
, a component)
also makes things a little more readable IMO
I can understand the feeling of using multiple mutations, and also its requirement when you need to chain multiple things, but in practice I've not feel the need for it
though i agree, it’s better not to
But transact!
is assuming you’re going to compose one thing that has optimistic updates, goes to one server, and “succeeds by default”, with you adding in the logic to deal with everything.
if you are using a single source of truth like Pathom to wrap everything else, most of the "dependency chain" can be handled at API level, so your UI doesn't have to do it, surely that will be exceptions, but I find then very rare (personally I never had one to be honest)
agreed…most interactions, in my experience are pretty straightforward, with a decent amount of boilerplate…these cases of composition across multiple endpoints with no interstitial user interaction are (fortunately) rare
cool, thanks guys
I do, but not in the context of fulcro. Could probably provide some guesses if you are having any issues though.
Hi! Thanks for the reply! I already solved my yesterday's problem, but I have no idea of how implement this style:
title: {
display: 'none',
[theme.breakpoints.up('sm')]: {
display: 'block',
}
How to call theme.breakpoints ? Any idea?(clj->js {
:display "none"
(-> theme .-breakpoints (.up "sm")) { :display "block" }
})
for interop with jss