Fork me on GitHub
#om
<
2015-11-13
>
jannis00:11:41

Hrm. There must be something very wrong here. This works fine:

app.reconciler=> (cognitect.transit/read (om.transit/reader) "[\"~#om/id\",\"~u9fff7aad-e336-4d21-a582-86cc133b0ddd\"]")
<#C06DT2YSY>/id["9fff7aad-e336-4d21-a582-86cc133b0ddd"]
But this doesn't:
app.reconciler=> (ajax.core/POST "" {:params (om.next/tempid) :reader (om.transit/reader) :writer (om.transit/writer) :handler #(println % (type %))})
#object[Object [object Object]]
The server returns application/transit+json and the body of the response is ["~#om/id","~ua4477301-123c-4fe0-b4dd-233749caaa2d"]. I suspect cljs-ajax is messing with the response body in a way that confuses transit/read...

jannis00:11:32

Nevermind. Passing :response-format :transit to POST did the trick... so this took me over an hour.

leontalbot00:11:44

Don't forget to sleep @jannis ;-)

jannis00:11:20

@leontalbot: Aww, thanks simple_smile You're right

denik01:11:27

When I use om/computed componentDidUpdate is called twice. First with om/props or prev-props having the correct props and then again with {:om.next/computed {...}}. Why is that?

dnolen02:11:39

Did you try without computed to verify it actually has anything to do with that?

denik02:11:39

yes when I pass a map as props it works fine

noonian02:11:03

man, after figuring out that normalization stuff everything just started working as I hoped/expecting things would be simple_smile

dvcrn03:11:42

question: I have a post component which looks like this:

(defui Post
  static om/Ident
  (ident [this {:keys [id]}]
         [:post/by-id id])
  static om/IQuery
  (query [this]
         '[:id {:user [:username]} :content])
if I understand this query fragment correct, it says give me :id :content and :user (but only :username) from that. Post is identified by id. My server is returning data like this (after parsing):
{:app/posts [{:user {:username dvcrn}, :content Hello World!, :id 1}]}

dvcrn03:11:14

yet after normalisation, :user is always nil. What did I do wrong?

dvcrn03:11:06

(The parent component queries like this:

(defui TimelineComponent
  static om/IQuery
  (query [this]
         (let [subquery (om/get-query Post)]
           `[{:app/posts ~subquery}]))
)

dnolen03:11:03

@dvcrn: you should be able to test this without the server bit

dnolen03:11:19

Isolate the issue

dvcrn03:11:58

hmm what do you suggest?

dvcrn03:11:23

my thinking was that the :user key will be handled like every other key in that query during normalisation. so :post/by-id 1 should be {:id 1, :user {:username dvcrn}, :content Hello World!}

dvcrn03:11:54

ah, am I supposed to return the data flat maybe? like: {:app/posts [{:user/username dvcrn, :post/content Hello World!, :post/id 1}]}

dnolen03:11:10

@denik: make a minimal example

dnolen03:11:12

@dvcrn: just test parsing or normalization with data like the tutorials show

dvcrn04:11:48

hrm you are right. I tested it with the normalisation tutorial (but with "name" being embedded into "user") and the problem seems to not be present

dnolen04:11:30

@dvcrn: might be a normalization bug now that I look at it

dnolen04:11:28

using your example as a test case

noonian04:11:34

I think I just found a normalization bug

noonian04:11:28

normalizing nested data with a ui tree where you have nested components with idents

noonian04:11:35

hard to describe

dnolen04:11:41

@noonian: might be the same issue @dvcrn is having

dnolen04:11:45

just fixed in master

dnolen04:11:59

if it’s not fixed, need another minimal case

dnolen04:11:15

make sure your environment is clean if you’re testing master yadda yadda

noonian04:11:32

ok, I haven’t tested master yet

dnolen04:11:41

@noonian: looks the same

noonian04:11:48

and also didn’t understand what @dvcrn’s case was

dnolen04:11:49

definitely a bad bug that’s easy to hit

noonian04:11:05

I’ll check master in a moment

noonian04:11:03

I think my case still exists

noonian04:11:21

but I want to make sure what I’m trying to do is/should be supported

noonian04:11:55

In my case, the first component encountered in the tree that implements ident is correctly normalized, but the data nested inside that map is not normalized i.e. the normalization does not recurse into the identified thing and replace maps with refs. It doesn’t create tables for the components getting the nested data.

dvcrn05:11:13

@dnolen: can you go into short detail what was causing that bug?

dvcrn05:11:17

Checking if it's fixed for me

dvcrn05:11:34

problem is gone. user data is now being normalised correctly.

dvcrn06:11:48

Somehow I'm getting process.hrtime is not a function now though

noonian06:11:18

What version of cljs are you using? I’ve had similar issues in the past that were fixed by updating to the latest version (1.7.170 at this time).

dvcrn06:11:01

let me check

dvcrn06:11:37

@noonian: yep that was it. Updated clojurescript and cljsbuild and it's gone

thomasdeutsch10:11:07

In my datascript/om.next app i would like to specify that a component should not be rendered if only a :db/id is received. Here is a scenario in 30 loc: https://gist.github.com/ThomasDeutsch/8a88f6d63063e892daee Would this make sense?

jannis10:11:50

@thomasdeutsch: Sure, why not? If the subcomponent queries demand props that you can't satisfy because they don't exist / aren't set, you shouldn't pass the incomplete data down to those subcomponents anyway - you'd be violating the contract established by their queries.

jannis10:11:49

Although I'd probably make sure that what ends up in the database is stuff that is actually useful (e.g. through validation / schemas / etc.) and can be rendered.

dnolen11:11:10

@noonian: so I spoke incorrectly last night, the keys of the union matter

dnolen11:11:42

the keys must match the first component of the idents

dnolen11:11:33

@noonian: I would test with master (made some other fixes) and change this and see if it still fails for you.

dnolen11:11:52

if does please provide the components along with the data as well so I can easily make a test case. Thanks.

jannis11:11:13

UUID hashing in transit-cljs was a nasty bug. Took me an hour or two last night to figure out why in default-migrate, (get-in pure old) returned nil, resulting in all local entity props to be erased when migrating from a tempid to a real one.

dnolen11:11:32

@jannis ah yeah, I’m surprised that one was only just reported a couple of days ago

dnolen11:11:44

but maybe people just aren’t using UUIDs that much yet

jannis12:11:04

I didn't notice it at first yesterday because along with the mutation, I also re-read the corresponding data. So it would migrate to something empty, then be overwritten by the new data right away. Dropped the read and ran into the bug right away.

jannis12:11:16

But it's working now

dnolen12:11:34

ah right because I suggested that (`:id-key`)

dnolen12:11:45

@jannis glad to hear it, sorry about that

jannis12:11:09

No problem at all

jannis12:11:23

If cljs-ajax had bumped its dependency on transit-cljs, it wouldn't have been an issue. This should solve UUIDs in any client that uses cljs-ajax: https://github.com/JulianBirch/cljs-ajax/pull/113

dnolen12:11:10

@jannis yeah this also is why I never bother with wrappers over goog.net.XhrIo

dnolen12:11:26

just too much trouble for a simple but critical part of the app

jannis12:11:36

You're probably right. cljs-ajax doesn't even make it possible with less code. The extra dependency/complexity may not be worth it.

anmonteiro12:11:51

I might have completely misunderstood what it is used for, but doesn't lein override the package's dependency if you use :scope "provided"?

anmonteiro12:11:18

or is it for something totally different and I'm just saying nonsense?

dnolen12:11:04

@anmonteiro: people keep copying that part blindly

dnolen12:11:12

that’s Maven scope

dnolen12:11:25

it doesn’t make sense to do that in anything but libraries that other people will use

anmonteiro12:11:59

thanks for clearing it up for me

dnolen12:11:59

it just means this is a dependency but don’t actually add it to the artifacts lists of deps

dnolen12:11:08

because everyone will always provide it themselves

dnolen12:11:24

so it doesn’t make sense for anything other than Clojure & ClojureScript

anmonteiro12:11:46

even then, only in libraries that other people will use, right?

dnolen12:11:52

absolutely

anmonteiro12:11:58

doesn't really make sense on our own projects, then

anmonteiro12:11:03

if I'm understanding correctly

dnolen12:11:07

that’s correct

anmonteiro12:11:11

by projects I mean apps

dnolen12:11:32

it’s just a way to avoid adding to a user’s dependency hell

dnolen12:11:00

you have to be careful though

dnolen12:11:10

I do it because Clojure & ClojureScript change with enough frequency

dnolen12:11:28

but if your library actually needs a specific version of either of those things you need to pin.

anmonteiro12:11:44

yep, that makes sense

dnolen13:11:00

@jannis integrated transform-reads into transact, give it a spin at your leisure

jannis13:11:43

Wow, that was quick

jannis13:11:04

I'll look at how you did it first, I'm really curious

anmonteiro13:11:59

haven't been following the latest updates to Om, been caught up in schoolwork; what does transform-reads do ?

dnolen13:11:22

@jannis wasn’t much to do since there’s all these helpers now that are needed elsewhere

dnolen13:11:41

@anmonteiro: it fixes up reads so that remotes get the right thing

dnolen13:11:58

and locally you have the convenience of just talking about some key

anmonteiro13:11:59

selector-wise?

dnolen13:11:16

[(change/it! …) :some/list]

dnolen13:11:30

that’s fine locally, but remote we need to know the queries associated with that prop

anmonteiro13:11:24

so it gets those queries from the components where they are declared

anmonteiro13:11:31

and passes them to our read fn?

jannis13:11:22

@dnolen: Excellent. focused-query is what I tried to "emulate" in my hack (except only for the initiating component itself). full-query is something the hack didn't even consider. Nice. Gonna try it now

jannis13:11:13

@dnolen: (get-ident this) is always (ident this (props this)) now?

dnolen13:11:49

@jannis yes, I could bring that back, were you actually using that?

jannis13:11:40

Everywhere simple_smile Mostly to pass the ident of a component to callbacks. But I can live with ident as well, it's only marginally longer.

dnolen13:11:51

@jannis reverted, it’s back

dnolen13:11:58

I just forgot why it was there simple_smile

jannis14:11:26

@dnolen: Somehow performing a local mutation without specifying any reads causes the entire query of the initiating component to be sent over the wire again.

dnolen14:11:08

@jannis well you have the implicit read of the component

dnolen14:11:21

but that shouldn’t be triggering a the query to get rewritten out

jannis14:11:43

Yeah, that's supposed to be local only, isn't it?

dnolen14:11:13

@jannis if you look at transform-reads you should see it only applies if the transaction fragment is a keyword

dnolen14:11:53

@jannis so not clear to me how that could be happening

jannis14:11:50

Same here. tx only contains the mutation by the time it arrives at transact*. I'll debug a bit more.

jannis14:11:26

Okay, it happens only when the app is reloaded after changing its code. If I refresh the page in the browser it works. I had this weird behavior before...

dnolen14:11:18

@jannis right because you blew away the state and it would resend right?

jannis14:11:44

That's the initial read but that's another thing. I've ran into situations where the app has behaved differently after refreshing and after reloading (regardless of the state). One time it was caused by doing (for [item list-of-items] (item item)) by accident (data and component had the same name...). I must be doing something like that again.

dnolen14:11:04

@jannis so I’m interested in the case the where you actually supply a key, does that work for you?

jannis14:11:50

With my app behaving in two different ways I can't say which one is actually the right one.

jannis14:11:34

It could be that it transforms [(app/something) :foo] into [(app/something) [({:foo ...} {:param :bar})]] instead of [(app/something) ({:foo ...} {:param :bar})] but I can't be sure.

jannis15:11:24

I think the app is behaving normal again. @dnolen It's not transform-reads that is the problem. It only sends the entire component query over the wire if mutate returns an :action. So somewhere else it must accidentally go remote when updating the component after the action.

dnolen15:11:27

@jannis ok cool, that could be a bug in Om of course

jannis15:11:38

Strange. It only happens if :action is provided and :send is specified.

dnolen15:11:38

@jannis you must be providing :remote logic somewhere and not conditionalizing it?

dnolen15:11:51

if parse keep returning :remote then it’s going to keep going back

dnolen15:11:07

(or it’s a bug)

dnolen15:11:52

@jannis easy way to test - parse w/ this mutation query provide :remote as 3rd argument

dnolen15:11:59

it should return []

dnolen15:11:04

if it doesn’t, that’s the bug

dnolen15:11:36

@jannis so something else is up

dnolen15:11:18

@jannis I would test gather-sends next.

dnolen15:11:06

(gather-sends (to-env (:config reconciler)) tx [:remote])

jannis15:11:27

Will do. (om/transact! reconciler '[(app/toggle-expanded ...)]) triggers the send as well, so it's not the component being added implicitly that's the problem.

dnolen15:11:02

@jannis if this is getting messed up it’s getting messed up at gather-sends

dnolen15:11:06

that’s what transact* uses

jannis15:11:17

gather-sends returns {}.

dnolen15:11:32

heh so then this doesn’t make any sense simple_smile

dnolen15:11:10

I would start setting some breakpoints in the transact logic and poking around

dnolen15:11:48

or in queue-sends! impl of reconciler

dnolen15:11:58

and walk the stack backwards to see how this is possible

jannis15:11:55

Is there a way to see cljs data structures and not the generated JS ones when debugging in chrome?

dnolen15:11:37

I just use cljs.core.pr_str

jannis16:11:25

@dnolen: Right. @tony.kay pointed me to it. It may be simple. The "problem" is that something triggers schedule-render!. Could be the state watch. That calls reconcile!, that fetches the root query and gathers and schedules the read sends I'm seeing.

dnolen16:11:56

@jannis, ah right I see the bug, will fix in a bit

jannis16:11:17

What's the bug exactly?

dnolen16:11:03

see parsef in reconciler

dnolen16:11:15

the gather-sends there should be first time only

dnolen16:11:46

simple to fix

tony.kay16:11:48

@dnolen: is the second one to pick up possible new stuff that needs to happen due to the state change?

tony.kay16:11:07

perhaps I'm misunderstanding something: the parser is run with a nil target and each remote on every re-render, correct?

tony.kay16:11:31

or is the remote set only done after transacts and query param changes?

tony.kay16:11:31

my reading of the code says the former...gather sends is running the parser on all remotes

tony.kay16:11:38

during parsef

nha16:11:50

following the om.next tutorial (the datascript integration part), I get :

pull_parser.cljc:223 Uncaught #error {:message "Cannot parse pull pattern, expected: [attr-spec+]", :data {:error :parser/pull, :fragment nil}}
. Is there some change to do from the README ?

dnolen16:11:45

@tony.kay: it’s just wrong

dnolen16:11:55

gather-sends should only run 1st time and after transactions

tony.kay16:11:22

set-params!?

dnolen16:11:11

@tony.kay: ah right after query changes

tony.kay16:11:21

I had assumed your example in todomvc of conditional remote logic and comments on conditionalized read meant you intended that simple_smile

jannis16:11:38

Does that mean :remote true doesn't have to be conditionalized at all because it will only be executed during initial read and transactions that ask for the key to be re-read?

tony.kay16:11:41

So, you need the conditions either way...but I can see why you only need to do the remote rescan in special cases

tony.kay16:11:01

@jannis: ANY transact could re-run it

tony.kay16:11:14

so conditional it is, unless you want to repeat it always

tony.kay16:11:24

parse goes from root

tony.kay16:11:28

@dnolen: but what if the incoming data from the remote read changes the app state in a way that wants more remote reads?

dnolen16:11:57

@tony.kay: that just sounds broken to me

tony.kay16:11:03

e.g. new things appear on the screen that were not there.

dnolen16:11:14

one way binding

dnolen16:11:22

if a read causes another read that’s two way binding

tony.kay16:11:25

I guess the follow-on reads in transact can handle that

jannis16:11:35

transact! doesn't gather keys from the root though, so you can choose whether or not to re-read remotely by including it in the transaction. If you don't - local re-read only. If you do - local and remote re-read.

jannis16:11:10

I find conditional :remote confusing. The only situation where the client knows to re-read remotely is on initial render and whenever a mutation happens. That information is not available inside read :foo.

tony.kay16:11:42

straining my brain to think of an example...had not thought about it as a two-way binding

tony.kay16:11:32

@jannis: what's wrong with "if my data is here in app state, use it; else remote".

tony.kay16:11:41

"refresh" becomes a transact that clears the state

tony.kay16:11:52

or timestamps, etc.

jannis16:11:04

How do I know the data in my app state is up-to-date enough not to require remote?

jannis16:11:01

The client doesn't have the tools to make that decision in read. Unless I'm wrong.

tony.kay16:11:20

up-to-date is cache invalidation problem...one of the two hard problems

tony.kay16:11:30

(naming, cache invalidation, and off by one errors)

tony.kay16:11:05

I don't think David has solved that one in Om simple_smile

jannis16:11:25

Fair enough. You could argue that polling/pushing server data into the client can happen separately to keep the app state up to date.

jannis16:11:42

And the client needs to assume what it has is fine.

jannis17:11:44

Although in that case... why have remotes at all and not just wait for something else to make data available in the app state?

jannis17:11:19

Also: if :remote is conditional, gathering sends for (om/transact! '[(foo/bar) :baz]) would never return any.

jannis17:11:00

I think you want to be able to state: after this mutation, :foo or :bar may be out of date and I want to re-read it. But if there already is a :foo or :bar in the app state, that wouldn't end up as a query at the remote end.

jannis17:11:15

Unless you add explicit invalidation flags in the app state and ... ugh.

jannis17:11:22

Please correct me if I'm totally wrong here. simple_smile

tony.kay17:11:47

Why can't your (foo/bar) clear the invalid stuff locally before returning?

tony.kay17:11:05

I haven't looked at transact! implementation enough, so not sure what else it might do

bplatz17:11:54

@jannis: This is what I am doing... so the query ends up being more of a subscription request than an request for data. The server will send updates, and the client assumes it always has current data.

bplatz17:11:45

SSE... but web sockets would work fine too.

tony.kay17:11:20

either way, the thing that remains: we need to understand better how it is supposed to work simple_smile

bplatz17:11:00

Datascript allows the subscription to be more broad, to reduce the server-side need to re-running queries. So it can push attribute changes that may not actually be required, but then the client will re-execute the query once the changes are received. Om helps here in that it will limit re-rendering if nothing has changed.

tony.kay17:11:04

the code for transact does local and remote

tony.kay17:11:19

queues and sends

jannis17:11:40

@tony.kay: You could clear the invalid stuff. But think about the tempid feature, for instance. If you'd say saving a temporary entity will remove it from the local state parallel to sending to the server for creating it there, the whole tempid migration story makes no sense.

tony.kay17:11:00

so, the parser (your parser) must do the "right thing" to get the follow-on reads to ever happen

jannis17:11:25

And if you didn't clear the temporary entity but marked it as invalid instead, you'd have to clear the invalidation hints when merging the server data or during migrate.

dnolen17:11:04

@jannis “the client doesn’t know to read"

dnolen17:11:12

this just simply isn’t true

dnolen17:11:32

this is how caching works everywhere

dnolen17:11:39

there is no magic way to invalidate cache

dnolen17:11:53

only the programmer knows when/how and with what strategy

dnolen17:11:52

tempid strategy is just a special case that’s outside of any specific application (like GC)

jannis17:11:46

I guess instead of deleting an entity with a tempid before transacting its real creation, read could return :remote true if the entity has a temporary id.

jannis17:11:34

So if you pass the read to the transact! call, it would go remote.

stephen17:11:07

@dnolen How would I import styles from a css file per component? http://ai.github.io/postcss-way/?full#29

dnolen17:11:29

@stephenway: Om Next doesn’t care about that, same as it doesn’t really care about DOM in the big picture

dnolen17:11:15

@stephenway: CSS is very specific to web, Om Next is designed to work with Web, iOS, Android

dnolen17:11:25

so that’s a community concern, not one I intend to work on myself

stephen17:11:49

oh interesting, didn’t know that

dnolen17:11:12

like traditional routing, templating

dnolen17:11:35

this is all stuff I don’t care about including

dnolen17:11:15

@jannis I don’t really understand this point about handling tempid’s via read

dnolen17:11:29

another huge thing about tempid stuff is clients who cannot reach the network

dnolen17:11:14

tempid is just about building up the value you want before committing, regardless of when you get to commit it

jannis17:11:56

Let's ignore the tempid stuff for the moment. What I don't understand is how passing a read to remotely executed transact! would be useful if the corresponding read function had a conditional :remote that is only returned if there is no data in the local app state.

jannis17:11:33

How would you express "please have the post-tx read include the remote part after this transaction"?

dnolen17:11:33

@jannis I don’t understand the question since I don’t know why you would do that

dnolen17:11:59

you’re talking about the case where it’s already in the app state but you need a fresh thing

dnolen17:11:25

@jannis right so not obvious but that was addressed a while ago

dnolen17:11:40

[(do/it! …) ‘:please/read]

dnolen17:11:19

quoting will always refetch it doesn’t matter what you say in read

jannis17:11:52

Oh! How did I miss the discussions around that?

dnolen17:11:03

@jannis I think it was before you showed in the channel

dnolen17:11:05

really old thing

dnolen17:11:39

@jannis heh, been working on this since February

dnolen17:11:52

so there are quite a few things that happened before the Slack channel was a thing

jannis17:11:13

How does the quoted thing know what the remote AST(s) will be if they aren't returned by read?

dnolen17:11:34

@jannis you can do this via metadata

dnolen17:11:53

@jannis this stuff wasn’t completely set in stone though since I wasn't really sure about runtime remote computation

dnolen17:11:01

and I definitely am convinced of that now

dnolen17:11:16

@jannis: you can do [(do/it! …) ~(with-meta ‘(quote :please/read) {:remote …}))]

dnolen17:11:32

and I’m more than happy to add a helper for that

dnolen17:11:34

something like

dnolen17:11:46

[(do/it! …) ~(force :please/read :remote)]

jannis17:11:01

Ok. I haven't modified AST remotes yet, so others would be better judges on how this is done best.

jannis17:11:07

I was just curious

jannis17:11:31

I'll play with quoted reads

jannis17:11:37

And conditional :remote.

jannis17:11:41

transform-reads seems to turn [(app/dosomething) :foo/bar :baz] into [(app/dosomething) [:foo/bar] [{:baz [:db/id :baz/name]}]] where it should be [(app/dosomething) :foo/bar {:baz [:db/id :baz/name]}]

dnolen17:11:18

@jannis good catch fixing

dnolen17:11:03

should have been into tx not conj tx

dnolen17:11:24

@jannis also fixed the continuous gather sends problem

jannis17:11:25

@dnolen: Thanks for the fix, retesting now

jannis17:11:59

@dnolen: I am confused enough now... wasn't gather-sends fine after all if :remote is conditional?

dnolen17:11:33

the logic should be very, very clean here

dnolen17:11:43

only 1st time and only after transactions or query changes

jannis17:11:46

Doesn't that mean you could always return :remote true and it would still only be executed "1st time and only after transactions or query changes"?

jannis17:11:08

And only transactions that ask to re-read the thing that always returns remote true.

dnolen17:11:15

@jannis in what cases would this not be desirable?

jannis17:11:01

@dnolen: This is perfectly desirable, it's what I've been arguing for all along (unless I misunderstand yet again). 😉

jannis18:11:05

@dnolen: transform-reads works fine now, the gather-sends on rerender is also gone and it's all working smoothly now. Good stuff!

dnolen18:11:21

@jannis oh ok misunderstood simple_smile

dnolen18:11:59

ok so here’s a breaking change, apologize for that

dnolen18:11:14

set-query! & set-params! are separate functions

dnolen18:11:29

but that’s a disaster for computing sends

dnolen18:11:33

(you’ll do it twice if you do both)

dnolen18:11:49

I’m going to collapse these two things into one fn

tony.kay18:11:03

@jannis: but the parser will run from root, so anything that says remote true will be included in the remote read, I believe

tony.kay18:11:20

so conditionals are still part of the equation

tony.kay18:11:00

@dnolen: Ah, the quote thing is exactly what I needed for what I'm working on...I was doing something a lot more convoluted

tony.kay18:11:01

I like the idea of a helper function for that...quote is not very self-documenting

gardnervickers18:11:54

I have a component that queries for a nested map, and then creates a set of child components. I am passing transact callback to each of those components I create. This should be enough to trigger a re-render correct? I shouldnt need to implement Ident and IQuery on the child components right?

dnolen18:11:50

@tony.kay: will add a helper for sure

dnolen19:11:51

set-query! and set-params! collapsed into master

dnolen19:11:55

update docstring on usage

tony.kay19:11:35

ok, so everything is set-query! now

dnolen19:11:37

@tony.kay: fixing the send issue with set-query! now

bplatz19:11:42

I think I've seen some conflicting information about returning a vector from a join. Is that best practice, or is a map perfectly acceptable. i.e. [{:me [:name]}] returns {:me [{:name "brian"}]}, or is returning {:me {:name "brian"}} perfectly acceptable?

dnolen19:11:40

@bplatz: all the code is meant to handle vectors or maps

dnolen19:11:57

if there’s some case that doesn’t work provide a minimal example

dnolen19:11:05

@tony.kay: master is fixed

bplatz19:11:40

Both work, I just thought I saw somewhere "always return a vector from a join". In certain cases I'd prefer to return a map from a join, I just want to make sure I'm not messing up anything internally if I do so.

dnolen19:11:02

@bplatz: if you can find that, feel free to fix

dnolen19:11:10

I realized that you need to be able to return single values

dnolen19:11:20

1.0.0-alpha22 released

dnolen19:11:22

updating docs

tony.kay19:11:46

@bplatz: I might have made such a mistake in my (unstanctioned) doc...I didn't realize singleton case was ok until fairly recently

tony.kay19:11:38

yeah, I did say something like that in my docs...fixing

dnolen19:11:21

force remote read helper added to master

noonian19:11:20

@dnolen: thanks, changing my ident fixed everything.

noonian19:11:04

Do you have any plans to make the relationship between the shape of an ident and how things are normalized more configurable?

paxan20:11:15

OH: "i swear he’s watching our private slack channel, the # of times he’s just happened to drop whatever feature we’ve been wanting is uncanny"

jannis22:11:12

@dnolen I assume doesnt force sending reads to remotes if the remotes are conditional in the corresponding read functions and thus may not be returned from via e.g. :remote, :static or whatever? Or can it do that somehow?

dnolen22:11:06

@jannis yes force sending just overrides everything

dnolen22:11:20

an alternative is to just parameterize the key yourself

dnolen22:11:29

and conditionalize in parse on that parameter

jannis22:11:57

But the resulting queries don't include modifications to the AST that read might make if the condition for a remote is true?

dnolen22:11:29

@jannis I don’t understand what you’re asking.

dnolen22:11:47

my point is that read can’t easily know if something changed by itself

dnolen22:11:59

it can if you parameterize the key after the transaction

dnolen22:11:04

you can do whatever AST fu you want

jannis22:11:36

Yes. We may be talking about two different aspects. When you read :foo/bar the usual way, its read function would be called and that might return :value plus perhaps :remote. The latter could be true or it could be a modified query/AST, right? Like in your static vs. dynamic example. Om would then use that modified query and send it to the remote. Actually, with force I assume read is still called and in there you can then detect that (via target?), bypass any conditional stuff and to get the same modified query even if the condition you'd normally use may be false?

dnolen22:11:36

@jannis I think I understand what you are trying to ask

dnolen22:11:52

whether quoting will allow you do something conditional instead of going some other way

dnolen23:11:47

the answer is yes you can in fact detect this

dnolen23:11:03

the AST fragment will have :target, normally it would not

dnolen23:11:25

@jannis so you can reuse whatever you’ve got going on

jannis23:11:12

My confusion is mostly about what force/quoting actually does. Like: what would the resulting query look like compared to not forcing? How is it different from an unconditional remote in the corresponding read function? If read has (if <cond> {:remote ...modify AST...}), will the forced query have that modification if the cond is false. As for the latter, I'm guessing: only if the condition is aware of checking :target. Or if force is passed that same modified AST already.

jannis23:11:43

I might be miles off with my assumptions about what it does...

dnolen23:11:32

sorry for not being clear

dnolen23:11:37

it only does ONE thing

dnolen23:11:42

add :target to the AST

dnolen23:11:45

so you can detect this case

dnolen23:11:39

for example

dnolen23:11:01

the first time you read you know you want to go remote because you cannot find it in the app state

dnolen23:11:08

after that you never want to go remote ...

dnolen23:11:27

unless someone forced a read and you know that happened because the AST now has :target

jannis23:11:14

Ok, cool! :) So you can make it (if (or <cond> <has target?>) {:remote ...}) basically.

dnolen23:11:32

yeah there might be a bug here but that’s how it’s supposed to work

jannis23:11:56

Oooook, sorry it took me so long but I get it.

dnolen23:11:10

yeah there’s a bug fixing

dnolen23:11:13

and you can give it a shot

dnolen23:11:17

@jannis fixed in master, give it a spin

jannis23:11:20

I'll try tomorrow. Put the laptop away because I needed a break (if only from hacking myself) 😉

dnolen23:11:29

@jannis haha, no rush

jannis23:11:12

I was expecting more magic but looked at force and thought: "but how das that force anything?" So it doesn't per se but it makes forcing possible. Good, I can take a nap at ease now. 😉

jannis23:11:18

Or does it also send the read over even if the local read function doesn't do anything / doesn't return anything for the target remote?

dnolen23:11:48

@jannis I just changed the behavior, previously it would go regardless, which was the wrong thing (that’s what I stated earlier)

dnolen23:11:01

you need to be able to control this, the new behavior doesn’t blindly go

jannis23:11:24

You, agree.

dnolen23:11:52

@jannis yeah after you pointed out that you’d lose your AST modifications I realized the current way was wrong

dnolen23:11:40

seriously everyone in the channel is amazing ❤️

dnolen23:11:05

thanks much for helping think through all of this stuff … there’s a lot of corners!

jannis23:11:01

Well, we get your hard work, pace and incredibly amazing technology in return. It's worth for that alone but it's also great to learn so much as we discuss and be a really lively community through it. So thank you as well! simple_smile