Skip to content

Commit

Permalink
QP refactor part 7 [WIP] [ci skip]
Browse files Browse the repository at this point in the history
  • Loading branch information
camsaul committed Sep 26, 2018
1 parent 0b58d20 commit dd0ebfd
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 11 deletions.
5 changes: 4 additions & 1 deletion src/metabase/mbql/schema.clj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Schema for an MBQL datetime string literal, in ISO-8601 format."
(s/constrained su/NonBlankString du/date-string? "datetime-literal"))

;; TODO - `unit` is not allowed if `n` is `current`
(defclause relative-datetime
n (s/cond-pre (s/eq :current) s/Int)
unit (optional RelativeDatetimeUnit))
Expand Down Expand Up @@ -74,10 +75,11 @@
(def ^:private BinningStrategyName
(s/enum :num-bins :bin-width :default))

;; TODO - binning strategy is disallowed for `:default` and required for the others
(defclause binning-strategy
field (one-of field-id field-literal fk-> expression datetime-field)
strategy-name BinningStrategyName
strategy-param (optional s/Num))
strategy-param (optional (s/constrained s/Num (complement neg?) "strategy param must be >= 0.")))

(def Field
"Schema for anything that refers to a Field, from the common `[:field-id <id>]` to variants like `:datetime-field` or
Expand Down Expand Up @@ -245,6 +247,7 @@
"Schema for things that make sense in a filter like `>` or `<`, i.e. things that can be sorted."
(s/cond-pre
s/Num
s/Str
DatetimeLiteral
FieldOrRelativeDatetime))

Expand Down
23 changes: 13 additions & 10 deletions src/metabase/query_processor/middleware/binning.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
[metabase
[public-settings :as public-settings]
[util :as u]]
[metabase.query-processor.util :as qputil])
(:import [metabase.query_processor.interface BetweenFilter BinnedField ComparisonFilter]))
[metabase.mbql.util :as mbql.u]
[metabase.query-processor.util :as qputil]))

(defn- update!
"Similar to `clojure.core/update` but works on transient maps"
[^clojure.lang.ITransientAssociative coll k f]
(assoc! coll k (f (get coll k))))

(defn- filter->field-map
"A bit of a stateful hack using clojure.walk/prewalk to find any comparison or between filter. This should be replaced
by a zipper for a more functional/composable approach to this problem."
"Find any comparison or `:between` filter. AND...?" ; TODO
[mbql-filter]
(for [filter-clause (mbql.u/clause-instances #{:between :< :<= :> :>=} mbql-filter)
field-id-clauses (mbql.u/clause-instances #{:field-id} filter)])
(let [filters ])
(let [acc (transient {})]
(walk/prewalk
(fn [x]
Expand Down Expand Up @@ -155,14 +157,15 @@
;; nice version.
(or (nicer-breakout resolved-binned-field) resolved-binned-field))))

(defn update-binning-strategy* [query]
(let [filter-field-map (filter->field-map (get-in query [:query :filter]))]
(qputil/postwalk-pred #(instance? BinnedField %)
#(update-binned-field % filter-field-map)
query)))

(defn update-binning-strategy
"When a binned field is found, it might need to be updated if a relevant query criteria affects the min/max value of
the binned field. This middleware looks for that criteria, then updates the related min/max values and calculates
the bin-width based on the criteria values (or global min/max information)."
[qp]
(fn [query]
(let [filter-field-map (filter->field-map (get-in query [:query :filter]))]
(qp
(qputil/postwalk-pred #(instance? BinnedField %)
#(update-binned-field % filter-field-map)
query)))))
(comp qp update-binning-strategy*))

0 comments on commit dd0ebfd

Please sign in to comment.