Fork me on GitHub
#om
<
2016-01-29
>
ethangracer00:01:20

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.

alasdair00:01:58

you mean (transact! mutation-1 mutation-2 mutation-3) ?

hueyp00:01:10

it catches the action call, if the mutation throws outside of that it fails like a read

ethangracer00:01:51

@alasdair: yeah, that way mutation-1 can fail but 2 and 3 can run

ethangracer00:01:50

@hueyp: true, that doesn’t solve the corollary problem though — I can't throw errors in action thunks to catch them

ethangracer00:01:07

at least, not without writing some helper method to rethrow the error

ethangracer00:01:10

it appears there is a way to throw an ex-info with {:type :om.next/abort} to forcibly rethrow the error

hueyp00:01:24

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?

ethangracer00:01:26

but that only works for ex-info, what if my action thunk calls something that itself throws an error?

hueyp00:01:53

oh cool, I had wondered if you could abort early

hueyp00:01:22

@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

hueyp00:01:12

it also lets your follow up query return a value so you can rollback any optimistic mutations

hueyp00:01:20

maybe thats the main reason?

hueyp00:01:25

[(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

hueyp00:01:41

vs blowing the whole result up

ethangracer00:01:29

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

hueyp00:01:04

the thing is its easy enough to make a function to rethrow them, but hard to do the opposite 😜

mahinshaw00:01:08

But mutations run in a transaction. If you are halfway through a transaction, and it fails, you don’t want to continue.

cjmurphy06:01:37

@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.

cjmurphy06:01:56

@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.

petterik09:01:28

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)) ?

petterik09:01:54

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.

jimmy09:01:37

@cjmurphy: thanks for mentioning me. I will try it out later today simple_smile

cjmurphy10:01:15

It could probably be a bit cleaner by using tree->db directly as done: https://github.com/omcljs/om/wiki/Components,-Identity-&amp;-Normalization

iwankaramazow12:01:47

@petterik: just noticed the same thing, don't think this is supposed to be this way

iwankaramazow13:01:52

Hmm not sure, might be a problem with my code

petterik13:01:17

I ended up not transacting directly on the reconciler anymore, so I'm not dependent on the change anymore

denik13:01:15

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?

denik13:01:46

i.e. when every parent only has one child

anmonteiro14:01:13

@denik: yep, see part 2 of that series simple_smile

denik14:01:34

@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

denik14:01:46

without recursion the query works fine

denik14:01:09

on alpha30

anmonteiro14:01:20

@denik: woohoo! seems like you never have a stop condition for the recursive parsing

anmonteiro14:01:39

or are you running my example?

anmonteiro14:01:37

good question; could you post a minimal case somewhere?

denik14:01:47

okay will do

denik15:01:49

@anmonteiro:

(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)
  )

denik15:01:14

@anmonteiro: what do you think?

anmonteiro15:01:38

@denik: running it now

cjmurphy15:01:22

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?

cjmurphy15:01:46

Hmm - the code just above in the comment seems to do what I want, I think..

cjmurphy15:01:02

