untangled

NEW CHANNEL: #fulcro
urbank 2017-03-06T11:29:36.005088Z

why does IQuery (query [this]) get passed 'this'? In what case would it be used?

urbank 2017-03-06T12:37:07.005089Z

Is it for dynamic queries? I read on the slack log some mention of dynamic queries, but I'm not sure what it means, and what is its use case

qqq 2017-03-06T12:48:20.005090Z

@urbank: I don't know either. If you figure it out, please let me know.

qqq 2017-03-06T12:48:41.005091Z

I do know that I often see [_] and it seems like it's main use is taht the (query ... ) can depend on the defui component

mitchelkuijpers 2017-03-06T13:01:52.005092Z

@urbank @qqq You can use the instance of the component for dynamic queries indeed, but I never need this with untangled. And it adds a lot of complexity that I would stay away from.

qqq 2017-03-06T13:04:58.005093Z

@mitchelkuijpers : someone else told me that was "impossible" becuase only the Root node makes queries

qqq 2017-03-06T13:05:16.005094Z

so therefore, the only use is that it tells the Root what attributes it wants

qqq 2017-03-06T13:05:33.005095Z

furthermore, iirc, this function is "static", so it's further evidence it can't actually depend on the value of this

mitchelkuijpers 2017-03-06T13:06:02.005096Z

If you add a console.log in query you will see it get's called many times, but you are right that it needs to compose to root

qqq 2017-03-06T13:07:23.005097Z

This is my understanding: when Root needs to render, root needs to get it's data to gets its data, it submits it query to get the query of Root, we call all the children of Root to get their queries (and this is when the query function gets called) == it is my understanding that besides the above, query is NEVER called is that correct ?

urbank 2017-03-06T13:10:09.005098Z

@qqq That's my understanding as well. The component query gets called when its composed into the Root query.

urbank 2017-03-06T13:15:04.005099Z

@mitchelkuijpers I'm still having a bit of a hard time reconciling generic components and not having dynamic queries which would tell the component which data it should care about.

qqq 2017-03-06T13:15:31.005100Z

@urbank: I couldn't figure that out either, which is one of the reasons I switched over to datascript for my db.

urbank 2017-03-06T13:19:13.005101Z

@qqq Yeah, datascript basically lets you do anything from anywhere, because it's literally just a bunch of datoms, so all you need to change some piece of data is the global unique id of that data. However, I found some issues with performance when 'benchmarking'. It's possible that I was just doing something very wrong. You've had no issues with performance?

urbank 2017-03-06T13:19:36.005102Z

On the other hand, I'm pretty sure there's a solution to the generic component problem in untangled, I just don't understand it

qqq 2017-03-06T13:20:05.005104Z

@urbank: what type of performance issues?

qqq 2017-03-06T13:20:20.005105Z

for writes, I expect it to be 6x slower since it has to update every index

qqq 2017-03-06T13:20:46.005106Z

for queries, as long as the ordering is not stupid, I expect it to be drastically faster since it doesnot have to linearly scan all objects

qqq 2017-03-06T13:21:28.005107Z

@urbank: with no intention to offend -- have you worked through the first 4 sections of http://www.learndatalogtoday.org/ ? I found it very useful for mentally thikning about how the order of clauses affect the speed of a query

urbank 2017-03-06T13:23:51.005108Z

None taken! I have actually gone through that. I think I just had a lot of queries. There was one q which got all the entity-ids that I wanted, and passed them to subcomponents where each of the subcomponents did a pull for the attributes it cared about

urbank 2017-03-06T13:24:30.005109Z

