Fork me on GitHub
#untangled
<
2016-09-12
>
jasonjckn22:09:42

defui SearchTable [{[:search :tab] [:es-type :es-sort-fields :sort-ascending?]}
                    {:hits (get-query SearchTableRow)}
                    :total]

jasonjckn22:09:52

(defui SearchTab [{:hits (get-query SearchTable)}

jasonjckn22:09:38

i do load-field-action on :hits in SearchTab, and this causes the props to have not-found

jasonjckn22:09:17

so far I haven't noticed any issues in production with this, and everything still works as expected

jasonjckn22:09:34

but it would be nice if load-field-action excluded [:search :tab] like it would exclude :ui/foobar

tony.kay22:09:51

load field should narrow the query to JUST the field

jasonjckn22:09:04

i'm loading :hits on SearchTab

tony.kay22:09:17

yeah, so [:search :tab] should not be affected

jasonjckn22:09:32

this is the behaviour i'm seeing

tony.kay22:09:15

are you right at a union?

tony.kay22:09:23

the ident might be confused?

jasonjckn22:09:30

so the api-read is going to see a query like [:search [{:hits [:hits :total [:search :tab]]}]]

jasonjckn22:09:40

notice I have 2 :hits in my example so it's confusing

tony.kay22:09:50

why is :search :tab there?

tony.kay22:09:04

remember that that is an ident

jasonjckn22:09:13

yes I need access to that data in SearchTable

jasonjckn22:09:28

i was hoping idents would be stripped out like ui/foobar is stripped out

jasonjckn22:09:35

putting an ident in a query is valid om.next syntax

jasonjckn22:09:39

but it shouldn't be sent to the server

tony.kay22:09:47

it is, but you're saying the SERVER should return it

tony.kay22:09:54

by putting it in load-field's query

tony.kay22:09:00

which overwrites it

tony.kay22:09:27

totally valid thing to ask for, but you're unintentionally asking for it

tony.kay22:09:34

no way to automatically elide that

tony.kay22:09:58

load-field has a :without option for this kind of case, but not sure we tested an ident case

jasonjckn22:09:06

i agree the case is contrived a bit, but sticking with my analogy on ui/foobar, if I load-field-action on :hits, and the query was [:search [{:hits [:hits :ui/foobar]}]] that would not be sent to the server

tony.kay22:09:25

:ui prefix is defined to always be elided...separate issue

tony.kay22:09:30

an ident is valid query syntax

tony.kay22:09:37

(to server)

jasonjckn22:09:55

i guess that's my confusion I thought an joining on an ident has no meaning server side

tony.kay22:09:01

in fact, load-field sends and ident-based join to the server 🙂

jasonjckn22:09:15

i'll try without 🙂

tony.kay22:09:22

[:type-of-thing id] makes total sense to a server 🙂

tony.kay22:09:28

if it is a persistent thing

jasonjckn22:09:28

Yah I see now

jasonjckn22:09:37

nods okay, i'll use computed props or something

tony.kay22:09:51

try :without. We should make that support idents

tony.kay22:09:10

it may "just work". Have not looked at the impl

tony.kay22:09:20

but it should just work 😉

jasonjckn22:09:35

so in this case, when the server returns data for the ident, do you automatically merge it into [:search :tab] ?

tony.kay22:09:40

:without #{[:type :id]}

tony.kay22:09:13

merge is recursive on return value, and since you asked for it but didn't return it: not-found

tony.kay22:09:50

though technically the sweep step should turn not-found into literally nothing...that's a minor bug too

jasonjckn22:09:30

it's weird to see anything at all in the global state at [:search :tab :hits [:search :tab]] for the ident [:search :tab], because if I actually returned a value from the server for [:search :tab] it would not exist in the global state at the path [:search :tab :hits ...] the data would be merged into [:search :tab], and then when om.next computes the props for the query [... [:search :tab]] it would fill it in

jasonjckn22:09:42

but as it stands I see [:search :tab] not found in the global state under hits

jasonjckn22:09:14

yah "into literally nothing" i guess we're on the same page 🙂

tony.kay22:09:19

oh right. that's a little screwy

tony.kay22:09:00

it should have totally "wiped" your :tab entry of the :search table

tony.kay22:09:20

that's another ident-related merge bug, I'd say

tony.kay22:09:28

when the ident isn't in a join (perhaps)

jasonjckn22:09:58

fyi i'm starting to write a series of little addons to our untangled project, i'm not sure they're suitable for mass adoption, but they work in all our use cases and simplify the API

jasonjckn22:09:22

so i'll entertain you with the list of addons fyi 🙂

jasonjckn22:09:46

1) i wrote my own transact! to never require an apostrophe on the query

jasonjckn22:09:10

(defmacro transact!
  ([txs]
   `(transact! (:reconciler @admin.core/app) ~txs))

  ([reconciler txs]
   (let [txs (->> txs
                  (mapv (fn [xf]
                          (if (list? xf)
                            (let [[mutation-sym & args] xf]
                              (assert (symbol? mutation-sym))
                              `(list (quote ~mutation-sym) [email protected]))
                            xf))))]

