Adds a simple Entry points:
Requirements:
Query transformation:
Question transformation: - None | (ns metabase.lib.drill-thru.fk-filter (:require [metabase.lib.aggregation :as lib.aggregation] [metabase.lib.drill-thru.common :as lib.drill-thru.common] [metabase.lib.filter :as lib.filter] [metabase.lib.metadata :as lib.metadata] [metabase.lib.metadata.calculation :as lib.metadata.calculation] [metabase.lib.options :as lib.options] [metabase.lib.schema :as lib.schema] [metabase.lib.schema.drill-thru :as lib.schema.drill-thru] [metabase.lib.stage :as lib.stage] [metabase.lib.types.isa :as lib.types.isa] [metabase.lib.util :as lib.util] [metabase.util.malli :as mu])) |
(mu/defn fk-filter-drill :- [:maybe ::lib.schema.drill-thru/drill-thru.fk-filter] "When clicking on a foreign key value, filter this query by that column. This has the same effect as the `=` filter on a generic field (ie. not a key), but renders differently. Contrast [[metabase.lib.drill-thru.object-details/object-detail-drill]], which shows the details of the foreign object." [query :- ::lib.schema/query stage-number :- :int {:keys [column column-ref value], :as _context} :- ::lib.schema.drill-thru/context] (when (and column (some? value) (not= value :null) ; If the FK is null, don't show this option. (lib.drill-thru.common/mbql-stage? query stage-number) (not (lib.types.isa/primary-key? column)) (lib.types.isa/foreign-key? column)) (let [source (or (some->> query lib.util/source-table-id (lib.metadata/table query)) (some->> query lib.util/source-card-id (lib.metadata/card query)))] {:lib/type :metabase.lib.drill-thru/drill-thru :type :drill-thru/fk-filter :filter (lib.options/ensure-uuid [:= {} column-ref value]) :column-name (lib.metadata.calculation/display-name query stage-number column :long) :table-name (lib.metadata.calculation/display-name query 0 source)}))) | |
(defmethod lib.drill-thru.common/drill-thru-info-method :drill-thru/fk-filter [_query _stage-number drill-thru] (select-keys drill-thru [:type :column-name :table-name])) | |
(mu/defmethod lib.drill-thru.common/drill-thru-method :drill-thru/fk-filter :- ::lib.schema/query [query :- ::lib.schema/query stage-number :- :int drill-thru :- ::lib.schema.drill-thru/drill-thru.fk-filter & _args] ;; If the stage in question is an MBQL stage, we can simply add a `=` filter to it. ;; If it's a native stage, we have to apply the drill to the stage after that stage, which will be an MBQL stage, ;; adding it if needed (native stages are currently only allowed to be the first stage.) ;; Similarly if the query contains aggregations we will have to add a new stage to do the filtering. (let [[query stage-number] (if (lib.drill-thru.common/mbql-stage? query stage-number) ;; MBQL stage - append a stage if there are aggregations (if (seq (lib.aggregation/aggregations query stage-number)) (lib.stage/ensure-extra-stage query stage-number) [query stage-number]) ;; native stage - append an MBQL stage (let [;; convert the stage number e.g. `-1` to the canonical non-relative stage number stage-number (lib.util/canonical-stage-index query stage-number) ;; make sure the query has at least one MBQL stage after the native stage, which we ;; know is the first stage. query (lib.util/ensure-mbql-final-stage query) next-stage-number (lib.util/next-stage-number query stage-number)] (assert (lib.util/query-stage query next-stage-number) "Sanity check: there should be an additional stage by now") [query next-stage-number]))] (lib.filter/filter query stage-number (:filter drill-thru)))) | |