"See this month by weeks" type of transform. Entry points:
Requirements:
Query transformation:
Question transformation:
| (ns metabase.lib.drill-thru.zoom-in-timeseries (:require [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.common :as lib.schema.common] [metabase.lib.schema.drill-thru :as lib.schema.drill-thru] [metabase.lib.schema.temporal-bucketing :as lib.schema.temporal-bucketing] [metabase.lib.temporal-bucket :as lib.temporal-bucket] [metabase.lib.underlying :as lib.underlying] [metabase.lib.util :as lib.util] [metabase.util.i18n :as i18n] [metabase.util.malli :as mu])) |
(mu/defn- valid-current-units :- [:sequential ::lib.schema.temporal-bucketing/unit.date-time.truncate] [query :- ::lib.schema/query stage :- :int field :- :mbql.clause/field] (->> (lib.temporal-bucket/available-temporal-buckets query stage field) (map lib.temporal-bucket/raw-temporal-bucket) (filter lib.schema.temporal-bucketing/datetime-truncation-units) reverse)) | |
(mu/defn- matching-breakout-dimension :- [:maybe ::lib.schema.drill-thru/context.row.value] [query :- ::lib.schema/query stage-number :- :int dimensions :- [:sequential ::lib.schema.drill-thru/context.row.value]] (first (for [[breakout-ref breakout-col] (map vector (lib.breakout/breakouts query stage-number) (lib.breakout/breakouts-metadata query stage-number)) :when (and (lib.util/clause-of-type? breakout-ref :field) (lib.temporal-bucket/temporal-bucket breakout-ref)) {:keys [column] :as dimension} dimensions :when (and (lib.equality/find-matching-column breakout-ref [column]) (= (lib.temporal-bucket/raw-temporal-bucket breakout-ref) (or (lib.temporal-bucket/raw-temporal-bucket column) ;; If query is multi-stage and column comes from a call ;; to [[lib.calculation/returned-columns]], then it may have an ;; :inherited-temporal-unit instead of a :temporal-unit. (:inherited-temporal-unit column))))] ;; If stage-number is not -1, then the column from the input dimension will be from the last stage, ;; whereas breakout-col will be the corresponding breakout column from [[lib.underlying/top-level-stage]]. (assoc dimension :column breakout-col :column-ref breakout-ref)))) | |
(mu/defn- next-breakout-unit :- [:maybe ::lib.schema.drill-thru/drill-thru.zoom-in.timeseries.next-unit] [query :- ::lib.schema/query stage :- :int field :- :mbql.clause/field] (when-let [current-unit (lib.temporal-bucket/raw-temporal-bucket field)] (->> (valid-current-units query stage field) (drop-while #(not= % current-unit)) second))) | |
(mu/defn- describe-next-unit :- ::lib.schema.common/non-blank-string [unit :- ::lib.schema.drill-thru/drill-thru.zoom-in.timeseries.next-unit] (case unit :quarter (i18n/tru "See this year by quarter") :month (i18n/tru "See this quarter by month") :week (i18n/tru "See this month by week") :day (i18n/tru "See this week by day") :hour (i18n/tru "See this day by hour") :minute (i18n/tru "See this hour by minute"))) | |
(mu/defn zoom-in-timeseries-drill :- [:maybe ::lib.schema.drill-thru/drill-thru.zoom-in.timeseries] "Zooms in on some window, showing it in finer detail. For example: The month of a year, days or weeks of a quarter, smaller lat/long regions, etc. This is different from the `:drill-thru/zoom` type, which is for showing the details of a single object." [query :- ::lib.schema/query _stage-number :- :int {:keys [dimensions], :as _context} :- ::lib.schema.drill-thru/context] ;; For multi-stage queries, we want the stage-number of the underlying stage with breakouts or aggregations. (let [stage-number (lib.underlying/top-level-stage-number query)] (when (and (lib.drill-thru.common/mbql-stage? query stage-number) dimensions) (when-let [{:keys [value column-ref], :as dimension} (matching-breakout-dimension query stage-number dimensions)] (when value (when-let [next-unit (next-breakout-unit query stage-number column-ref)] {:lib/type :metabase.lib.drill-thru/drill-thru :display-name (describe-next-unit next-unit) :type :drill-thru/zoom-in.timeseries :dimension dimension :next-unit next-unit})))))) | |
(mu/defmethod lib.drill-thru.common/drill-thru-method :drill-thru/zoom-in.timeseries [query :- ::lib.schema/query _stage-number :- :int {:keys [dimension next-unit]} :- ::lib.schema.drill-thru/drill-thru.zoom-in.timeseries] (let [{:keys [column value]} dimension old-breakout (:column-ref dimension) new-breakout (lib.temporal-bucket/with-temporal-bucket old-breakout next-unit) stage-number (lib.underlying/top-level-stage-number query) resovled-column (lib.drill-thru.common/breakout->resolved-column query stage-number column)] (-> query (lib.filter/filter stage-number (lib.filter/= resovled-column value)) (lib.remove-replace/replace-clause stage-number old-breakout new-breakout)))) | |