I was also using Posh (if you've heard about it)

qqq 2017-03-06T13:25:11.005110Z

Is Posh the one where it tries to infer which datascript queries need to be rerun automatically?

qqq 2017-03-06T13:25:19.005111Z

That seemed way too magical for me.

urbank 2017-03-06T13:25:35.005112Z

Yeah, that one

qqq 2017-03-06T13:25:43.005113Z

I wonder if that's what's making it slow.

qqq 2017-03-06T13:25:57.005114Z

I[m using https://github.com/omcljs/om/wiki/DataScript-Integration-Tutorial at th moment.

qqq 2017-03-06T13:26:09.005115Z

And my strategy is: I write my own datascript querieis; I think very hard about how to make them fast, and I don't do any other optimizations.

qqq 2017-03-06T13:26:33.005116Z

Basically, my goal is : queries = lookup 1 index, get items, then just minor filtering on them;

qqq 2017-03-06T13:27:09.005117Z

I'm completely convinced that well organized queries should be as fast as hand written code

urbank 2017-03-06T13:28:01.005118Z

My top level component had a query which got all entity ids of entities with some attribute [:find ?eid :where [?eid :attr]]

urbank 2017-03-06T13:28:31.005119Z

this means that it had to rerun (according to posh) every time one of those entities changed

urbank 2017-03-06T13:29:15.005120Z

triggering a ton of subsequent pull queries ... so in retrospect I suppose it's no wonder it was slow ๐Ÿ˜…

qqq 2017-03-06T13:30:15.005121Z

The reason why I believe datascript can be faster in the generic case, is consdier todomvc where we want to filter on all "completed" tasks

qqq 2017-03-06T13:30:26.005122Z

in a simple store, we have to (1) run through all todo items (2) check if it's "completed"

qqq 2017-03-06T13:30:48.005123Z

in datascirpt, it's [:find ?eid :where [?eid :todo/status :completed]] and since there's an AVE index

qqq 2017-03-06T13:30:59.005124Z

this is equiv to (get-in AVE [:todo/status :completed])

mitchelkuijpers 2017-03-06T13:31:13.005125Z

Have you looked at union queries and the new routing in Untangled?

mitchelkuijpers 2017-03-06T13:31:33.005126Z

I can tell you from experience that datascript is way slooooower then the normal app-db format

qqq 2017-03-06T13:31:55.005127Z

how does union queries factor in when the fundamental issue is "data is indexed" vs "data is a list" ?

mitchelkuijpers 2017-03-06T13:32:49.005129Z

If you add the correct idents you also index your data

qqq 2017-03-06T13:33:18.005130Z

I seareched that page for "index" and got nothing

qqq 2017-03-06T13:33:21.005131Z

where does it talk about indexing?

qqq 2017-03-06T13:33:31.005132Z

I believe idents noramlize data, but that's very different from idnexing.

mitchelkuijpers 2017-03-06T13:34:16.005133Z

If you have a user, and you create an ident which is [:user/by-id 1] where you store the user info

mitchelkuijpers 2017-03-06T13:34:32.005134Z

Then I would say that is an index to get the user by id in your app-state

qqq 2017-03-06T13:35:05.005135Z

suppose for each user, you also stored their age

qqq 2017-03-06T13:35:12.005136Z

and I wanted "get me all users whose age is 25"

qqq 2017-03-06T13:35:21.005137Z

can you do that without running through the list of all users?

qqq 2017-03-06T13:35:27.005138Z

if not, I wouldn't call this indexing

mitchelkuijpers 2017-03-06T13:35:31.005139Z

Then I would think in a real use case you go to the server

qqq 2017-03-06T13:36:22.005140Z

I don't get what's "un"-real about the above scenario.

mitchelkuijpers 2017-03-06T13:37:12.005141Z

You'l probably want pagination and stuff on users unless you know there will never be more than 1000 for example

mitchelkuijpers 2017-03-06T13:38:32.005142Z

But I don't think you'll get much out of Untangled when you want to use Datascript

urbank 2017-03-06T13:41:16.005143Z

Hm... I think that things like 'get me all users whose age is 25' definitely happen on the client. Well, at least in my specific use case. The data I get from the server is very general, and I have to transform it in to various views

mitchelkuijpers 2017-03-06T13:43:07.005144Z

Ah for those cases we use post-mutations to build the right views for the same data. That is way to trigger a mutation after some data is loaded to create the right views for the data.

qqq 2017-03-06T13:43:50.005145Z

... or just use a db query ๐Ÿ™‚

mitchelkuijpers 2017-03-06T13:44:23.005146Z

Yes or use Datascript (but then lose all the benefits from Untangled)

urbank 2017-03-06T13:44:53.005147Z

Yeah, I'm still deciding between the two. But I don't think I understand untangled enough yet to make a call

qqq 2017-03-06T13:45:10.005148Z

Untangled is what got me into trying Om in the first place, but at this point, I'm in love with datascript and can't see what Untangled offers me over just using plain transit.

mitchelkuijpers 2017-03-06T13:47:52.005149Z

It offers you: getting data from the server, error handling, a lot plumbing, InitiallAppState goodies, Nice union query handling, A routing solution, Time traveling debugger, Testing tools, A generalized query solution, Server plumbing, i18n. You have to think if you need those things and if you are willing to build these yourself. And what do you do when you work with multiple developers and they have to use your homegrown framework.

qqq 2017-03-06T13:48:29.005150Z

I'm using google app engine datastore on server side

qqq 2017-03-06T13:48:39.005151Z

I'm using datascript on client side, and transit to communicate.

qqq 2017-03-06T13:49:04.005152Z

I don't see all the plumbing, InitialAppState, union query, routing ...

qqq 2017-03-06T13:49:15.005153Z

the replay debugger is nice, that I do miss

mitchelkuijpers 2017-03-06T13:50:24.005154Z

http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.F_Untangled_Initial_App_State this is the initial app-state (this is untangled not om.next)

mitchelkuijpers 2017-03-06T13:50:47.005155Z

http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.H_Server_Interactions and these are the server interactions from untangled

mitchelkuijpers 2017-03-06T13:51:11.005156Z

http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.I_Building_A_Server You have to create your own server and then add a om.next parser somewhere

qqq 2017-03-06T13:51:15.005157Z

I found that with transit/cljs-ajax this isn't nearly as big a deal as people claim to be.

qqq 2017-03-06T13:51:41.005158Z

That's what people to me -- and I figured out I don't ahve to use om.next on the server side, I can just transit /cljs-ajax ... and write to my gae datastore.

qqq 2017-03-06T13:52:17.005159Z

We should proably move to #off-topic

qqq 2017-03-06T13:52:36.005160Z

It's probably not very polite of me to be bashing untangled in#untangled

mitchelkuijpers 2017-03-06T13:53:40.005161Z

Yeah I was just trying to prove a point what Untangled fixes for you. I don't think you are bashing it. But I do want to make sure that you get what you are missing out on when you use om.next without untangled. (I started out with om.next and then later learned about untangled) ^^

qqq 2017-03-06T13:54:41.005162Z

I thikn untangled makes this assumption that "you have to build on top of om.next for client/server", and I'm now convinced: I can just use datascript for client, gae datastore for server, and cljs-ajax/transit really isn't all that bad for communication.

qqq 2017-03-06T13:55:10.005163Z

Also, om.next's query/db format seems very convoluted compared to datascript/datomic's eav store + datalog as query language.

mitchelkuijpers 2017-03-06T13:55:41.005164Z

I would not recommend that to be honest, but you are free to do what works best for you.

urbank 2017-03-06T14:04:29.005166Z

Anything in the above that would be a bad fit for untangled?

urbank 2017-03-06T14:07:44.005167Z

I'm not quite clear how much of that derived data should actually have some form in the database, or how to easily swap generic components.

mitchelkuijpers 2017-03-06T14:08:58.005168Z

This seems like a very good fit for untangled have you seen: http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.C_App_Database

urbank 2017-03-06T14:16:56.005170Z

@mitchelkuijpers Yes, but I have two unresolved questions. If there's no real structure to my data, would all the structure be given 'on the fly', with the component just getting a list of all the friends, or would some mutation create an entry in the database that would correspond to my example derived state.

urbank 2017-03-06T14:17:12.005171Z

The second question pertains to generic components. And I probably don't know the answer because I don't quite understand those.

urbank 2017-03-06T14:20:59.005174Z

If a multiselect is a generic component with a query [:ui-select/options]

urbank 2017-03-06T14:22:26.005175Z

how does that map onto the :friends-id list? Where it isn't actually a list anywhere, it's just derived from the fact that Tom has these 3 friends

mitchelkuijpers 2017-03-06T14:24:33.005177Z

Most Generic components don't have queries you probably don't need them for those. You can get the iinfo in a parent component and then give the generic component the :ui-select/options

mitchelkuijpers 2017-03-06T14:28:47.005178Z

And the structure in your app-db will be given by using idents. When you load data from the server it will normalize that based on your idents. http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.D_Queries there are some examples of idents in this devcard

urbank 2017-03-06T14:37:28.005179Z

I see. So I go to a different view of the flat data, would I create the structure on the fly, or create it in the app-db via some mutation? Also, in the untangled ui library, the calendar has a query, and Tony Kay indicated that this is useful for more complex components, because you can then affect them from anywhere in the app (click anywhere to hide some popup)

mitchelkuijpers 2017-03-06T14:39:37.005180Z

The idents get created by creating the right queries with components. Have you followed the Untangled tutorials?

urbank 2017-03-06T14:43:00.005181Z

I've seen the video tutorial, and read the untangled devguide where it pertains to the client-side. Maybe the relevant part went over my head. I'll definitely refer to it more.

mitchelkuijpers 2017-03-06T14:44:53.005182Z

No problem at all just keep asking, I would recommend to build a small POC. You will miss stuff when you are just following the tutorial or a video

urbank 2017-03-06T14:50:16.005183Z

Thanks! Yes I'm attempting a POC at the moment. Got stuck at generic components with queries, and merging their queries with something like an EditPerson component. EditPerson's query is composed into the Root query, and just specifies which attributes of a person to extract. So query: [:name :age :dark-secret]

urbank 2017-03-06T14:51:32.005184Z

So if :dark-secret needs to be edited by some DarkSecretEditor, and that component has its own query, how would it be composed into the EditPerson query

urbank 2017-03-06T14:52:13.005185Z

Since the data for generic components lives in top level tables (if I understand correctly)

urbank 2017-03-06T14:53:05.005186Z

would this be a use case for links? ( [:dark-secret-editor/by-id '_] )

urbank 2017-03-06T14:56:07.005189Z

what exactly would the DarkSecretEditor hold, since it's just editing the Person's :dark-secret?

urbank 2017-03-06T15:00:31.005190Z

Or more concretely, since the calendar queries for :day :month :year, this means that there's a calendar table in the app-db, which holds these 3 values

urbank 2017-03-06T15:01:00.005191Z

but what if these 3 values correspond to the birthday of some Person

urbank 2017-03-06T15:02:46.005192Z

so Person has a :birthday field which is at some point controlled by Calendar

urbank 2017-03-06T15:02:52.005193Z

how does this work?

mitchelkuijpers 2017-03-06T15:03:42.005194Z

I have never used the calendar component to be honest

mitchelkuijpers 2017-03-06T15:04:19.005195Z

Give me a second to see if I understand you correctly

mitchelkuijpers 2017-03-06T15:05:06.005196Z

Ah so the basic thing is you have a person and you want to change his birthday with the calendar component right?

mitchelkuijpers 2017-03-06T15:05:45.005197Z

But you want to change it when someone presses on save or submits a form, something along those lines am I correct?

mitchelkuijpers 2017-03-06T15:08:04.005198Z

you could have a {:dark-secret-editor {:who [:person/by-id 1] :form/state {:secret "foo"}}}

mitchelkuijpers 2017-03-06T15:08:45.005199Z

And when you change from which person you are editing you can change the :who and clear the :form/state

mitchelkuijpers 2017-03-06T15:09:05.005200Z

And if you want to save them you merge the form state into the [:person/by-id 1]

urbank 2017-03-06T15:09:09.005201Z

Oh, sorry I had to go somewhere for a moment. Yes, you understood correctly. It's an example though. Basically some generic component which has some state in the app-db is changing some other thing in the db

mitchelkuijpers 2017-03-06T15:10:26.005202Z

No problem, and your dark secret editor could have a query of [{:who [:secret]} {:form/state [:secret]}}]

mitchelkuijpers 2017-03-06T15:10:35.005203Z

Does this make sense?

urbank 2017-03-06T15:12:41.005204Z

Right, that makes a lot of sense!

urbank 2017-03-06T15:13:21.005205Z

And to make some more generic component (such as a calendar), which doesn't have a reference to what it's editing, you would just wrap it into another component that holds the reference, and the calendar's state?

mitchelkuijpers 2017-03-06T15:14:01.005207Z

Yes, that is exactly what I would do

mitchelkuijpers 2017-03-06T15:14:23.005208Z

I think you get it!

urbank 2017-03-06T15:17:48.005209Z

Great, each time I pop over here and ask some questions it gets clearer. ๐Ÿ™‚ Thanks very much for the help and your time!

mitchelkuijpers 2017-03-06T15:20:54.005211Z

No problem!

tony.kay 2017-03-06T16:11:20.005212Z

@qqq if you want to use Datascript, Untangled is not for you. Agreed.

gardnervickers 2017-03-06T16:22:13.005213Z

Iโ€™m doing a data-fetch/load using an ident with the target being that same ident. Putting a watch on the state atom and observing the state transitions for the entity under the ident, I see it correctly change to a load marker, then nil, then the loaded state, but then itโ€™s set back to nil again.

gardnervickers 2017-03-06T16:22:55.005214Z

If anyone has any hints for where to look to resolve that, it would be appreciated. Iโ€™m not super familiar with the load marker lifecycle.

tony.kay 2017-03-06T16:23:41.005215Z

So, target was really meant to target the insides of a node, not a top-level table entry. The query itself does that.

tony.kay 2017-03-06T16:24:11.005216Z

I'm guessing you're using a link query and want a load marker as well?

tony.kay 2017-03-06T16:24:34.005217Z

E.g. some component is doing a query of a specific table entry that you want to load dynamically?

gardnervickers 2017-03-06T16:25:46.005218Z

We have a parent component that is trying to dynamically load a child by id.

tony.kay 2017-03-06T16:26:05.005219Z

ok, so do it this way:

tony.kay 2017-03-06T16:26:36.005220Z

1. In the parent's query, add some made-up keyword that points to the correct type: [{:the-child (om/get-query Child)}]

tony.kay 2017-03-06T16:26:50.005221Z

2. Make sure the parent has an ident, so you know where it is

tony.kay 2017-03-06T16:27:53.005222Z

3. Run a load with query params: (load [:child/by-id 42] Child {:target [:parent/by-id parent-id :the-child]})

tony.kay 2017-03-06T16:28:08.005223Z

I think that should work

gardnervickers 2017-03-06T16:28:54.005224Z

Should :target place the ident of the loaded data at the :target location?

tony.kay 2017-03-06T16:29:05.005225Z

yes, that is what it is for

tony.kay 2017-03-06T16:29:13.005226Z

normalization still applies

tony.kay 2017-03-06T16:29:58.005227Z

(load-field this :the-child) is also a nice shortcut for this use-case, though then your server has to understand a query based on the parent's ident

tony.kay 2017-03-06T16:30:31.005228Z

(e.g. what you'll get on the server is [{[:parent/by-id parent-id] [{:the-child (om/get-query Child)}]}]

gardnervickers 2017-03-06T16:31:03.005230Z

load-field works well for us, however Iโ€™m not seeing df/load getting the ident of the loaded data and placing it at :target

tony.kay 2017-03-06T16:31:47.005231Z

It is possible the ident-based load case has a bug. I was pretty sure it was tested in the cookbook load-samples, though

tony.kay 2017-03-06T16:32:01.005232Z

could be wrong. Lots of combinations are possible

tony.kay 2017-03-06T16:32:49.005233Z

It could be I only tested something like reloads, and never worked out the logic for an ident-based load that needed edge fixes in the graph

gardnervickers 2017-03-06T16:32:52.005234Z

Ok great, Iโ€™ll start there.

gardnervickers 2017-03-06T16:32:58.005235Z

Thanks!

tony.kay 2017-03-06T16:33:27.005236Z

If you're seeing a problem on ident-based load, don't assume it is you.

tony.kay 2017-03-06T16:35:10.005237Z

the load marker logic might not be right for that case

gardnervickers 2017-03-06T16:39:07.005238Z

Ah, looks like when default-target here is an ident, itโ€™s wrapped in another vector. Then we do get-in @state-atom default-target where default-target is [[component/by-id <id>]] which is nested too deep.

gardnervickers 2017-03-06T17:01:45.005240Z

Here I conditionally wrap the return from data-query-key in a vector, covering the case where the query key is an ident instead of a keyword. https://github.com/untangled-web/untangled-client/pull/65

fz 2017-03-06T17:14:46.005242Z

๐Ÿ‘‹ Hello! I'm trying to wrap my head around queries and database structure

fz 2017-03-06T17:15:01.005243Z

In the Person/`PeopleWidget`/`Root` example here http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.E_UI_Queries_and_State

fz 2017-03-06T17:15:49.005244Z

The Root has a query which evaluates to [{:people [:people/name]}]. That makes sense, given the database below it where :people is a vector of "person" maps.

fz 2017-03-06T17:16:53.005245Z

What if I wanted :people to be an "Ident-able" table? Instead of {:people [{:id 1 โ€ฆ} {:id 2 โ€ฆ}]}, I'd have {:people { 1 {:id 1 โ€ฆ} 2 {:id 2 }}

fz 2017-03-06T17:17:11.005246Z

Then the [{:people [:people/name]}] join would break

fz 2017-03-06T17:17:55.005247Z

I'd like to get the same result as I'd get in the example, but also have :people be a "table" that can be accessed via Idents. Is that possible?

gardnervickers 2017-03-06T17:20:25.005248Z

If youโ€™re normalizing the โ€œpersonโ€ maps, youโ€™d have a top-level key in your app-db that is something like :person/by-id.

gardnervickers 2017-03-06T17:21:03.005249Z

Then you could query [:person/by-id] to get the raw table back.

fz 2017-03-06T17:23:39.005253Z

So the app db would look like

{:people { 1 {:id 1 โ€ฆ} 2 {:id 2 โ€ฆ } }
 :person/by-id [{:id 1 โ€ฆ} {:id 2 โ€ฆ}]}
Or if not, what data would go under the :person/by-id key?

gardnervickers 2017-03-06T17:25:51.005254Z

The app-db would look like this

{:person/by-id {1 {:id 1} 2 {:id 2}}
 :people [[:person/by-id 1] [:person/by-id 2]]}

๐Ÿ‘ 1
gardnervickers 2017-03-06T17:27:57.005256Z

identโ€™s are resolved using get-in, so if you have an ident that is [:person/by-id 1] there must be a :person/by-id top level key in your app-db, with itโ€™s value being a map containing the key 1. The ident would then resolve to the value of the key 1.

fz 2017-03-06T17:29:20.005257Z

If I wanted to set that up in initial-state, I presume I would do that on the Root component. Would I have to manually specify both the :person and :person/by-id values? I'm pretty sure there's a way to not have to manually keep the two sets of data in sync, but not clear how that works

darrellesh 2017-03-06T17:34:00.005258Z

@tony.kay Is it possible to add a filtered-list-input to the possible input types supported with Forms. It would be nice to allow the user to key in a value and have the filtered list filter the results to the value entered and if there was no match in the filtered list then the input value would be the value persisted. Otherwise, the the id of the value which matches the filtered list item would be persisted?

tony.kay 2017-03-06T17:34:36.005259Z

Any kind of form field you can imagine it easily added to form support

tony.kay 2017-03-06T17:34:58.005260Z

how you render it is up to you, and how you interact with it is also up to you

tony.kay 2017-03-06T17:36:19.005261Z

All forms care about is that you've declared some field of the entity to be form data. If it isn't a subform, you could render an alternate control (e.g. your filtered list) and use callbacks to populate the field.

tony.kay 2017-03-06T17:36:31.005262Z

The "field" in this case is just a prop on your entity. Nothing special about it at all

darrellesh 2017-03-06T17:37:18.005263Z

Right. That makes sense. I will render a filtered list but the text input would be under form support.

tony.kay 2017-03-06T17:37:27.005264Z

Say you wanted to use the ui-calendar component to edit a date. The calendar itself has a query and mutations, and a callback. In that case you'd compose the calendar into your "form" and use the callback to update the date.

tony.kay 2017-03-06T17:37:51.005265Z

The form support itself is about state management, with some nice add-ins for common cases.

tony.kay 2017-03-06T17:41:13.005266Z

@gardnervickers Ah, so you're saying when you use an explicit target that is an ident, we get the wrong thing.

gardnervickers 2017-03-06T17:41:32.005267Z

Actually no sorry

tony.kay 2017-03-06T17:42:01.005269Z

I see the problem. I'm a little concerned about the solution. I'm still not convinced we should be "targeting" something that will already normalize to the correct place.

tony.kay 2017-03-06T17:42:17.005270Z

I.e. relocate? should be false on an ident-based load

gardnervickers 2017-03-06T17:43:10.005272Z

I misread the question. When Iโ€™m using a path like you suggested above, but loading from an ident, the default-target ends up being [[<ident>]] instead of [<ident>]

gardnervickers 2017-03-06T17:43:36.005273Z

So (get-in state [[<ident>]]) always is going to be nil.

tony.kay 2017-03-06T17:43:36.005274Z

right, but an ident load should not be "targeted"

tony.kay 2017-03-06T17:43:58.005275Z

so the swap! should not go in that case, and you are right, it is going an screwing things up

gardnervickers 2017-03-06T17:44:00.005276Z

I thought you were suggesting this above (load [:child/by-id 42] Child {:target [:parent/by-id parent-id :the-child]})

tony.kay 2017-03-06T17:44:38.005277Z

OH. Right

tony.kay 2017-03-06T17:44:40.005278Z

I see.

tony.kay 2017-03-06T17:45:54.005279Z

still, isn't the right fix, since the dissoc should not run. Relocate is meant to move idents, not objects...you don't want to dissoc, though I guess it wouldn't hurt, since there is no dissoc-in

tony.kay 2017-03-06T17:46:48.005280Z

I think this would be clearer, perhaps, as a cond that enumerates the cases.

gardnervickers 2017-03-06T17:49:03.005281Z

Why dissoc ever? Wouldnโ€™t you just want to overwrite the load-marker with the value in every case?

tony.kay 2017-03-06T17:49:18.005282Z

dissoc is about loading into the root. It is simply a cleanup

tony.kay 2017-03-06T17:49:37.005283Z

(load :my-thing Comp) adds a key to the app db :my-thing

tony.kay 2017-03-06T17:49:50.005284Z

but you wanted the value to be elsewhere, so we don't leave it around.

gardnervickers 2017-03-06T17:50:04.005285Z

Ah gotcha

gardnervickers 2017-03-06T17:50:43.005286Z

and it works for me because (dissoc state [:thing/by-id <id>]) does not do anything since the ident is a path into app state, not a key.

tony.kay 2017-03-06T17:50:53.005287Z

Yeah, loading a list of things, etc. Nice to send an abstract name of the query to the server, like (load :all-things Thing {:target [:thing/holder :things]})

tony.kay 2017-03-06T17:51:02.005288Z

right

tony.kay 2017-03-06T17:51:22.005289Z

doesn't hurt, but the code is already more opaque than I'd like

tony.kay 2017-03-06T17:51:33.005290Z

so a no-op dissoc makes it worse

gardnervickers 2017-03-06T17:51:39.005291Z

Yea agreed

tony.kay 2017-03-06T17:54:19.005292Z

Did you verify that this does not break any tests?

gardnervickers 2017-03-06T17:54:40.005293Z

Yup, I ran the firefox suite in addition to the lein tests.

tony.kay 2017-03-06T17:56:27.005294Z

ok, I'm not going to worry about the dissoc for now. I'm doing a refactor, so I'll do some cleanup around this in a bit.

gardnervickers 2017-03-06T17:56:41.005295Z

Fantastic, thanks for your help.

tony.kay 2017-03-06T17:57:22.005296Z

on 0.8.1-SNAPSHOT on clojars

tony.kay 2017-03-06T17:57:34.005297Z

be sure to upgrade Om to alpha48 and also latest cljs

gardnervickers 2017-03-06T17:57:40.005298Z

Ok thanks

tony.kay 2017-03-06T17:57:54.005299Z

you can be a test subject for the new network stack ๐Ÿ˜‰

gardnervickers 2017-03-06T18:11:46.005300Z

This is likely problematic as well for the ident case https://github.com/untangled-web/untangled-client/blob/develop/src/untangled/client/impl/data_fetch.cljc#L311

gardnervickers 2017-03-06T18:12:15.005301Z

Specifically for the loaded-callback during the remove-markers step.

tony.kay 2017-03-06T18:13:02.005302Z

agreed

tony.kay 2017-03-06T18:13:15.005303Z

I thought we patched that the other day

tony.kay 2017-03-06T18:14:17.005304Z

weird...did we talk about that one???

gardnervickers 2017-03-06T18:16:58.005306Z

Yes but that fix didnโ€™t actually work, probably because of the issue we addressed today.

gardnervickers 2017-03-06T18:23:16.005307Z

Ahhh I see what you were saying. When data-query-key is an ident, we donโ€™t want to (get-in st (data-query-key ...)) and relocate that because thatโ€™ll relocate the value, not the ident.

tony.kay 2017-03-06T18:24:07.005308Z

yep

gardnervickers 2017-03-06T18:42:09.005309Z

PR to set the data-path correctly for when a query is going off an ident, and retargeting loads to move the ident instead of the actual value. https://github.com/untangled-web/untangled-client/pull/66

gardnervickers 2017-03-06T18:42:25.005310Z

Firefox + lein tests pass for me.

tony.kay 2017-03-06T18:45:22.005311Z

couple of quick feedbacks

tony.kay 2017-03-06T18:45:32.005312Z

via github

gardnervickers 2017-03-06T18:54:49.005313Z

Hmm not seeing those on the PR

tony.kay 2017-03-06T18:55:07.005314Z

forgot to submit

tony.kay 2017-03-06T18:55:08.005315Z

sorry

tony.kay 2017-03-06T19:25:39.005326Z

@gardnervickers So, on load markers. I think we need to do a bit of refactoring, actually, and specify exactly what the behavior should be in all cases. There are not that many, and I'd like this to be cleaner

gardnervickers 2017-03-06T19:25:49.005327Z

@tony.kay Thanks, fixed up the PR a bit.

gardnervickers 2017-03-06T19:25:51.005328Z

Ok sounds good

tony.kay 2017-03-06T19:25:52.005329Z

and more testable

tony.kay 2017-03-06T19:27:17.005330Z

Seems there are the following cases: 1. Loading an entity by ident. We could place the data-fetch marker on an existing entity, if present (since it is a map). We could potentially generate said placeholder, but then the ident problem (nil id) is concerning. I guess we could derive the ID of the object from the query, but not the key. That would require some additional parameter on the load, which I'm a little loathe to add.

gardnervickers 2017-03-06T19:28:08.005332Z

Loading by ident gives you the id though right?

tony.kay 2017-03-06T19:28:19.005333Z

yeah, but we don't know what key it goes with

gardnervickers 2017-03-06T19:28:25.005334Z

Ahhh yup.

tony.kay 2017-03-06T19:28:55.005335Z

but this is only a problem if you're using link queries

tony.kay 2017-03-06T19:29:06.005336Z

(e.g. pulling the thing into some arbitrary component by ident)

tony.kay 2017-03-06T19:29:30.005337Z

In 99% of good cases, you'd link the graph together and have a real UI component pointing to the loaded thing

gardnervickers 2017-03-06T19:29:40.005338Z

The queries like [:toplevel/key โ€˜_]?

tony.kay 2017-03-06T19:29:44.005339Z

in which case :target would be some prop on another obj

tony.kay 2017-03-06T19:29:46.005340Z

Yes

tony.kay 2017-03-06T19:29:54.005341Z

well

tony.kay 2017-03-06T19:30:14.005342Z

[{[:obj 3] [:a :b]}]

tony.kay 2017-03-06T19:30:28.005343Z

which you can do, but I would not recommend it

tony.kay 2017-03-06T19:30:39.005344Z

I mean, you'd need dynamcic queries

tony.kay 2017-03-06T19:30:44.005345Z

and the headaches that go with those

tony.kay 2017-03-06T19:31:09.005346Z

So, in that case we never want to put a load marker in a table. I think we just make that a rule.

tony.kay 2017-03-06T19:31:26.005347Z

you have to do your own marker if that's what you need

gardnervickers 2017-03-06T19:31:50.005348Z

Oh I didnโ€™t even know the client side parser supported that format of query.

tony.kay 2017-03-06T19:32:38.005349Z

sure, works fine. As do dynamic queries. Standard Om fare, and we use db->tree from Om for reads, so it all works. Parameters are the thing you cannot use, but not because the syntax doesn't work

tony.kay 2017-03-06T19:32:54.005350Z

just because we give you no hook to process them. Forced trade-off

tony.kay 2017-03-06T19:33:09.005351Z

Write no read parser, get no client-side query params...but not in the dyn query sense

tony.kay 2017-03-06T19:33:28.005353Z

ug. terminology

tony.kay 2017-03-06T19:33:52.005354Z

[{:a ?subquery}] actually works in Untangled

tony.kay 2017-03-06T19:34:17.005355Z

but [{(:a {:p 1})}] ignores the param

tony.kay 2017-03-06T19:34:30.005356Z

and just reads prop :a

tony.kay 2017-03-06T19:34:53.005357Z

the prior is a "query param", and the latter is a "parameter on a property in a query" (or query param for short ๐Ÿ˜œ )

tony.kay 2017-03-06T19:35:59.005359Z

You can have a remote send the latter by messing with the AST in your mutation (common)...server can use them just fine

tony.kay 2017-03-06T19:36:02.005360Z

ANYHOW

tony.kay 2017-03-06T19:36:10.005361Z

back to the cases

tony.kay 2017-03-06T19:36:27.005362Z

1. Loading via ident. If you give a target, that is where the load marker goes, else you don't get one.

tony.kay 2017-03-06T19:36:43.005363Z

2. Loading via top-level key: load marker goes on top-level key. Again, all ok

tony.kay 2017-03-06T19:37:05.005364Z

3. Loading via top-level key with target: marker goes at target

tony.kay 2017-03-06T19:37:09.005365Z

am I missing any?

gardnervickers 2017-03-06T19:37:21.005366Z

Does #2 get a marker if target is not specified?

tony.kay 2017-03-06T19:37:34.005367Z

well, load-field is a utility auto-generates a query based on the parent's ident to populate a sub-field. So, it is technically (1), but with a query focused on the field.

tony.kay 2017-03-06T19:37:53.005368Z

yes, 2 is ok, since it isn't a table, just a root graph edge

gardnervickers 2017-03-06T19:39:29.005373Z

So load-field on [:something/by-id 5] on :field :foo puts itโ€™s load marker where in app state?

gardnervickers 2017-03-06T19:39:45.005375Z

at [:something/by-id 5 :foo]?

tony.kay 2017-03-06T19:40:09.005378Z

sorry

tony.kay 2017-03-06T19:40:14.005379Z

I know I confused you there

tony.kay 2017-03-06T19:40:18.005380Z

I was trying to remember

tony.kay 2017-03-06T19:40:41.005381Z

(load-field this :comments): The :comments are on a subfield of this

tony.kay 2017-03-06T19:41:47.005382Z

so, the query is [{ (om/ident this) (focus-the-query-of this :comments) }] The load marker shows up on the :comments field of whatever object "this" is

tony.kay 2017-03-06T19:42:07.005383Z

For load-field, you're loading some additional bit of something you already have

tony.kay 2017-03-06T19:42:12.005384Z

like a blog post

tony.kay 2017-03-06T19:42:26.005385Z

but you only want to load some focused bit of it

tony.kay 2017-03-06T19:42:55.005386Z

[{[:blog-post 3] [{:comments (om/get-query Comment)}]}]

gardnervickers 2017-03-06T19:42:59.005387Z

But for that case, this could be an ident which resolves to a table entry, which we end up sticking a load marker into for :comments. Or does the โ€œno load marker in a tableโ€ rule only apply to load markers being top-level elements in a table.

tony.kay 2017-03-06T19:43:14.005388Z

no load marker as an entry in the table

gardnervickers 2017-03-06T19:43:19.005389Z

Gotcha

tony.kay 2017-03-06T19:43:22.005390Z

everything is in a table in a normalized database ๐Ÿ˜‰

tony.kay 2017-03-06T19:43:39.005391Z

except for the root edges, and those are keys -> idents

tony.kay 2017-03-06T19:43:53.005392Z

and any scalar values you plop in the "root node"

tony.kay 2017-03-06T19:44:03.005393Z

like :ui/react-key

tony.kay 2017-03-06T19:46:27.005394Z

Oh, I guess the load-field case is a special one...since the load marker goes one level deeper than the others

tony.kay 2017-03-06T19:47:29.005395Z

the ident we're using is not technically the thing we're loading...or should it be?

tony.kay 2017-03-06T19:48:53.005396Z

conceptually, we're loading one or more of some children, so I've typically thought of that as loading the children. But you could also think of it as loading the "remainder" of the thing you've got.

tony.kay 2017-03-06T19:49:30.005397Z

I think it is this use-case that makes most of the logic a mess ๐Ÿ˜•

tony.kay 2017-03-06T19:49:50.005398Z

it's a really useful one, though

tony.kay 2017-03-06T19:50:04.005399Z

and the one that motivated load markers to begin with

gardnervickers 2017-03-06T19:52:00.005400Z

Yea, we most often have an entity partially loaded and want to load the rest of it. For example, when doing initial page load with a blank app-db, we can gather at least the desired entity id from the URL fragment. This gives us the entity id which we can run a mutation and put in our app-db.

gardnervickers 2017-03-06T19:52:15.005401Z

Then we try and load the โ€œremainderโ€ of the entity with load.

tony.kay 2017-03-06T19:53:00.005404Z

so you're treating it like a "refresh"

tony.kay 2017-03-06T19:53:05.005405Z

instead of an initial load

gardnervickers 2017-03-06T19:53:23.005407Z

Yes, for the ident load case.

gardnervickers 2017-03-06T19:53:40.005408Z

For every other case, we want a list of things so we use a server property.

gardnervickers 2017-03-06T19:53:59.005409Z

So itโ€™s either loading [:user/by-id <id>] or :users/list-of.

tony.kay 2017-03-06T19:54:27.005410Z

and your UI is querying via a link query?

tony.kay 2017-03-06T19:54:47.005411Z

or do you have some component that has [{:current-user (om/get-query User)}]

gardnervickers 2017-03-06T19:55:00.005412Z

[{:current-user (om/get-query User)}]

tony.kay 2017-03-06T19:55:09.005413Z

ok, so that is your target ๐Ÿ˜‰

gardnervickers 2017-03-06T19:55:18.005414Z

Yup!

gardnervickers 2017-03-06T19:56:23.005415Z

But weโ€™re still hitting the server with the query [{[:user/by-id <id>] (om/get-query User)}]

tony.kay 2017-03-06T19:56:26.005416Z

You could even use load-field with that...it supports :params

tony.kay 2017-03-06T19:57:37.005417Z

(load-field thing-with-current-user-prop :current-user :params { :user-id 5 })

gardnervickers 2017-03-06T19:57:43.005418Z

And pass it the subquery as params?

tony.kay 2017-03-06T19:58:19.005419Z

would send the query [({:current-user [props of user]} {:user-id 5})], and your server parser would see the params

tony.kay 2017-03-06T19:58:34.005420Z

in the read keyed on :current-user

tony.kay 2017-03-06T19:58:55.005421Z

oh wait

tony.kay 2017-03-06T19:59:00.005422Z

there's another join in there

tony.kay 2017-03-06T19:59:14.005423Z

so load-field might not be best

tony.kay 2017-03-06T19:59:21.005424Z

since it would have the parent component composed in

tony.kay 2017-03-06T20:00:28.005425Z

(load this :user User {:target [:parent :comp :current-user] :params {:id 5 }})

tony.kay 2017-03-06T20:01:09.005426Z

where :user is now the join key the server sees. Just have to make sure it doesn't collide with any state of interest already in the root of app db

tony.kay 2017-03-06T20:01:41.005427Z

and params can be used to pass the ID of interest

tony.kay 2017-03-06T20:01:47.005428Z

now you'll get the load marker as you want it

gardnervickers 2017-03-06T20:01:57.005429Z

Thatโ€™s what we were doing originally

tony.kay 2017-03-06T20:02:14.005430Z

why changed? Hopefully not because I told you ๐Ÿ˜œ

gardnervickers 2017-03-06T20:03:16.005431Z

Seeing the ident support in df/load made more sense. That way it was just (df/load this (om/ident this) (om/react-class this)) for refreshes

tony.kay 2017-03-06T20:03:38.005433Z

Ah, I see

tony.kay 2017-03-06T20:04:02.005434Z

so, I would be OK with putting in a load marker IFF the entity already looks to be in your db

tony.kay 2017-03-06T20:04:18.005435Z

and in your case this would work, since you're pre-populating with something that looks like it

tony.kay 2017-03-06T20:05:30.005436Z

actually, (df/refresh this) sounds like a nice util function with just that signature

tony.kay 2017-03-06T20:07:43.005438Z

OK, so I'm going to re-enumerate the cases:

tony.kay 2017-03-06T20:12:53.005439Z

1. Loading a field is a special case. Load marker goes in field of parent, and that parent's ident is what is used for the query. 2. Load via top-level key: Load marker goes at key (or target if specified) 3. Loading via ident: Understands that we're loading or refreshing an entry in a table. If there is already a map in the table, put the load marker on the object already in the table (and the graph will resolve it for the UI). Target is always ignored for this case. Do a post-mutation if you need to integrate the ident into app state. (or a pre-mutation if you want to see load markers for newly loading objects).

gardnervickers 2017-03-06T20:28:35.005440Z

Perfect

gardnervickers 2017-03-06T20:29:26.005441Z

#3 works extremely well for us.

tony.kay 2017-03-06T20:29:47.005442Z

k. patching that now

2017-03-06T21:15:11.005443Z

I've found a strange behaviour change between untangled client 0.7.0 and 0.8.0 To do a login I'm using a google login that is checked on the server and then saving a jwt sent from the server in a cookie. I then do follow on reads in the transaction to set/check the client app state to show login and current user - my transaction looks like this:

#(om/transact! this
      `[(login/attempt {:jwt ~(om/tempid) :id_token ~(-> % .getAuthResponse .-id_token)})
        (untangled/load {:query [:login-sequence] ;; this is a dummy query to sequence the post-mutation
                         :post-mutation login/set-cookie})
        (untangled/load {:query [:logged-in? :current-user]
                         :post-mutation login/complete})])
I can see the cookie being set using goog.net.cookies and the correct value returned from the server in the app state from the om/tempid handling. The problem is that the last untangled/load call does not provide the cookie in the request using v0.8.0 whereas they did in v0.7.0. This is visible in the request headers in the browser network inspector.

tony.kay 2017-03-06T21:16:22.005444Z

So, you're indicating that post-mutation did not run?

2017-03-06T21:18:11.005445Z

The login/set-cookie post-mutation does run and the cookie is set, it appears like the next remote load (from the last untangled/load doesn't contain the cookie).

tony.kay 2017-03-06T21:18:42.005447Z

oh, are you expecting the cookie to be set between these two calls?

2017-03-06T21:19:22.005448Z

Yes - is that not the expected behaviour?

tony.kay 2017-03-06T21:19:49.005449Z

hm. well, mutations go before reads, so your attempt will happen on a separate network request

tony.kay 2017-03-06T21:20:08.005450Z

Then the loads are ganged together in a separate request (they go together on the net)

tony.kay 2017-03-06T21:21:21.005451Z

I'm not sure why anything that changed would have affected something like this if it was already working ๐Ÿ˜•

tony.kay 2017-03-06T21:22:57.005452Z

so , I would not have expected what you wrote to work because the post mutations always go after the queries have run, and both go at the same time...

tony.kay 2017-03-06T21:23:13.005453Z

so no, I would never have expected that to work as described.

tony.kay 2017-03-06T21:23:51.005454Z

reads have been combined since day one

tony.kay 2017-03-06T21:25:20.005455Z

Can you have login/attempt set the cookie?

2017-03-06T21:26:10.005456Z

I'll try that

tony.kay 2017-03-06T21:26:29.005457Z

attempt is a remote mutation, right?

tony.kay 2017-03-06T21:26:51.005458Z

and you have the value you need before it runs, or no?

tony.kay 2017-03-06T21:29:30.005459Z

if no, then you could install a mutation-merge function at startup, and capture the attempt merge to handle a return value

2017-03-06T21:30:39.005460Z

attempt is a remote read, and I generate my own jwt token on the server which is then placed in the app-state (using temp-id) hence the dummy read - I was attempting to follow the pattern at the bottom of M40 in the devguide

2017-03-06T21:30:52.005461Z

sorry mutation not read

tony.kay 2017-03-06T21:32:53.005462Z

I see. OK. So bullet 3, essentially.

2017-03-06T21:34:21.005463Z

yes

tony.kay 2017-03-06T21:38:56.005464Z

So, in a single transaction, the reads will go over the network together, and the post mutations will run (after they've returned)

tony.kay 2017-03-06T21:39:17.005465Z

so it should have never worked to expect the last load to have the cookie if the cookie was set in the middle one

tony.kay 2017-03-06T21:40:26.005466Z

The example you point to: The assumptions is that you already know who the user is. If the remap came from the server. Otherwise the server should throw an exception which will kill the transaction on the client.

2017-03-06T21:44:33.005467Z

Ah, okay good to know about the ordering, I'll see if I can get something different to work

tony.kay 2017-03-06T21:45:36.005468Z

clarification: the assumptions is you know what the user told you about themselves. The login mutation is trying to verify that (and using a tempid as a way to get a response).

tony.kay 2017-03-06T21:45:57.005469Z

If you refuse to remap on the server, the the client will still have a tempid, which you could use to detect that something went wrong

tony.kay 2017-03-06T21:46:33.005470Z

If you need identity info from the server after doing the login sequence (and that requires a cookie), then I'd probably use a mutation-merge and just return the info from the login

tony.kay 2017-03-06T21:47:15.005471Z

The tempid remap WILL happen before the post mutations on the reads

2017-03-06T22:30:10.005472Z

looking a bit further, I'm just trying to understand the ordering of things that happend with :post-mutation - I've setup a simple test case like this:

#(om/transact! this `[(untangled/load {:query [:something]
                                       :post-mutation test/pm1})
                      (untangled/load {:query [:something]
                                       :post-mutation test/pm2})
                      (untangled/load {:query [:something]
                                       :post-mutation test/pm3})])
Where test/pm1,test/pm2,test/pm3 just output a string to client consolt (pm1, pm2, pm3) - should I expect the output to be 'pm1','pm2','pm3' or is the ordering undefined?

tony.kay 2017-03-06T22:44:33.005473Z

the order should be preserved

tony.kay 2017-03-06T22:44:56.005474Z

but realize that the loads ALL run the networking part, and THEN run all 3 post mutations

tony.kay 2017-03-06T22:45:03.005475Z

the networking is done before the first post mutation

tony.kay 2017-03-06T22:45:51.005476Z

actually, you could confuse yourself with this particular example, since they all have the same query

tony.kay 2017-03-06T22:46:00.005477Z

This is a special case

tony.kay 2017-03-06T22:46:54.005478Z

The return value from the server has to be a map, and :something can only appear once in such a map, so Untangled should actually do these in perfect sequence as you were thinking (it must serialize them because otherwise they'd stomp on each others return values)

tony.kay 2017-03-06T22:47:13.005479Z

change the queries to :a :b and :c, and you should only see one network requext

tony.kay 2017-03-06T22:47:52.005482Z

@tobias ^^^

tony.kay 2017-03-06T22:50:02.005483Z

@gardnervickers So, I've got a patch. I think this is right: :target really only applies on queries that load into the top-level (root)

tony.kay 2017-03-06T22:50:11.005484Z

which simplified a bit of logic

tony.kay 2017-03-06T22:50:52.005485Z

I added tests, and updated the relocation and marking code. I have not tested it on a live app, but I can push a snapshot

tony.kay 2017-03-06T22:51:05.005486Z

I'll test live against that and would love to hear back from you

tony.kay 2017-03-06T22:52:58.005487Z

0.8.1-SNAPSHOT on clojars. Testing for regressions against cookbook.

gardnervickers 2017-03-06T22:53:19.005488Z

@tony.kay Fantastic, Iโ€™ll check that out on our app tonight.

2017-03-06T22:57:38.005490Z

Okay, I now understand the network stuff and the way it's batched I think, the strange thing is that in 0.7.0 I see pm1,pm2,pm3 and in 0.8.0 I see pm3,pm2,pm1 - even with seperate queries BUT, I think I'm realising that in practice with the correct usage that this won't make a difference to the final outcome of the transaction

tony.kay 2017-03-06T23:10:11.005491Z

Yeah, I was not aware the order changed. I did rework a bit on the network stack.

tony.kay 2017-03-06T23:10:34.005492Z

I cannot think of what I did that would have revered them

tony.kay 2017-03-06T23:11:18.005493Z

is that with out without the conflicts in naming?

2017-03-06T23:13:03.005494Z

yes, reversed when the names are not conflicting

tony.kay 2017-03-06T23:21:48.005495Z

hm, but not in 0.7.0, eh?

tony.kay 2017-03-06T23:22:02.005496Z

it shouldn't matter, but I don't personally like things like that changing

tony.kay 2017-03-06T23:22:13.005497Z

vectors imply order

tony.kay 2017-03-06T23:22:43.005498Z

@gardnervickers It seems to check out for me. I also added a df/refresh! function for your specific case

2017-03-06T23:23:42.005499Z

I'll run through the diffs and see if I can find anything

tony.kay 2017-03-06T23:29:15.005500Z

could be in mark-loading

tony.kay 2017-03-06T23:29:20.005501Z

I had to revamp that for the multiple remotes

tony.kay 2017-03-06T23:31:39.005502Z

I you look at the actual network request, is it in the right order?

tony.kay 2017-03-06T23:31:54.005503Z

i.e. is it just running the mutations in some arbitrary order?

tony.kay 2017-03-06T23:32:09.005504Z

because the post-mutations will run in whatever order the responses are seen in, and the response is a map

tony.kay 2017-03-06T23:32:15.005505Z

Your server code can affect that

tony.kay 2017-03-06T23:32:39.005506Z

the post mutations go with the query. I don't think I changed anything. I think your response is causing the order of the post mutations

tony.kay 2017-03-06T23:33:30.005507Z

@tobias ^^^

2017-03-06T23:44:08.005508Z

@tony.kay git bisect says this is the first commit where it changes - bbae5ea568291c8589bf6dcae55863565b739a95 - Added support for multiple remotes - Updated defmutation to allow definition of multiple remotes interactions I don't have anything but a print on the server side, it's the ordering of the sends from the client that is being reversed

tony.kay 2017-03-06T23:44:39.005509Z

thanks for doing the research. I'll look at it

tony.kay 2017-03-06T23:53:53.005510Z

well, the item filtering down end up using a set, which doesnt have guaranteed order

tony.kay 2017-03-06T23:53:58.005511Z

but that was how it was before

tony.kay 2017-03-06T23:54:59.005512Z

the hashes of the data items could have changed, which would cause the set to reorder

tony.kay 2017-03-06T23:55:14.005513Z

the data item markers in load tracking, that is

tony.kay 2017-03-06T23:55:17.005514Z

which they would have

tony.kay 2017-03-06T23:55:53.005515Z

So, technically this "broke" some time ago when the query collision avoidance was added