jasonjckn22:09:00

wrote my own defui macro that returns a factory when you do @MyComponent, and also expects query as 2nd argument

jasonjckn22:09:12

(defmacro defui [name q & forms]
  {:pre [(symbol? name)
         (or (map? q) (vector? q) (list? q))]}
  `(let [factory-fn# (atom nil)]
     (om.next/defui ~(with-meta name {:once true})

         ~'static cljs.core/IDeref
         (~'-deref [this#]
          @factory-fn#)

         ~'static om.next/IQuery
         (~'query [this#]
          ~q)

         [email protected])

     (reset! factory-fn#
             (om.next/factory ~name {:keyfn (framework.core/mk-defui-keyfn ~name)}))))

jasonjckn22:09:32

it also uses ident as the react-key by default

jasonjckn22:09:41

if no idents, then it uses GUID

jasonjckn22:09:47

good enough for our purposes

jasonjckn22:09:40

in our mutations you can bind a mutation namespace to an ident, so that the 'ref' is always set to the binding for any mutation that begins with myns/foobar

jasonjckn22:09:53

(m/bind-ns-to-singleton-ref! 'search admin.ui.search.core/SearchTab [:search :tab])

jasonjckn22:09:21

this let's us transact! from anywhere on (search/...) and still have the mutation implementation leverage 'ref'

jasonjckn22:09:45

you can also bind namespaces to ComponentType

jasonjckn22:09:03

(m/bind-ns-to-component! 'search-row admin.ui.search.table/SearchTableRow)
in this case when transacting on this, (presumably a child of SearchTableRow such as SearchTableRowColumnXYZ ) any mutation that that has namespace search-row/xxx will find the nearest parent with component type SearchTableRow

jasonjckn22:09:24

so the idea here is to use computed props less

jasonjckn22:09:35

and just have transact! be applied to relevant parent

jasonjckn22:09:48

hope that's useful

jasonjckn22:09:24

i guess another would be I have swap-this! swap-global!

jasonjckn22:09:31

swap-global! is just swap! on app state

jasonjckn22:09:38

swap-this! is swap! on app state + ref

jasonjckn22:09:59

(defmethod m/mutation 'search-row/activate-listing [env _ params]
  {:action (fn []
             (m/swap-this! env assoc :status "ACTIVATED"))})

tony.kay23:09:42

Yeah, I like the swap helpers. Not quite following what the bind things are doing. I'm a little tired today...not thinking very fast 😕

tony.kay23:09:04

The deref trick for factories is an interesting twist

tony.kay23:09:20

ah, I see on your binding. Interesting. A bit more convoluted on the ref bit. Harder to trace what's going wrong when things bubble like that, but tractable.

tony.kay23:09:33

I can see how that reduces some of the boilerplate

jasonjckn23:09:33

@tony.kay fyi the deref trick code I wrote doesn't work in :advanced mode yet 😞

jasonjckn23:09:52

i think 'static' has some issues in advanced that i'm not appreciating

tony.kay23:09:07

you using the latest Om/UC?

tony.kay23:09:19

I think there was a static fix, but perhaps it didn't get merged yet

jasonjckn23:09:23

hm interesting

jasonjckn23:09:30

i'll try it out i haven't tested advanced in 2 months