Fork me on GitHub
#om
<
2016-04-04
>
podviaznikov02:04:12

init state should work like this in on.next

(initState [this]
    (println “init state”))
, is it correct?

taylor.sando02:04:42

It is initLocalState

uwo16:04:14

@anmonteiro: (cc @cjmurphy) Ok, so I’ve thrown together the Autocomplete tutorial code and added a root component with a read method that attempts what I understood you to be suggesting on Saturday. Obviously the autocomplete works if it is the target of add-root!, but once it’s the child of a Root component it becomes unclear to me how to compose the query. https://github.com/uwo/om-params

seanirby16:04:39

@uwo: it looks like your :search/results read method is not going to be called in your code above. Only the :root-query read will be called

seanirby16:04:42

only the top level keys in your query will trigger a read

cjmurphy16:04:59

@seanirby: This one doesn't work either:

(defmethod read :root-query
  [{:keys [query parser ast] :as env} k params]
  (println "The user's query is in the ast: " (-> ast :children first :params :user-query))
  (println "The query is already as we need it to be: " query)
  {:value {:root-query (parser env query)}})

uwo16:04:06

@seanirby: yeah, you’re right :search/results is never called in that case

uwo16:04:17

This obviously calls it but the the remote logic is never handled at the root level. so recursive parsing seems kinda off the table (would have to share remote logic)

(defmethod read :root-query
  [{:keys [parser query] :as env} k params]
  {:value (parser env query)}  )

isak16:04:21

@uwo why do you think that implies recursive parsing is off the table? can't you just call the parser again from :root-query if needed with different args?

isak16:04:17

i haven't had to do it myself yet but i think you mess around with the read-tracking parser from here you'll see how it can be done

uwo16:04:22

@isak: you’re right I shouldn’t say off the table, but after sharing this with anmonteiro a couple of days ago, he discouraged me from going the recursive route

isak16:04:44

hm, i see

seanirby16:04:18

uwo: i'm also unfamiliar with recursive parsing. can you not do his other suggestion and put the logic in :root-query

isak16:04:34

seems like it would be a good use case for it, though i'm just getting into it. I was going to go this route to handle client side routing and subqueries

uwo16:04:11

@seanirby: certainly, but then we’re not colocating query with components ( to be glib)

isak16:04:18

because i'd still want to spread out my read logic as normal even though everything gets composed from a root query

isak16:04:12

i wonder what alternative there is if it is not a simple query handled by db->tree

uwo16:04:16

@seanirby: actually strike what I just said, the Iquery would still live on the component

uwo16:04:21

@seanirby: when I asked him about taking that approach he responded that it was best not to: https://clojurians.slack.com/archives/om/p1459549857002290

uwo16:04:40

sorry took me awhile to find the comment simple_smile

anmonteiro17:04:10

@uwo: after looking at the concrete example, it seems that what I said might not be exactly true after all

anmonteiro17:04:48

I'm thinking that a recursive parsing approach would probably help here

anmonteiro17:04:58

(defmethod read :root-query
  [{:keys [query target parser ast state] :as env} k params]
  (let [val (parser env query target)]
    (if (and (= target :search)
          (not (empty? val)))
      {:value (select-keys @state [:search/results])
       :search (om.next.impl.parser/expr->ast (first val))}
      {:value val})))

anmonteiro17:04:10

changing the read method to this works in your example

uwo17:04:59

hm! thanks! so for all components that require query params they’ll need to be a comparable read method on root?

anmonteiro17:04:36

I wouldn't say that's always the case

isak17:04:14

isn't this his query?

isak17:04:56

if so the target is nil

isak17:04:14

ah, i see

tomjack17:04:25

so what happens if we need to read more than one thing from :search in :root-query? I had thought once that recursive parsing would make it work, but I don't see how

iwankaramazow17:04:34

@tomjack: what's the root-query?

isak17:04:04

would it make sense to call the parser recursively, then pick out the :value from the parser result recursively, and merge it into the top level :value map that will be returned?

