Fork me on GitHub
#untangled
<
2016-11-04
>
wilkerlucio11:11:48

hello, for the people using Datomic, how are you handling union queries on the server side?

ethangracer13:11:03

@wilkerlucio we’re only using union queries for view routing on the client, so we never need to send those queries to the server. all the queries we send contain only props and joins

wilkerlucio13:11:24

@ethangracer thanks, and you have thoughts on how to integrate that with pull syntax? on my previous project I was fully controlling the parsing, so was kind easy to implement, I can still go this way but I rather find a way that requires less coding

ethangracer13:11:55

I wouldn’t describe it as “integrating with pull syntax”, but what we do is we set up all of the UI relevant concerns with InitialAppState (which include all of the union queries). Then we’ll do something like (load-data this [{:people (om/get-query Person)}]), which would build a list of people idents at :people normalized to :people/by-id. So when we need to access all people, we do so by adding [:people ‘_] to the query of the component that needs the data

ethangracer13:11:40

So we circumvent the need to have the data placed in the app state corresponding with the UI component structure (which would require the union logic server-side that you’re talking about to return the data in the right format)

wilkerlucio13:11:05

humm, my need is in the heterogeneos list style of query

wilkerlucio13:11:41

I think it needs to be processed on the server side, otherwise I would be required to overfetch (and in my case that can be a disaster, some of the types requires much more data than others)

ethangracer13:11:29

what do you mean by “heterogeneous list style?"

ethangracer13:11:41

entities with different attributes in the same list?

ethangracer13:11:32

I’m not sure off the top of my head if there’s a way to do that without server-side processing

ethangracer13:11:48

And I’m not sure how a union query would handle normalizing that data

wilkerlucio13:11:55

I don't think would be possible without it, the server needs to decide the fields while fetching each entry

ethangracer13:11:56

just because I haven’t tried it 🙂

wilkerlucio13:11:02

