Fork me on GitHub
#other-languages
<
2021-12-21
>
Yehonathan Sharvit10:12:15

Thank you @mauricio.szabo for participating to this discussion

Yehonathan Sharvit10:12:59

It seems that with bee-record you tried to port the good parts of ActiveRecord to Clojure. Is that correct?

raspasov11:12:28

@viebel I totally agree that there's a problem (but unsure of the best solution). The problem can be stated as: There's data in your database (call it DB) and there's the language data structures (Clojure or Ruby, no difference, call it LANG) which everybody knows and loves to use. How do you create a two-way connection between the two data models? Fetch data from DB, converts to LANG. Change some data in LANG, magically end up in DB. On the surface, this seems straightforward. But in practice, it never is. Sometimes you need just the "person". But other times you need the "person" with the list of "orders" that they've placed in the last 30 days. Joining data, filtering data, removing data, using caches like Memcache, etc, makes the process of constructing the LANG data complex.

raspasov11:12:47

And that's just in terms of correctness. There's also general performance and/or per-database specific-features (MySQL vs Postgres, for example) that you might want to use.

Yehonathan Sharvit12:12:57

@cgrand How does this topic relate to your "map fatigue" idea?

cgrand12:12:17

Spot on: it's about relational/hierarchical mismatch which to me has two factors: • a border between db and lang • Lang not being relational

cgrand12:12:11

The most common pain to me is that when you need to retrieve an additional piece of data like an extra field you have to modify the query and the shaping code (map juggling).

cgrand12:12:50

These days I'm thinking about templating-as-querying where by templating I mean the process of turning relational data in hierarchical data – with more control on the output shape than what pull queries allow.

borkdude12:12:47

> you need to retrieve an additional piece of data like an extra field you have to modify the query and the shaping code this problem is solved for me by honeysql completely

Yehonathan Sharvit12:12:50

And for me this problem is solved by graphql

cgrand13:12:36

If you walk the resulting DS you’ve lost 😄 Imagine the goal is to display (Flutter widgets, DOM, HTML, JSON, whatever) a list of physicians and for each physician a list of free slots for appointements. I’d like to infer the query from the “templating” code (even if shaping clj maps into JSON is seldomly seen as templating). The closer one can get to this feeling is by using datomic entities (the lazy associative thingies returned by d/entity).

mauricio.szabo13:12:18

For me the problem is partially solved by multiple solutions, but specially by HoneySQL and Pathom - both libraries that I'm using at BeeRecord

mauricio.szabo13:12:26

As for the BeeRecord, at the beginning yes, I was trying to port the good parts of SQL to Clojure. But then things became really complex and I wasn't sure that this code was correct or desirable anymore. So I focused on the second idea that I had - the walk namespace - where I wanted to focus on generating the right (INNER) JOINs for a specific data.

mauricio.szabo13:12:19

Using the example of @raspasov, if you want the list of "orders" that a "person" placed in the last 30 days, you could query for a person, then filter the orders. The "orders" table can be a direct join from "person", or not - it can be, for example, behind a join table for some reason. If we translate this to HoneySQL, you have a :select, a :where, and lots of noise. The idea of BeeRecord/walker is to remove the noise: (to-honey {:select [:person/name :order/number] :where [:> :order/placed-at a-month-ago]})

mauricio.szabo13:12:07

This will generate one query. And that's the issue (because if the user placed multiple orders, the :person/name will be returned multiple times). Then Pathom3 got stable, and I'm currently working on making the less number of queries possible to retrieve the data. So for example, this is the API for bee-record.sql for now:

(query [:person/name {'(:person/order {:where [:> :order/placed-at a-month-ago]})
                       [:order/number]}])
The code above is just an EQL query, with honeySQL fragments when you need to filter for things.

Ivan09:12:04

> the `:user/name` will be returned multiple times you mean the :person/name

mauricio.szabo20:12:10

Yes, fixed. Thanks 🙂

mauricio.szabo13:12:12

Now for the issues I'm having: first, I'm not really happy with the :person/order subkey - I want it to be more configurable, so I'm studying alternatives. The most problematic issue is that they have to be unique over the whole query because they will be queried by batches. The second problem is that the current implementation expects the :person/order key is in the format of FROM/TO, and I want to remove "conventions" and allow the user to define what he wants the association data to be named

cgrand16:12:28

What I have in mind is something like:

(xx/deft last-30-days-orders [user-id]
  [:div
   [:div (:user/first-name user-id) "'s orders:"]
   [:ul
    (xx/for [#order {:owner user-id
                     :placed-at t
                     :_/as order}
             (< thirty-days-ago t)]
      :sorted-by (> t)
      [:li (:order/number order)])]])
two or three years ago I had a working prototype in cljs

mauricio.szabo15:12:50

@cgrand but is it only for front-end developing? I'm not sure what I'm seeing at your code...

cgrand16:12:53

@mauricio.szabo you can read the above pseudo code either as server-side html gen or client-side reactive (my POC was client-side and it adds complexity but it was fun: event handlers where queries returning transaction data).

cgrand16:12:32

My point is that all kind of tree-building can be seen as a kind of templating and that we should strive to stay in the relational model as long as possible.

cgrand16:12:46

tree-building/walking is necessary for interop with the outside (including UI: interop with the human) but should be kept at the borders. Too much of our code budget is spent on hierarchical<->relational and hierarchical<->hierarchical transfos.

👍 1