This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-01-29
Channels
- # aatree (1)
- # admin-announcements (7)
- # announcements (3)
- # beginners (125)
- # boot (164)
- # braid-chat (8)
- # cider (26)
- # cljsrn (37)
- # clojars (3)
- # clojure (162)
- # clojure-argentina (1)
- # clojure-art (2)
- # clojure-berlin (5)
- # clojure-czech (3)
- # clojure-ireland (1)
- # clojure-miami (1)
- # clojure-norway (9)
- # clojure-russia (47)
- # clojurebridge (1)
- # clojurescript (151)
- # community-development (1)
- # conf-proposals (80)
- # core-async (15)
- # core-matrix (1)
- # cursive (66)
- # datomic (26)
- # emacs (17)
- # events (10)
- # funcool (59)
- # hoplon (43)
- # incanter (2)
- # jobs (10)
- # ldnclj (8)
- # lein-figwheel (18)
- # luminus (1)
- # off-topic (19)
- # om (144)
- # onyx (167)
- # overtone (9)
- # parinfer (12)
- # pedestal (1)
- # proton (158)
- # re-frame (139)
- # reagent (48)
- # test-check (19)
- # testing (43)
so on further thought it seems the reason is that you can have multiple mutations in one query, so if one mutation fails, you don’t necessarily want all of them to fail.
it catches the action call, if the mutation throws outside of that it fails like a read
@alasdair: yeah, that way mutation-1 can fail but 2 and 3 can run
@hueyp: true, that doesn’t solve the corollary problem though — I can't throw errors in action thunks to catch them
at least, not without writing some helper method to rethrow the error
it appears there is a way to throw an ex-info
with {:type :om.next/abort}
to forcibly rethrow the error
are there any examples / patterns of wanting to take action on a remote mutations response … I’m coming from Relay where you can pass a callback, but that is not really fitting into om.next thinking … is the general idea to capture a mutations progress in state and react to state changes?
but that only works for ex-info
, what if my action thunk calls something that itself throws an error?
@ethangracer: been using om.next for like 2 days, so I don’t know, but I kind of like the behavior, that the mutations return value is the error which is more information than the error itself
it also lets your follow up query return a value so you can rollback any optimistic mutations
[(user/name {:name “Voltron” }) :user/name]
… the client mutation might optimistically set state to the new name, but then the remote mutation fails, but the result contains the server state so the client can sync back up
that’s a good point @hueyp, thanks. I guess it’s just a bit frustrating in the context I’m trying to use it — throwing errors from the parser that the server can catch and handle. In which case using :om.next/abort
is good enough
the thing is its easy enough to make a function to rethrow them, but hard to do the opposite 😜
But mutations run in a transaction. If you are halfway through a transaction, and it fails, you don’t want to continue.
@iwankaramazow, @jlongster: thanks for helping with putting the 'secret' singular reference into Kanban. There was no need to wrap in a vector. See https://github.com/chrismurrph/om-alarming/blob/master/test/kanban/tree_db.cljs, which is the Kanban code but without any rendering methods, and just the secret added.
@nxqd: I got the table view I was thinking of (2 locations and 4 gases) working by just concentrating on the Idents/IQuery component structure that turns denormalized initial state into properly normalized i.e. with Idents everywhere you would expect them to be. After that the rendering in the main application fell into place. See https://github.com/chrismurrph/om-alarming/blob/master/test/om_alarming/tree_db.cljs. It is the same thing as the Kanban tree_db.cljs
, just for a different application.
Is there a reason why om/transact! doesn't transform reads if "x" is a reconciler? Shouldn't this line: https://github.com/omcljs/om/blob/master/src/main/om/next.cljs#L886 Be: (transact* x nil nil (transform-reads x tx)) ?
I'm using (om/transact! reconciler '[(set-url {}) :read/key]) for url/history stuff, and my :read/key isn't passed with params or query.
It could probably be a bit cleaner by using tree->db
directly as done: https://github.com/omcljs/om/wiki/Components,-Identity-&-Normalization
@petterik: just noticed the same thing, don't think this is supposed to be this way
Hmm not sure, might be a problem with my code
I ended up not transacting directly on the reconciler anymore, so I'm not dependent on the change anymore
regarding recursive queries (http://anmonteiro.com/2016/01/exploration-patterns-om-next-part-1/) do they work the same way for one to one relations?
@denik: yep, see part 2 of that series
@anmonteiro: thanks. the query works when I run the parser with the reconciler as state but it throws Uncaught RangeError: Maximum call stack size exceeded
when I put the exact same query in the component
@denik: woohoo! seems like you never have a stop condition for the recursive parsing
or are you running my example?
good question; could you post a minimal case somewhere?
(ns query.recursion-test
(:require [om.next :as om]
[om.dom :as dom]
[goog.dom :as gdom]
[om.next :as om :refer-macros [defui]]))
(defmulti read om/dispatch)
(defmethod read :default
[{:keys [state parser query] :as env} key params]
(println "Default query for" key query)
{:value (when query
(parser env query))})
(defmulti mutate om/dispatch)
(defmethod read :test-query-with-recursion
[{:keys [state query parser] :as env} key _]
(let [st @state]
{:value (om/db->tree query (get st key) st)}))
(def parser
(om/parser {:read read :mutate mutate}))
(def state
{:test-query-with-recursion [:item/by-id 1]
:item/by-id {1 {:id 1
:title "first"
:next [:item/by-id 2]}
2 {:id 2
:title "second"}}})
(def reconciler
(om/reconciler {:state state
:parser parser
}))
(defui App
static om/IQuery
(query [this]
[{:test-query-with-recursion [:id
;; TRY uncommenting
;{:next '...} ;; Uncaught RangeError: Maximum call stack size exceeded
]}])
Object
(render [this]
(dom/pre nil
(with-out-str
(cljs.pprint/pprint (om/props this)))
))
)
(comment
;; Works
(parser {:state reconciler} [{:test-query-with-recursion [:id
:title
{:next '...}]}])
(om/add-root! reconciler
App (gdom/getElement "app"))
(cljs.pprint/pprint @reconciler)
)
@anmonteiro: what do you think?
@denik: running it now
What is the easiest way to issue a query from another part of the application (not inside a component)? Say :sticky? is at the top level of the app state, so I want to issue the query [:sticky?]. Should I do this against the parser or the reconciler?
(parser {:state reconciler} [{:test-query-with-recursion [:id
:title
{:next '...}]}])
@anmonteiro: sanity check, does it throw for you?
Getting the error
looking into it
shouldn't be a regression in Om
there are tests which cover this exactly
@anmonteiro: within the component?
@denik: yes, in Om's devcards
@anmonteiro: they’re all one-to-many
@denik: that's not the problem
your case is breaking in index-root
because you have only one component
so it might not be because you have only one component, but some other termination condition that's not met
looking into it further
Question about Om Next normalization: When does it happen, exactly? When you load in initial data it happens (i.e. if you don't use and atom and/or use the normalize flag) but at what other points does it happen? For instance, if results come back from a remote that are denormalized, will Om automatically normalize it for me?
that's up to you to decide
when Om merges remote query results trough the default callback, it'll look for Idents
and normalize it based on the Idents
Take a look at the source code
@iwankaramazow: Thank you, that was helpful
@iwankaramazow: initial load & server responses
because you often are need to go back and forth db->tree
and tree->db
are public useful helpers
Is the Something is calling a React component directly
warning still expected in Om 0.9.0?
(I'm still working on upgrading to it and I want to make sure I haven't done something wrong.)
@denik: so I've found the issue and can probably fix it
but I'm really not sure if you should be allowed to do a query like that without using more components
I agree that it should be supported
I'll submit a patch if @dnolen agrees.
@dnolen: should this work?
(defui App
static om/IQuery
(query [this]
'[{:item [:id :title {:next ...}]}]))
it's currently blowing the stack in index-root
thank you @anmonteiro 🙇
it works in the parser however
if there’s a bug interested in that, but we’re not changing this limitation - this is how Datomic works
yep, recursion is working as expected
index-root
is not
I think it's a bug too
there’s a lot of work to make that more smooth and I don’t have time to focus on it really
working on a fix
It doesn't seem like it's a big deal. I just know that these React warnings were normal in 0.8.8 and I want to verify that they're still expected in 0.9.0.
@denik: should be fixed, you can try to test against my branch to see if it solves your issues: https://github.com/anmonteiro/om/tree/OM-595
@anmonteiro: works! thank you
Yeah, maybe that's where I'm going wrong, trying to get the branch component to perform the querying, maybe it's just a matter of moving that responsibility to the root component, since it's global information...
(also, my example may be confusing due to errors in trying to pare down a larger piece of code)
Just to clarify the details of what the :send
function expects. (The function provided to the reconciler at the :send
keyword) It takes the remote name and a callback function to provide data to. That data is then passed through the normalization system?
the callback can also take a query as a second arg … I’m also curious if the query is a helper or a necessity to normalize
@drcode: also check out https://github.com/omcljs/om/wiki/Thinking-With-Links! If you happen to have something that should be globally stored, that helps. But generally I think it's up to the send and read functions to figure out how to cache stuff if that's what you're worried about
Thanks @jlongster, I think I have solved my problem, based on the advice I have been given. I will post a quick explanation once I am 100% sure I got it right (to avoid posting wrong info that could confuse others)
takes a while to adjust to this way of thinking, I'm still figuring out certain patterns, usually works out well though
The strange thing is after a while I can't imagine why we haven't been writing code with graphs
@iwankaramazow: we have been, just half-assed graphs shoved into a tree shape and manual joining etc
@iwankaramazow: I seem to think that one hour and then an hour later I get myself confused and say "why do we need to use graphs again?"
@jlongster: That link is an empty page it seems?
@stuartsierra: add !
to the url, the linker didn't pick it up
thanks
@drcode: re-read thinking-with-links!
like another 5x 😉 Not sure how I can explain what 'thinking in graphs' really means
It depends on your domain ofcourse, but the way you can express links in Om is just awesome
@jlongster: it only made sense to me since David Nolen spread the vision of the ancients Before experimenting with Om I launched an app with redux/falcor combined. Falcor has JSON-graph, but it just didn't click. Maybe I didn't get the combination of Redux/Falcor quite right, redux app-state merged with Falcor just was an awkward way of programming.
yeah no idea how that would work. redux explicitly is a simple tree. it works well for simple apps but only goes so far. (we are using redux in firefox devtools and it's still a huge improvement from before)
once you write apps like that for a while it's clear why a graph is better, we're manually joining all over the place
tempting to try to get a query engine into devtools but we have more important things to do for now
moving to Om/clojurescript is probably too much of a stretch in the future?
the ff devtools*
Well -- I just spent a little bit trying to figure out why a server response wasn't normalizing -- it was because the thing I was handing to the reconciler was a list not a vec. (I feel like a dope)
Just FYI on (I think) the right solution to my earlier problem (https://clojurians.slack.com/files/drcode/F0KQ9GM4L/Untitled.txt) The answer is I forgot that parent components, when defining their queries, can adjust their child queries to suit their needs (as dnolen does in the "Unions" example). That way, I can make a child component "think" it is querying a piece of local data, but the parent component can spoon feed the child with data that is actually global.
however that doesn’t address the normalization bit - you still need to specify the structure for that to work