Fork me on GitHub
Reily Siegel21:08:19

Quick question about union queries: is it possible to union on an attibute that isnt the ident? I have a system where all products have a :product/sku and a :product/type. Products with different types need to be displayed/edited using different components. Is this a use-case for union queries, or would I be better off using pathom in lenient mode and requesting data for all types and dispatching on :product/type?


Fulcro's UI interpretation of union queries is as follows: When denormalizing a given edge (e.g. {:feed/entry [:image/id 22]}) where the query for that join (:feed/entry) is a UNION, it uses the keyword portion of the ident to look up the subquery on the union component. Thus, the first element of the ident IS the index into the map of the union query. So, resolution on the server of union queries is one thing, but the UI interpretation structure requires that you use idents that can dispatch this way. Normally you use union queries when the underlying data is actually different (in complete identity). For example and image vs text object vs video. In those cases the keyword (first) of the ident will naturally vary, normalization will work properly, as will union query lookup. In your case you've got a single kind of thing (a product) and you want to vary some display aspect based on a type field. This is not a good use-case for unions. Instead just dispatch your rendering on :product/type and use plain functions to encapsulate those differences.

Reily Siegel21:08:31

Thanks for the info!


Perhaps an additional bit of info to enlighten: Union queries can be seen as a kind of optimization: To not over-query when the possible things at a path have an orthogonal nature. This is true for the network and the UI, since every prop that you query for (or worse, have a sub*query for) entails overhead. If there is a lot of *overlap and very little orthogonality, then a union isn't really called for (the optimization doesn't win much, and the overlap in identity causes the issues above).


This is why it was used in legacy routing: only one UI component (completely orthogonal) was ever on-screen at once (to-one relation)...but the subquery of each route was large, so there was a lot to save in terms of optimization.


Dynamic routing adds more features, and leverages dynamic queries instead (where the actual query of the router is changed at runtime to just point to one thing at a time)