diff options
Diffstat (limited to 'src/clojure_sql')
| -rw-r--r-- | src/clojure_sql/dsl.clj | 30 | 
1 files changed, 25 insertions, 5 deletions
| diff --git a/src/clojure_sql/dsl.clj b/src/clojure_sql/dsl.clj index 16bc2e5..413b9c0 100644 --- a/src/clojure_sql/dsl.clj +++ b/src/clojure_sql/dsl.clj @@ -61,6 +61,10 @@                     :right right                     :type type }))) +(defn ^:private not-a-function-expression [expr] +  (throw (ex-info "Expr is not a function application - could not possibly be an aggregate" +                  {:expr expr}))) +  (defn ^:private invalid-union [queries]    (throw (ex-info "Cannot union queries with different fields"                    {:queries queries}))) @@ -326,19 +330,35 @@  (defn group    "Apply a grouping to a query. -  `fields` is a sequential collection of fields to group by. +  `fields` is a collection of fields to group by. `projection` is a +  map with which to perform a projection. + +  The projection must perform an aggregate function on each +  non-grouped field, or else the resulting group is invalid. This is +  not verifiable without knowing the full set of aggregate +  functions (which is not possible in general), so any projection will +  be accepted as long as a function is called as a part of each +  projection.    If the query has already been grouped then this will create a    subquery." -  [query fields] +  [query fields projection]    (let [query (if (:group query)                  (convert-to-subquery query)                  query)          fields-seq (if (sequential? fields)                       fields -                     [fields])] -    (assoc query :group (map (partial resolve-field (:tables query) (:fields query)) -                             fields-seq)))) +                     [fields]) +        fields-map (into {} (map vector fields fields))] +    (doseq [[expr name] projection] +      (try (or (some #{expr} fields-seq) +               (seq expr)) +           (catch Exception e +             (not-a-function-expression expr)))) +    (-> query +        (assoc :group (map (partial resolve-field (:tables query) (:fields query)) +                           fields-seq)) +        (project (into fields-map projection)))))  (defn take    "Limit the number of results of a query. | 