tomjack17:04:32

in om-params the root-query is like [{:root-query [(:search/results {:query "foo"})]}]

tomjack17:04:49

but say we want [{:root-query [(:search/results {:query "foo"}) (:other-search/results {:query "bar"})]}]

iwankaramazow17:04:29

ah it's just the autocomplete example from the tutorial?

iwankaramazow17:04:43

I'll run it locally to check the result

uwo17:04:51

@iwankaramazow: except it nests the autocomplete in a root component

uwo17:04:15

just pushed the change António suggested

iwankaramazow17:04:54

ok, I'll take a look at it 😄

uwo17:04:28

I’m curious if this will become an unwieldy requirement in an app that has a lot of components with dynamic queries.

iwankaramazow17:04:11

@uwo: I see what you mean, almost finished here

iwankaramazow17:04:17

just gotta modify the send function

iwankaramazow18:04:04

This might be a little tricky 😄

iwankaramazow18:04:45

give me 10 more minutes 😛

tomjack18:04:56

I'm wondering if line 42 shows a bug in om

iwankaramazow18:04:01

anyone tried this with :query-root true & om/process-roots ?

uwo18:04:14

@iwankaramazow: why process-roots? we aren’t dealing with client local keys, no?

iwankaramazow18:04:05

My idea was to return {:search (assoc ast :query-root true)} in the read of :search/results

iwankaramazow18:04:44

This way we can rewrite [{:root-query [(:search/results {:query ""})]}] to [{(:search/results {:query "test"})]}]

iwankaramazow18:04:06

Or at least om could do it for us 😄

iwankaramazow18:04:42

however, I'm doing something wrong at the moment

uwo18:04:16

gotta take lunch simple_smile

iwankaramazow18:04:59

I'll let you know when I've found a solution

iwankaramazow18:04:07

The only thing I changed:

(defmethod read :root-query
  [{:keys [parser query ast target] :as env} key _]
  (let [search (parser env query target)]
    (if (and target (not-empty search))
      {:search (update-in ast [:query] (fn [query] search))}
      {:value (parser env query)})))


(defn send-to-chan [c]
  (fn [{:keys [search] :as env} cb]
    (when search
      (let [{[search] :children} (om/query->ast (get-in (first search) [:root-query]))
            query (get-in search [:params :query])]
        (put! c [query cb])))))

tomjack18:04:15

solution to what? I thought it was already working

iwankaramazow18:04:37

ah ok never mind then 😛

iwankaramazow18:04:29

ah I see, anmonteiro already provided one

iwankaramazow18:04:37

(om.next.impl.parser/expr->ast (first val)) is in fact much cleaner

iwankaramazow18:04:19

my first instinct was to call the parser recursively on the :root-query key, and then use process-roots

uwo18:04:09

yeah, what I was curious about was having to write essentially two read methods for each dynamic query, one with the actual logic and another to compose with root

iwankaramazow18:04:55

that's pretty much the case

uwo18:04:05

of course all root keys will need read impl, but plenty of them can use the helper fns

iwankaramazow18:04:37

there are some places where you have to compose queries in joins or unions to make valid queries

iwankaramazow18:04:19

the logic of

(defmethod read :root-query
  [{:keys [parser query ast target] :as env} key _]
  (let [search (parser env query target)]
    (if (and target (not-empty search))
      {:search (update-in ast [:query] (fn [query] search))}
      {:value (parser env query)})))
will mostly be the same in all those cases

iwankaramazow18:04:44

indeed helper fns will save you

uwo18:04:30

gotcha. thanks!

tomjack18:04:51

nit: (assoc ast :query search) simple_smile

iwankaramazow18:04:28

no idea what I was thinking

uwo18:04:01

oh versus update-in right

iwankaramazow18:04:57

@tomjack: have you tried the [{:root-query [(:search/results {:query "foo"}) (:other-search/results {:query "bar"})]}] version?

