"Zoom" transform for numeric (including location) columns. Entry points:
Requirements:
Query transformation:
Question transformation:
This covers two types of 'zoom in' drills:
| (ns metabase.lib.drill-thru.zoom-in-bins (:require [metabase.lib.binning :as lib.binning] [metabase.lib.breakout :as lib.breakout] [metabase.lib.drill-thru.common :as lib.drill-thru.common] [metabase.lib.equality :as lib.equality] [metabase.lib.filter :as lib.filter] [metabase.lib.remove-replace :as lib.remove-replace] [metabase.lib.schema :as lib.schema] [metabase.lib.schema.binning :as lib.schema.binning] [metabase.lib.schema.drill-thru :as lib.schema.drill-thru] [metabase.lib.schema.metadata :as lib.schema.metadata] [metabase.lib.underlying :as lib.underlying] [metabase.util.malli :as mu])) |
available-drill-thrus | |
(mu/defn zoom-in-binning-drill :- [:maybe ::lib.schema.drill-thru/drill-thru.zoom-in.binning] "Return a drill thru that 'zooms in' on a breakout that uses `:binning` if applicable. See [[metabase.lib.drill-thru.zoom-in-bins]] docstring for more information." [query :- ::lib.schema/query _stage-number :- :int {:keys [column value], :as _context} :- ::lib.schema.drill-thru/context] (when (and column value (not= value :null)) (when-let [existing-breakout (first (lib.breakout/existing-breakouts query (lib.underlying/top-level-stage-number query) column))] (when-let [binning (lib.binning/binning existing-breakout)] (when-let [{:keys [min-value max-value bin-width]} ;; If the column has binning options, use those; otherwise, check the top-level-column. (or (lib.binning/resolve-bin-width query column value) (lib.binning/resolve-bin-width query ;; One of the "superflous" options is ::lib.field/binning, which we want to preserve here. (lib.underlying/top-level-column query column :rename-superflous-options? false) value))] (case (:strategy binning) (:num-bins :default) {:lib/type :metabase.lib.drill-thru/drill-thru :type :drill-thru/zoom-in.binning :column column :min-value value :max-value (+ value bin-width) :new-binning {:strategy :default}} :bin-width {:lib/type :metabase.lib.drill-thru/drill-thru :type :drill-thru/zoom-in.binning :column column :min-value min-value :max-value max-value :new-binning (update binning :bin-width #(double (/ % 10.0)))})))))) | |
application | |
(mu/defn- update-breakout :- ::lib.schema/query [query :- ::lib.schema/query stage-number :- :int old-column :- ::lib.schema.metadata/column new-column :- ::lib.schema.metadata/column new-binning :- ::lib.schema.binning/binning] (if-let [existing-breakout (first (lib.breakout/existing-breakouts query stage-number old-column))] (lib.remove-replace/replace-clause query stage-number existing-breakout (lib.binning/with-binning new-column new-binning)) (lib.breakout/breakout query stage-number (lib.binning/with-binning new-column new-binning)))) | |
(mu/defmethod lib.drill-thru.common/drill-thru-method :drill-thru/zoom-in.binning :- ::lib.schema/query [query :- ::lib.schema/query stage-number :- :int {:keys [column min-value max-value new-binning]} :- ::lib.schema.drill-thru/drill-thru.zoom-in.binning] ;; We add and remove filters on the last stage rather than top-level-stage-number because that is ;; where [[metabase.query-processor.middleware.binning/update-binning-strategy]] expects to find them. Adding the ;; filters to top-level-stage-number breaks the binning. (let [top-level-stage-number (lib.underlying/top-level-stage-number query) resolved-column (lib.drill-thru.common/breakout->resolved-column query stage-number column) old-filters (filter (fn [[operator _opts filter-column]] (and (#{:>= :<} operator) (lib.equality/find-matching-column filter-column [column]))) (lib.filter/filters query stage-number))] (-> (reduce #(lib.remove-replace/remove-clause %1 stage-number %2) query old-filters) (update-breakout top-level-stage-number column resolved-column new-binning) (lib.filter/filter stage-number (lib.filter/>= resolved-column min-value)) (lib.filter/filter stage-number (lib.filter/< resolved-column max-value))))) | |