I know how to handle the client side, I did it before, just the server is being a scratch on the head (you can see more for the client here: https://github.com/omcljs/om/wiki/Queries-With-Unions)

ethangracer13:11:02

I suppose on the server you could write a query that pulled on set of attributes or another based on what attribute was missing from the entity that you’re pulling

ethangracer13:11:37

i.e.

[:find ?e
 :where 
(or-join [?e]
  (and
    [(missing $ ?e :attr-type/two)]
    [?e :attr-type/one ?value])
  (and
   [(missing $ ?e :attr-type/one)]
   [?e :attr-type/two ?value]))

ethangracer13:11:53

but that gets super ugly the more entity options there are

wilkerlucio13:11:17

and it ties the query to the attributes... not very good, we need the client on this decision

ethangracer13:11:06

yeah I would definitely vote for a post-mutation

ethangracer13:11:21

do a separate query for each type

ethangracer13:11:25

then manually merge the lists of idents into one list

wilkerlucio13:11:19

I think doing that would be a pain to join the items in order after, would need a separated field just to keep the sorting (that might change depending on occasion)

ethangracer13:11:31

oh, it’s order dependent!

wilkerlucio13:11:32

I believe the best solution is to the server to process the union as is

ethangracer13:11:32

In that case I’m not sure that you have an option apart from manually parsing it server-side

ethangracer13:11:39

but you’re now out my depth!

wilkerlucio13:11:44

on the other project I used something I called :union-selector, so in my manual parsing I check for this option, when it's present and the current query is an union, it would use the value of :union-selector as the key (which could be a regular attribute on the field, or a virtual one), to select which query to fetch the rest

wilkerlucio13:11:05

works greatly, but then I have to re-implement most of the pull syntax myself

ethangracer13:11:18

honestly not completely following but I understand the need to split up the union query into its constituent pull syntax fragments to get the data from datomic

ethangracer13:11:54

@wilkerlucio with regards to the sorting, why not just do that client side? why does it need to come back from the server sorted? if you don’t need the data to be sorted by the server, then you can use the post-mutation method and just sort the list that way

wilkerlucio13:11:36

@ethangracer it's possible, but I ultimaly I think the union syntax is a good query syntax, and by using it I avoid a lot of those manual transformations that will be hard to understand (and imagine a project with multiple of those across the UI)

wilkerlucio13:11:48

I think solving on the server is the simplest solution

ethangracer13:11:32

fair enough. I’d be curious to see a snippet for how you're handling that at some point if you don’t mind sharing

wilkerlucio13:11:26

sure, no problem with sharing at all 🙂

tony.kay18:11:01

@wilkerlucio Handling it on the server is why we left you to write parser emitters on the server. As long as you return your hetero list from the server, you can use the union query on the client to normalize the result.

tony.kay18:11:42

So, perfectly normal to want to send a union query to the server, but yeah Datomic won't just "get it"

wilkerlucio18:11:07

@tony.kay we, I'm getting to think that a custom pull reader is going to be required by a lot of applications, datomic pull is great, but not flexible/extensible enough, I'm porting some of the engine that I did before in Node.js to Clojure, it might get to be a lib one day 🙂

wilkerlucio18:11:09

the datomic entities help a lot on that

tony.kay18:11:23

In general, it would be nice to have something that does that repetitive work for both SQL and Datomic

tony.kay18:11:35

with just some security plugins

currentoor18:11:51

@wilkerlucio we also felt datomic pull was great but not flexible/extensible enough

wilkerlucio18:11:41

@currentoor thanks, I'll check it out

baris19:11:43

What's the best practice to store blob files e.g. images due the lack of support for blob files in datomic? I just saw that the adstage pluck-api mention the use of a blob store in the example snippets.

therabidbanana19:11:23

At AdStage we just generate a UUID and store them as serialized bytes to postgres (using Nippy), then use the pluck api to join the data back in as if it was a key you could pull with datomic. As datomic makes indexes on values, this was the approach recommended to us in the #datomic channel, rather than trying to serialize to string and store as a value in datomic.

baris19:11:15

Sounds good for me. Thanks

therabidbanana19:11:11

(Well, to be clear, just the "don't store in datomic" part was recommended, we arrived at the "store in postgres" thing mainly because we were already setting it up as our underlying datomic data store, so easy to add an extra table somewhere...)

baris20:11:27

That's reasonable. I also have to checkout the image-library component in untangled-component

baris20:11:19

But the pluck-api/blobstore solution is more general in case for storing other types of files for e.g PDFs and so on.

currentoor20:11:37

@baris yeah you should be able to store anything with the pluck API and still retain the niceness of the datomic pull query

currentoor20:11:31

the pluck-api doesn’t yet support pluck-many, analogous to pull-many for collections, but for pull it works pretty well for us

baris20:11:49

That's pretty cool. I'll give it a try.

currentoor20:11:11

awesome, let me know what you think 😄

ethangracer20:11:02

thought i’d drop a quick note in here to let people know that as much as I’ve enjoyed working on Untangled, and as much as I hope that I’ll continue to work on it, I’ve accepted a new job that isn’t working in Clojure. So I’m not sure how useful I’ll be as the framework continues to grow since I won’t be developing with it full-time or professionally. In any case, it has been a pleasure getting to know everyone here and we’ll see what happens. The rest of the team is still around and I’m still going to evangelize untangled as much as I can 🙂

currentoor20:11:25

@ethangracer sorry to see you go. I really appreciated your push for documentation. Good luck with the new job!

baris20:11:56

@ethangracer: All good for your future career...thanks for pushing untangled

wilkerlucio21:11:23

@ethangracer good luck on your new job, and thanks for all your contributions so far 🙂

ethangracer21:11:40

thanks everyone!

wilkerlucio22:11:21

@ethangracer I just finished the basic implementation of my parser, supporting union queries, the implementation uses an idea of "portable nodes" you can say, since I started using Om.next I always though on my server as a graph, and I would like to be able to specify nodes in a way that I could re-use then at any node point on my graph, and being able to compose those, to solve this I end up with the idea of "readers", the readers can be functions (simplest one, just receives the env) maps (keys are the attribute to access, values are functions that takes env) and sequences (can express a series of readers, readers can stop there to return a value, or return ::continue to move into the next reader, like ring or something), with these ideas I got a small library for those readers, and they are the base for the rest:

wilkerlucio22:11:45

then to use it:

wilkerlucio22:11:40

the important bit here is read-memos, it sets the ::union-selector to use :memo/type as the field to figure which branch of union to go, the rest is generic and can be reused

kenbier23:11:49

@ethangracer congratulations! just out of curiosity, what are you working on now if not clojure?