tomjack18:04:14

yeah, my patch above was working

tomjack18:04:22

but either there is a bug in om, or I'm doing it wrong

uwo18:04:28

should I be using fns from om.next.impl.parser?

tomjack18:04:14

anmonteiro's version does (first val) and uses that for expr->ast, but that will throw away part of the query if there is more than :search/results

tomjack18:04:24

so I used query->ast, but this triggers what looks like a bug to me

tomjack18:04:51

I am working with that patch to om above on my project, so eager to learn whether the patch makes sense or whether I'm doing it wrong simple_smile

iwankaramazow18:04:32

I'll try it first

iwankaramazow18:04:48

did you duplicate AutoCompleter with :other-search/results in the query?

tomjack19:04:16

just one autocompleter, with

'[(:search/results {:query ?query})
  (:search/other-results {:query ?query})]

iwankaramazow19:04:58

same params for both searches?

iwankaramazow19:04:05

ah you kept just one search input?

tomjack19:04:05

hmm, your (assoc ast :query search) seems like it may avoid the problem?

iwankaramazow19:04:50

no idea yet, I'm copying your code 😛

tomjack19:04:21

by forcing the send to handle exprs {:root-query [...]}, you can stuff multiple things in the ...

tomjack19:04:35

where I wanted send to receive just [...]

iwankaramazow19:04:57

why don't we do:

(defn search-loop [c]
  (go
    (loop [[query cb ] (<! c)]
      (let [[_ results] (<! (jsonp (str base-url query)))]
        (cb {:search/results results
             :search/other results} ))
      (recur (<! c)))))

tomjack19:04:04

I was just pretending like they might return different things simple_smile

iwankaramazow19:04:42

In a more real world situation, you wouldn't write (cb {:som-key "results"})

iwankaramazow19:04:04

:som-key is extremely dynamic

iwankaramazow19:04:55

in most cases, om would know under which key it would need to merge, or at least you supply it (most often dynamically)

iwankaramazow19:04:00

Example:

(defn send-to-chan [c]
  (fn [{:keys [search] :as env} cb]
    (when search
      (let [{[search] :children} (om/query->ast (get-in (first search) [:root-query]))
            query (get-in search [:params :query])
            key (get-in search [:key])]
        (put! c [key query cb])))))

(defn search-loop [c]
  (go
    (loop [[ key query cb ] (<! c)]
      (let [[_ results] (<! (jsonp (str base-url query)))]
        (cb {key results} ))
      (recur (<! c)))))

Lambda/Sierra20:04:20

I think I realized something: in JS React, nothing says the props passed to a child have to be part of the same data structure as the parent's props. The parent is free to create new props and pass them to the child.

Lambda/Sierra20:04:50

It's only in Om.now using cursors that you care if the child's props came from the same data structure as the parent's.

Lambda/Sierra20:04:25

If you don't use cursors, a parent component can safely generate props for its children, right?

Lambda/Sierra20:04:50

Or you could create new props on-the-fly in a call to om/build for example.

Lambda/Sierra20:04:42

Am I missing anything?

isak20:04:41

@stuartsierra: you can create new props without a problem either way (other than potential overrendering), though if you do pass down a cursor and props, you end up wrapping the cursor, so you just have to be careful to destructure the cursor before doing transact calls in the child component

Lambda/Sierra20:04:37

@isak: By “wrapping the cursor,” do you mean that Om.now will always wrap props in a cursor, even if that cursor has no root Atom to link to?

isak20:04:35

no, i mean if you send some props to a component inside a map, then you have to make sure to treat it that way and not like a cursor

Lambda/Sierra20:04:38

Right. If you want to use the cursor, you have to pull it out of whatever data structure you passed as props.

isak20:04:08

for om.next remotes, is it normal to have a lot of read methods, or just a few? i'm doing it now and i'm leaning towards just one, even though the client will have quite many

Lambda/Sierra21:04:19

Or is this what (om/build … {:opts {…}}) is for?