korma / Korma

Tasty SQL for Clojure.
http://sqlkorma.com
1.47k stars 222 forks source link

Count by relationship #264

Closed dvcrn closed 9 years ago

dvcrn commented 9 years ago

Hey,

I ran into a usecase where I need to count the elements of a relationship. I read through the documentation but couldn't find a way to achieve this behavior:

Entities:

(defentity poll
  (belongs-to user)
  (has-many choice))

(defentity choice
  (belongs-to poll)
  (has-many vote))

(defentity vote
  (belongs-to user)
  (belongs-to choice))

Query:

(first
  (select e/poll
          (with e/choice
            (with e/vote
              (aggregate (count :*) :votes))) ; <--- counting all votes for each choice object here
          (with e/user
            (fields :username))
          (where (= :poll.id (int poll_id)))
          (limit 1)))

Result:

choice: [
    {
        vote: [
            {
                votes: 0
            }
        ],
        description: "Something",
        poll_id: 1,
        id: 1
    },
    ...
]

What bugs me here is that votes is inside an array under 'vote', since it's inside the (with) block. I have no chance to tell korma to just count and alias the result (or so I think).

For my usecase, I wrote a little map function which cleans up the result for further use:

(map #(dissoc (assoc % :votes ((first (% :vote)) :votes))
                  :vote) (query-result :choice))

It'd be great to have something like this directly in korma. Apologies if I've overseen this.

immoh commented 9 years ago

You're correct, there's no way to tell Korma to flatten the results for 'vote' join.

I don't think it would be beneficial to have functionality to handle this kind of cases automatically, I think is actually better that structure of the return values is consistent and doesn't vary case by case. Transform functions (like yours) can be used to change the structure.