(parser {:state reconciler} [{:test-query-with-recursion [:id
                                                            :title
                                                            {:next '...}]}])

denik15:01:02

@cjmurphy: exactly. thinking with links in the om wiki

denik15:01:44

@anmonteiro: sanity check, does it throw for you?

anmonteiro15:01:00

Getting the error

anmonteiro15:01:13

looking into it

denik15:01:19

cool me too

anmonteiro15:01:36

shouldn't be a regression in Om

anmonteiro15:01:45

there are tests which cover this exactly

denik15:01:48

@anmonteiro: within the component?

denik15:01:11

since it works with the parser directly

anmonteiro15:01:12

@denik: yes, in Om's devcards

denik15:01:06

@anmonteiro: they’re all one-to-many

anmonteiro15:01:17

@denik: that's not the problem

anmonteiro15:01:32

your case is breaking in index-root

anmonteiro15:01:39

because you have only one component

denik15:01:52

are you sure?

denik15:01:09

I have many components in my original case and it also breaks

anmonteiro15:01:41

so it might not be because you have only one component, but some other termination condition that's not met

anmonteiro15:01:44

looking into it further

denik15:01:50

okay won’t distract you

drcode15:01:14

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?

iwankaramazow15:01:05

that's up to you to decide

iwankaramazow15:01:15

when Om merges remote query results trough the default callback, it'll look for Idents and normalize it based on the Idents

iwankaramazow15:01:20

Take a look at the source code

drcode15:01:41

@iwankaramazow: Thank you, that was helpful

dnolen16:01:10

@iwankaramazow: initial load & server responses

dnolen16:01:47

there are no other places it happens - notably not in your parse fns reads/mutates

dnolen16:01:30

because you often are need to go back and forth db->tree and tree->db are public useful helpers

peeja16:01:10

Is the Something is calling a React component directly warning still expected in Om 0.9.0?

peeja16:01:28

(I'm still working on upgrading to it and I want to make sure I haven't done something wrong.)

anmonteiro16:01:59

@denik: so I've found the issue and can probably fix it

anmonteiro16:01:22

but I'm really not sure if you should be allowed to do a query like that without using more components

denik16:01:56

is that the issue?

denik16:01:59

Not sure if being that strict about components and queries makes sense

denik16:01:19

especially in dev one might write bigger queries to move out into components later

anmonteiro16:01:38

I agree that it should be supported

anmonteiro16:01:01

I'll submit a patch if @dnolen agrees.

anmonteiro16:01:07

@dnolen: should this work?

(defui App
  static om/IQuery
  (query [this]
    '[{:item [:id :title {:next ...}]}]))

anmonteiro16:01:27

it's currently blowing the stack in index-root

anmonteiro16:01:38

it works in the parser however

dnolen16:01:01

recursion only works at the same level

dnolen16:01:17

if there’s a bug interested in that, but we’re not changing this limitation - this is how Datomic works

dnolen16:01:52

so … here recurs to [:id :title …]

anmonteiro16:01:08

yep, recursion is working as expected

anmonteiro16:01:18

index-root is not

dnolen16:01:56

sounds like a bug to me

dnolen16:01:01

unless there’s some reason to think otherwise

anmonteiro16:01:20

I think it's a bug too

dnolen16:01:23

@peeja: I don’t know many people who have actually tried upgrading

dnolen16:01:34

there’s a lot of work to make that more smooth and I don’t have time to focus on it really

dnolen16:01:38

happy to get help here

anmonteiro16:01:55

working on a fix

peeja16:01:36

@dnolen: Not many people have upgraded from 0.8.8 to 0.9.0?

peeja16:01:20

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.

anmonteiro17:01:43

@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

dnolen17:01:48

@peeja: ah yeah probably

peeja17:01:17

Sounds good, then. I'll ignore them. simple_smile

denik17:01:06

@anmonteiro: works! thank you simple_smile

dnolen19:01:39

@drcode: I don’t really understand your problem

dnolen19:01:45

your query has to be somewhere

dnolen19:01:59

sounds like you should put it on the root component

drcode19:01:24

OK, let me think about that- Thanks

dnolen19:01:55

:global-server-data isn’t enough on MyComponent like that

dnolen19:01:07

how can you normalize something without knowing anything about it?

dnolen19:01:13

normalization needs queries

drcode19:01:58

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...

drcode19:01:55

(also, my example may be confusing due to errors in trying to pare down a larger piece of code)

teslanick19:01:56

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?

hueyp19:01:50

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 simple_smile

jlongster19:01:44

@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

drcode19:01:57

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)

jlongster19:01:34

takes a while to adjust to this way of thinking, I'm still figuring out certain patterns, usually works out well though

iwankaramazow19:01:26

The strange thing is after a while I can't imagine why we haven't been writing code with graphs

jlongster19:01:01

@iwankaramazow: we have been, just half-assed graphs shoved into a tree shape and manual joining etc

drcode19:01:36

@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?"

Lambda/Sierra19:01:41

@jlongster: That link is an empty page it seems?

jlongster19:01:30

@stuartsierra: add ! to the url, the linker didn't pick it up

jlongster20:01:03

right, thanks

iwankaramazow20:01:13

@drcode: re-read thinking-with-links! like another 5x 😉 Not sure how I can explain what 'thinking in graphs' really means

iwankaramazow20:01:33

It depends on your domain ofcourse, but the way you can express links in Om is just awesome

iwankaramazow20:01:08

@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.

jlongster20:01:19

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)

jlongster20:01:37

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

jlongster20:01:14

tempting to try to get a query engine into devtools but we have more important things to do for now

iwankaramazow20:01:31

moving to Om/clojurescript is probably too much of a stretch in the future?

iwankaramazow20:01:45

the ff devtools*

jlongster20:01:16

oh absolutely, no way. but you can always port ideas

teslanick21:01:17

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)

drcode21:01:03

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.

dnolen21:01:44

@drcode: links are another way to do that btw

dnolen21:01:09

however that doesn’t address the normalization bit - you still need to specify the structure for that to work

drcode21:01:56

I couldn't get links to work when the item being linked was remote, but i may have been doing it wrong (didn't see example of links on remote data)

dnolen22:01:52

@drcode: right was assuming something already asked for it

dnolen22:01:59

the link isn’t for going remote really