Clojurians
#om
<
2016-02-11
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

hueyp03:02:12

is there a detectible difference in the parser for when a read is part of a transact! vs add-root! / set-query!?

tmorten03:02:51

@hueyp: I think that in the AST the :type keyword is set to :call on a mutation...someone can correct me if I am wrong on that one...

tmorten03:02:00

i.e. transact!

hueyp03:02:01

but for the reads in the transact! query, e.g. [(user/set-name {:name “Bob” }) :user/name] — the :user/name parse

hueyp04:02:38

I guess the idea is to use force to mark them … but not sure why transact! reads don’t default to force?

tmorten04:02:13

@hueyp: not sure on that one...

hueyp04:02:14

yah, might be barking up the wrong tree … just thinking of what information to use when deciding whether to cache a read. Like if I transition routes, I’m cool not hitting a remote for anything already in the local state, but if I do a transact! I want to make sure I always send remotes … I kind of view the reads in transact! as existing for exactly this purpose

drcode04:02:33

Hi everyone: I'm a bit confused by what types of "reads" are supported by om/transact!... In the documentation it calls them "keys" instead of "reads" and looking at the source code it uses the term "simple reads" I have a transaction as follows:

(om/transact! reconciler '[(do-this {}) {:read [:inner-read]}])
Am I correct in think that this is not a "simple read" and that I instead can only write:
(om/transact! reconciler '[(do-this {}) :read])
In other words, are "reads" other than atomic keywords supported? (I ask because I can't get more detailed reads to work)

hueyp04:02:08

you can have joins in those reads too. the distinction is that not all queries are … not sure the proper word, but ‘root’ queries

hueyp04:02:15

for instance [:id :name] is a legit query, but might not have enough context to parse … the parser might have a key :current-user … so the [:id :name] query on a component would be pulled into a root query

hueyp04:02:59

so I’d say [:id :name] is a simple query, and [{:current-user [:id :name]}] is a full or root query or whatever the non-simple term is

drcode04:02:29

@hueyp: Thanks- that's how I thought they worked as well, thanks for the confirmation (it's seems like the logical expectation that you can have arbitrary reads, as long as they are rooted) now I still need to figure out why it doesn't seem to work that way for me...

hueyp04:02:23

and to add to that … when you transact!, om is going to transform those reads by walking to the root … the exact mechanics I’m not 100% sure of, but if you have two components, [{:current-user (om/get-query Child)}] and Child transacts! with a key of :name it might resolve into a full query of {:current-user [:name]}

hueyp04:02:13

but its smarter than just that … I’ve had it notice that the key isn’t in the direct components query, but in the parents query, and it worked out fine … so I have that on my list to really understand

hueyp04:02:36

it might also remove read keys from a transact! too

hueyp04:02:19

which seems to go against documentation, so I want to double check .. but I think that happens :simple_smile:

hueyp04:02:45

actually it might not go against docs at all, maybe if its not indexed it feels free to remove it

drcode04:02:58

okok, so there's a bit of black magic there after all that might be tripping up my transactions... that's probably what I'm running into... > it might also remove read keys from a transact! too Yup, that's what seems to be happening, and I can't figure out why...

drcode04:02:34

> maybe if its not indexed Sigh... guess it's time to dig into the indexer logic :simple_smile:

drcode04:02:51

@hueyp Thanks for the helpful pointers

hueyp04:02:56

I don’t know exactly whats going on … I just remember testing by putting a fake key into a transact! and it didn’t survive

hueyp04:02:11

lemme see if I have the sample handy :stuck_out_tongue_winking_eye:

drcode04:02:50

@hueyp: Yes, it seems like the correct action with a garbage key would be to throw a parser error, not just sanitize the query

drcode04:02:57

(but I don't understand the situation well enough to know for sure)

hueyp04:02:54

yah, so if I do: (om/transact! this [(todo/toggle {:id ~id}) :completed? :random-key]) it turns into transacted '[(todo/toggle {:id 1}) {:current-user [{:todos [:completed?]}]} {:current-user [{:todos [:completed?]}]}] … the :random-key is gone

hueyp04:02:55

my assumption is that :random-key is not indexed so it gets taken out … but I need to check the code … clearly it was just me trying things out :simple_smile:

hueyp04:02:16

but you can see it properly … sorta … hoists the :completed? up into the root query

drcode04:02:04

Yes, that's the cause of my confusion in a nutshell, I see the same weirdness... I assume it's because the transactions go through the indexer in a "bottom up" fashion, causing the resulting query to be very ugly, but technically correct (As long as you are doing everything else correctly)

hueyp04:02:59

I couldn’t actually get that above to reliably work … e.g. [(todo/delete {:id ~id}) :todosCount :todos] gets turned into [(todo/delete {:id 1}) {:current-user [:todosCount]} {:current-user [{:todos [:id :text :completed? {:author [:id]}]}]}] which has :current-user twice as a root key the parser just overwrites the value

hueyp04:02:52

so instead I tried: [(todo/delete {:id ~id}) {[:person/by-id author-id] [:todosCount {:todos (om/get-query Todo)}]}]

hueyp04:02:56

e.g. I root it myself

hueyp04:02:40

that results in: transacted '[(todo/delete {:id 1}) {[:person/by-id 1] [:todosCount {:todos [:id :text :completed? {:author [:id]}]}]}]

drcode04:02:19

Yeah, all sensible advice, thanks for this info, I feel like I am at step 27 of the 100 steps of Om Next mastery now :simple_smile:

hueyp04:02:23

but this is just a braincheck app seeing how things work

hueyp04:02:29

a lot of this stuff doesn’t matter unless you have a remote … local state just re-running ui->props hides any data synchronization problems you might have

hueyp04:02:35

like if your data is 100% local

hueyp04:02:05

but if you need remotes to be synched, you have to figure out how to make om send the right reads

hueyp04:02:13

which is like exactly what I’m working on right now

hueyp04:02:45

but you can make a sample app which has local state and no reads in transacts and it works great

drcode04:02:00

Yes, the remote part is where things are so challenging...

drcode05:02:03

@hueyp: FYI, your advice was spot-on... followed your thinking and it fixed all my problems- Thanks!

thiagofm16:02:58

(om next) Hello, I have a component nested inside another one. The main one has a query to [:game/tutorial], for example. That query works perfectly and returns the desired output. But the nested component have the same query specified and (om/props this) returns nothing. Anyone knows what could be happening?

iwankaramazow16:02:18

@thiagofm: Is your query composing to the top? (i.e. by om/get-query)

thiagofm16:02:29

iwankaramazow: no, very straightforward stuff, like this: http://pastie.org/10718130

thiagofm16:02:40

for some reason it doesn't execute the query :disappointed:

iwankaramazow16:02:18

'[lambdas/total] -> '[:lambdas/total]

iwankaramazow16:02:47

just a guess, but make sure you're using keywords if your parser handles keywords

thiagofm16:02:28

Yeah, sorry. My example is wrong. I'm using your version but still doesn't work :disappointed:

thiagofm16:02:01

I'm using the exact same query of another component, which retrieves results, but this one doesn't, it just returns nil for om/props

thiagofm16:02:09

It kinda sucks to hit those walls and get no error message or anything at all :disappointed:

thiagofm16:02:38

Can't seem to be able to debug what goes to query or anything :stuck_out_tongue:

iwankaramazow16:02:42

hmm, if another component has that query and gets its props

iwankaramazow16:02:52

just pass those props down to the child

iwankaramazow16:02:10

the query on the child is redundant

thiagofm16:02:43

@iwankaramazow: I'm just using the same query because it doesn't work for any query. I actually wanted to use a different query

iwankaramazow16:02:52

do you have a link to the project? (github?)

thiagofm16:02:53

@iwankaramazow: https://github.com/thiagofm/haxlife it's using chestnut, so even to run it is easy. So, both the Window and Player components are the same, but in the Player component, the query doesn't run (it prints just nil, while the other prints {:game/tutorial #{[1 false]}})

thiagofm16:02:14

I'm trying to write a simple game

thiagofm16:02:49

One detail is that I'm using Datascript, the queries you can find in haxlife/data/query

iwankaramazow17:02:26

Window is your root, you're not passing any props down

iwankaramazow17:02:42

(tutorial-comp id)
                       (game-window-comp)

iwankaramazow17:02:59

only id get's down

iwankaramazow17:02:01

the root-query 'injects' the result as props on the root component

thiagofm17:02:19

Why do I need to pass the props down? If I (game-window-comp 1) it still doesn't work :disappointed:

thiagofm17:02:13

I admit I'm a bit lost. But if I'm querying in the Player component, shouldn't this be enough by itself?

iwankaramazow17:02:30

If a component deep inside the tree has a query, your have to compose it to the top with om/get-query on the root-component The root-component will get the result of that query as props

iwankaramazow17:02:38

then you have to manually pass them down

iwankaramazow17:02:43

no way around this

thiagofm17:02:02

Okay, so I can't query on Player?

iwankaramazow17:02:48

I'll write some example code

thiagofm17:02:11

Okay, thanks a lot for all the help so far.

iwankaramazow17:02:12

(defui Window
  static om/IQuery
  (query [this]
         [(first (om/get-query Player))])
  Object
  (render ...))

iwankaramazow17:02:50

Window is your root-component, Player a child. This is an example of the query composing to the top.

thiagofm17:02:19

So, Window will basically do queries for the whole app?

thiagofm17:02:53

Wouldn't this make Window become a 1k line component soon? :disappointed:

anmonteiro17:02:54

@dnolen: updated wiki docs to reflect the computed docstring about replacing previous computed props. here's the diff: https://github.com/omcljs/om/wiki/Documentation-(om.next)/_compare/29efb387dd2eba77afc1a5eae0d8edfbcd60ad5d...cedf53506ff37e5d318bb24eca437c68c554df40

anmonteiro17:02:47

@iwankaramazow: your example is wrong because Window is stealing Player's props

iwankaramazow17:02:50

@thiagofm: it'll contain the full query, that might be a long query :stuck_out_tongue:

thiagofm17:02:42

Okay, great. I guess this is written in "Components, Identity & Norm...", I've read all the docs multiple times, but I'm just really getting it now that I'm writing stuff down.

iwankaramazow17:02:15

Just remember that a child when implementing IQuery, doesn't get the result from it's query, it gets the result trough props passing down the tree

thiagofm17:02:31

I quite like this approach though, if I could query separately in each component it would feel as everything had some sort of state

thiagofm17:02:58

That was very nice help, thanks!

iwankaramazow17:02:59

If I recall correctly, Relay/GraphQL injects props at without you passing down the props from the root

iwankaramazow17:02:52

In the beginning the notion of passing everything down seemed a bit strange at first, but it hasn't given me any problems (yet :innocent:) )

thiagofm17:02:08

Great, lemme see if I can fix it now :simple_smile:

thiagofm17:02:48

@iwankaramazow: any special reason of why you used the first function on (first (om/get-query Player)) ?

dnolen17:02:50

@anmonteiro: looks good to me

iwankaramazow17:02:12

@thiagofm: would be [[:game/tutorial]] without (first ...), with it gives you [:game/tutorial]

iwankaramazow17:02:32

just making sure the query is valid

thiagofm17:02:16

@iwankaramazow: just a last question, I guess. the Player component is deep down, how can I reference it? I have to require its file? Wouldn't this create a circular dependency error?

iwankaramazow17:02:11

@thiagofm: no, you should require Player in Window. Only if you also require Window in Player you get a circular dependency

seantempesta18:02:05

So, om-next is pushing my (rather limited) clojure skills. As soon as I moved my app-state, read, mutate and reconciler definitions to a separate namespace (weather-project.state) I started getting this error: No method in multimethod 'weather-project.state/mutate' for dispatch value: weather-project.ios.core/zip-change Sure enough, if I change the definition from:

(defmulti mutate om/dispatch)

(defmethod mutate 'zip-change
  [{:keys [state]} _ {:keys [zip-text]}]
  {:action
   (fn []
     (swap! state assoc-in [:zip] zip-text))})
to
(defmulti mutate om/dispatch)

(defmethod mutate 'weather-project.ios.core/zip-change
  [{:keys [state]} _ {:keys [zip-text]}]
  {:action
   (fn []
     (swap! state assoc-in [:zip] zip-text))})

seantempesta18:02:54

It works. But how can I reuse that method if I have to explicitly define what namespace the function will be called in?

hueyp18:02:53

I’m guessing the way you are quoting the transact is setting namespace

seantempesta18:02:22

(om/transact! this `[(zip-change {:zip-text ~zip-text})])

seantempesta18:02:37

How should I be quoting it?

hueyp18:02:39

yah, add in front of zip-change I think

hueyp18:02:59

I’m no expert on quoting, but I think in makes it so the symbol isn’t namespaced

hueyp18:02:02

no I’m dumb its ~ in front of the symbol … crap lemme find it

seantempesta18:02:51

Yeah, the quote doesn’t work:

weather-project.ios.core=> `[(zip-change {:zip-text "asdf"})]
[(weather-project.ios.core/zip-change {:zip-text "asdf"})]

weather-project.ios.core=> `[('zip-change {:zip-text "asdf"})]
[((quote weather-project.ios.core/zip-change) {:zip-text "asdf"})]

hueyp18:02:24

try ~zip-change

hueyp18:02:51

the easiest thing to do is just namespace mutations yourself :simple_smile: zip/change :simple_smile:

seantempesta18:02:24

Ah, it’s tilda quote

seantempesta18:02:35

(om/transact! this `[(~'zip-change {:zip-text ~zip-text})])

hueyp18:02:01

that makes sense

seantempesta18:02:57

Oh yeah, zip/change is much easier to read.

hueyp18:02:19

yah usually it works out your mutations have a ‘thing’ to namespace them by anyways

hueyp18:02:26

user/set-name, etc

seantempesta18:02:44

Yeah, makes sense. Thanks @hueyp!

hueyp18:02:26

anyone have much experience with using :query-root meta?

hueyp18:02:33

with process-roots

bensu19:02:36

I need a little conceptual guidance. The root component composes a query which populates the state for the whole app. If I want something to be requested from the served afterwards, conditional on a child component being mounted, where should I do it? (or what should I read?)

iwankaramazow20:02:49

Probably in your parser

iwankaramazow20:02:15

check out the item, how can I delay loads

bensu20:02:21

@iwankaramazow: thanks, I read that but couldn't figure it out. Is :loading somehow a special value to om.next?

iwankaramazow20:02:01

@bensu: :loading is the possible value v of the destructured 'response' from (find @state key) :smile:

iwankaramazow20:02:18

not om specific

iwankaramazow20:02:56

it just means you can conditionally delay loads based on your app-state

iwankaramazow20:02:40

maybe you could put something in your state indicating that the component is mounted

iwankaramazow20:02:11

for example :is-mounted

bensu20:02:48

@iwankaramazow: I get it. Thanks! That is not what I'm going to do though, I'm going to use the same condition I use to decide if the component should be mounted in the first place

iwankaramazow21:02:34

Keep in mind root-query gets composed even if components aren't mounted

iwankaramazow21:02:44

(correct me if I'm wrong)

iwankaramazow21:02:52

that's the reason they are static

bensu21:02:03

yeah, that was the problem, but your solution will help me delay the read

bensu21:02:03

another problem I'm having is "No queries exist for component path ..."

iwankaramazow21:02:49

I encountered that one on more than one occasion :smile: Not sure how it should be fixed without concrete code.

bensu21:02:26

Since it happens on a rerender (during reconcile!) I don't know how to narrow it down

bensu21:02:07

It might be related to the fact that the smallest component specifies a query which its parent is not currently using

thiagofm21:02:29

Can I get a small datascript help? I'm trying to update the value of the key :lambdas/total to it + 1 (I don't want to use inc, because this 1 will become something else after)

thiagofm21:02:39

haxlife.data.db=> conn #object [cljs.core.Atom {:val #C07V8N22C/DB {:schema {}, :datoms [[1 :game/tutorial false 536870915] [2 :lambdas/per-character 1 536870914] [2 :lambdas/per-second 1 536870914] [2 :lambdas/total 0 536870914]]}}] haxlife.data.db=> (update-in (d/db conn) [2 :lambdas/total] #(+ % 1))) #C07V8N22C/DB {:schema {}, :datoms [[1 :game/tutorial false 536870915] [2 :lambdas/per-character 1 536870914] [2 :lambdas/per-second 1 536870914] [2 :lambdas/total 0 536870914]]}

thiagofm21:02:46

what is wrong? :disappointed:

grzm22:02:22

@thiagofm: can you create a function for it? such as (fn [x] (+ 2 x)) ?

grzm22:02:42

where 2 is something you can change as you desire

grzm22:02:49

oh, I see you're already doing something of the sort :confused:

grzm22:02:40

have you confirmed that inc works as expected in place of #(+ % 1) ?

wilkerlucio22:02:02

hello people :simple_smile:

wilkerlucio22:02:24

I gotta into a situation that I'm wondering if it's responsability of my code or it should be done by Om.next

wilkerlucio22:02:40

I have a query that looks like this:

wilkerlucio22:02:54

considering that on initial load the :categories are not available, it's going to be loaded on the first remote request

wilkerlucio22:02:33

the query rewrite seems to work fine, it removes the :menu from the game and add it back on the rewrite, making the server response being like this:

wilkerlucio22:02:07

when this response is merged, all the categories are propertly identified and added to the index, which one gotcha

wilkerlucio22:02:29

the :categories key itself (which should contain a list with refs for the categories) never gets into my local state

wilkerlucio22:02:35

then I wonder if it's a bug (meaning the Om.next should be able to recognize the [:categories _] and add it into the root of my state with the list of refs) or if I need to manually handle this before merging

wilkerlucio22:02:01

so, Om.next is supposed to handle the merge on those situations?

thiagofm22:02:58

@grzm: I didn't confirm that it works with inc. After having too much issues doing the update I'll do just a select + update, it's just a pet project, not worth fighting too much against something I'll have learned better later

thiagofm22:02:24

@grzm: thanks for the help, though!

iacopo23:02:31

anyone can help me with the IDisplayName protocol? i’m trying to debug some code and it would be very helpful. i implemented it this way:

(defn simple-component [data owner]
  (reify

    om/IDisplayName
    (display-name [_]
      "simple-component")

    om/IRenderState
    (render-state [_ _]
      (dom/li nil (:name data)))))

iacopo23:02:21

but React dev tools always shows &lt;No display name&gt; for all components