Fork me on GitHub
#untangled
<
2016-10-06
>
jasonjckn19:10:37

if I have a mutation 'create-object what's the pattern for transacting 'show-object IFF 'create-object succeeds in creating the object? should I have a post-mutation for 'create-object and transact! 'show-object in the post mutation?

tony.kay19:10:10

I take it show-object is a server query?

jasonjckn19:10:28

'show-object changes the :current-tab to show the object, and does load-field-action

tony.kay19:10:40

put that all in create-object

jasonjckn19:10:57

create-object also hits server though, so it's on server response that tab changes

tony.kay19:10:20

so, if the server denies something, you can throw an error that will trigger a fallback

tony.kay19:10:35

I assume create-object might fail from server permissions?

jasonjckn19:10:43

ok (transact! [(create-object) (show-object) (tx/fallback)]) ?

tony.kay19:10:50

tons of ways to do it. Your example is a bit vague

jasonjckn19:10:51

show-object is only transacted in non-exceptional case

jasonjckn19:10:27

yes create-object may fail for various reasons

tony.kay19:10:29

well, sort of

tony.kay19:10:41

so here's the thing. A single transaction in UI will be sent as single net transaction

tony.kay19:10:57

so, yes, if you implement it on the server to abort at create-object, then show-object should not happen

tony.kay19:10:12

in which case fallback may or may not be needed

tony.kay19:10:56

I would, however, tend to use alternate logic. I would not be showing UI for making the object if it was possible for happy path to deny.

tony.kay19:10:04

I'd show the object immediately for good user experience

tony.kay19:10:18

and use fallback to fix things up on the (rare) unhappy path

tony.kay19:10:26

otherwise you're waiting on the server, which is old-school thinking

jasonjckn19:10:08

hm yah, well for one thing there's server side validation of 'create-object params

jasonjckn19:10:20

so it may reject the user input, and need it to be reentered

jasonjckn19:10:27

i'm integrating with legacy system

tony.kay19:10:40

yeah, that's the way to do it then

jasonjckn19:10:46

kk, thanks tony

tony.kay19:10:54

I mean, you could validate the fields as you go (optimistically)

tony.kay19:10:10

and not do the submit of final object till you're sure it is going to go ok

tony.kay19:10:22

e.g. those validations could be server interactions

jasonjckn19:10:32

nods something to consider

tony.kay19:10:34

but as we described it above should work

ethangracer19:10:27

If there are are any more NYC area folks in here, I’d like to host a Clojure Meetup about Untangled. RSVP here! http://www.meetup.com/Clojure-NYC/events/234676309/

jasonjckn20:10:23

any examples on tempids because todomvc?

jasonjckn20:10:41

i've read some of the source

jasonjckn20:10:22

then I guess that updates the table in app-state, from {:table { :http://datomic.id/foobar { ..}}} to {:table {42 { ...}}}

tony.kay20:10:42

You should use (om/tempid) at the UI to send temp ids into your mutation

tony.kay20:10:59

the : is part of our testing library

tony.kay20:10:27

then return {:tempids {tmpid realid}} from your server mutation.

tony.kay20:10:36

everything else is automatic

jasonjckn20:10:33

You should use (om/tempid)` at the UI to send temp ids into your mutation ` I don't quite follow, so

(defmethod mutation 'my/mutation [e k p]
{:remote true
:action ???} )

tony.kay20:10:57

I'm sure todomvc does it this way...

tony.kay20:10:24

yes, :remote true should be sufficient assuming you don't need to modify the AST

tony.kay20:10:47

the local action is just to put the data in your db, as normal (including the tempid)

tony.kay20:10:00

tempid does NOT get called in the mutation!

tony.kay20:10:11

would cause problems

tony.kay20:10:22

tempid is called on the UI, and passed as a param OF the mutation

jasonjckn20:10:36

So

(defmethod mutation 'create-object [e k p]
{:remote true} )
is correct

jasonjckn20:10:44

then.. in api-mutate

tony.kay20:10:40

remember that mutations are called more than once on the client (once for UI, and once for each remote). Tempid returns something diff every time 🙂

tony.kay20:10:19

The only way we differ from Om Next on this is that we handle the joining together of tempids from the server for you...which you normally have to do manually.

jasonjckn20:10:38

ok so in todomvc (update-in [:todos :list/items] (fn [todos] ((fnil conj []) todos [:todo/by-id id]))) (assoc-in [:todo/by-id id] {:db/id id :item/label text}))))}) the untangled engine automatically finds all references to this 'id' in tables, and links, etc

tony.kay20:10:42

we don't really differ so much as implement

tony.kay20:10:58

yep, rewrite of tempids is automatic

tony.kay20:10:02

anywhere they appear

tony.kay20:10:06

in app state

jasonjckn20:10:14

you walk the whole of app state?

tony.kay20:10:26

all you have to do is return {:tempids {...}} from server mutation

tony.kay20:10:45

yes, we walk the app state...just a clojure prewalk, I think

jasonjckn20:10:54

Ok right on, thanks i'll give it a shot now

tony.kay20:10:06

In regular Om, you have to say what your ID fields are called...it is an optimization so that migrate is a bit faster. In practice, it really isn't so slow (network delay will be much longer typically)...so we opted for ease instead of premature optimization. We can always work on speeding it up later if it becomes a problem.

tony.kay20:10:51

For example, mark-n-sweep to remove missing data from responses is optimized by walking the query. We could do similar things for migrate that would speed it up. We really haven't found the need, though.

jasonjckn20:10:13

is this right?

(defmethod api-mutation 'booking2/create
  [env key {:keys [id]}]
  {:action (fn []
             (println "id: " (pr-str id))
             {:tempids {id 42}})})

jasonjckn20:10:19

i'm having issues

adambrosio20:10:40

is that client or server?

jasonjckn20:10:08

my global state gets it's om/tempid replaced with ...nothing...

jasonjckn20:10:37

curiously 'booking2/create shows up in the global app state too

jasonjckn20:10:04

not sure why the mutation symbol would be put into global app state

jasonjckn20:10:32

(defmethod m/mutation 'booking2/create [env _ {:keys [id]}]
  {:remote true
   :action (fn []
             (m/swap-this! env assoc :new-booking-id [:booking/by-id id]))})

jasonjckn20:10:44

(nav-item {:title "create booking #2"
                :onClick #(transact! T [(booking2/create {:id (om/tempid)})
                                        (app/choose-tab {:tab :booking2})])})

adambrosio20:10:51

is 42 what you are always returning?

adambrosio20:10:57

im not seeing anything obvious thats wrong

jasonjckn21:10:17

got it working,

jasonjckn21:10:26

(nav-item {:title "create booking #2"
                :onClick #(transact! T [(booking2/create {:id (om/tempid)})
                                        (app/choose-tab {:tab :booking2})])})
doesn't work

jasonjckn21:10:38

(nav-item {:title "create booking #2"
                :onClick #(transact! T [(booking2/create {:id (om/tempid)})})
does

adambrosio21:10:52

that looks like a bug

jasonjckn21:10:12

oh, sh* , I might be nuking the state in choose-tab

jasonjckn21:10:22

i thought it would show up in the DIFF at least, but maybe it happen quickly

adambrosio21:10:33

nuking? thats not a good idea

jasonjckn21:10:44

let me confirm that's it

jasonjckn21:10:55

yah choose-tab calls initial-state on the TabComponent

jasonjckn21:10:01

i thought it was a good idea at the time

jasonjckn21:10:07

fresh tab initialized

jasonjckn21:10:51

you can also switch tabs with merely a (om/merge Root {:current-tab (initial-state MyTabComponent nil)}) which is neat

adambrosio21:10:12

well it sounds like that was the problem

adambrosio21:10:34

shouldnt you be switching the tab ident to point to the new tab instead?

jasonjckn23:10:14

@adambros is there a snapshot release with your tools ?

jasonjckn23:10:24

i could use a mixin right now

adambrosio23:10:26

you could probably do a checkouts if you really want it