Object details drill for cases when there is multiple PK columns. Entry points:
Requirements:
Query transformation:
Question transformation:
A We will only possibly return one of the 'object details' drills ([[metabase.lib.drill-thru.pk]], [[metabase.lib.drill-thru.fk-details]], or [[metabase.lib.drill-thru.zoom]]); see [[metabase.lib.drill-thru.object-details]] for the high-level logic that calls out to the individual implementations. | (ns metabase.lib.drill-thru.pk (:require [medley.core :as m] [metabase.lib.drill-thru.common :as lib.drill-thru.common] [metabase.lib.filter :as lib.filter] [metabase.lib.metadata.calculation :as lib.metadata.calculation] [metabase.lib.schema :as lib.schema] [metabase.lib.schema.drill-thru :as lib.schema.drill-thru] [metabase.lib.types.isa :as lib.types.isa] [metabase.util.malli :as mu])) |
(mu/defn pk-drill :- [:maybe ::lib.schema.drill-thru/drill-thru.pk]
"'View details' drill when you click on a value in a table that has MULTIPLE PKs. There are two subtypes of PK
drills:
1) if you click on a PK column value, then we return a drill that will add a filter for that PK column/value
2) if you click a non-PK column value, then we return a drill that will add filters for the PK columns/values in the
row. This is never returned for FK columns; we return [[metabase.lib.drill-thru.fk-details]] drills instead."
[query :- ::lib.schema/query
stage-number :- :int
{:keys [column value row] :as _context} :- ::lib.schema.drill-thru/context]
(when (and
;; ignore column header clicks (value = nil). NULL values (value = :null) are ok if this is a click on a
;; non-PK column.
(some? value)
(lib.drill-thru.common/mbql-stage? query stage-number)
;; `:pk` drills are only for Tables with multiple PKs. For Tables with one PK, we do
;; a [[metabase.lib.drill-thru.zoom]] drill instead.
(lib.drill-thru.common/many-pks? query)
;; if this is an FK column we should return an [[metabase.lib.drill-thru.fk-details]] drill instead.
(not (lib.types.isa/foreign-key? column)))
(if (lib.types.isa/primary-key? column)
;; 1) we clicked on a PK column: return a drill thru for that PK column + value. Ignore `nil` values.
(when (and (some? value)
(not= value :null))
{:lib/type :metabase.lib.drill-thru/drill-thru
:type :drill-thru/pk
:dimensions [{:column column
:value value}]})
;; 2) we clicked on a non-PK column: return a drill for ALL of the PK columns + values. Ignore any
;; `nil` (`:null`) values.
(let [pk-columns (lib.metadata.calculation/primary-keys query)
dimensions (for [pk-column pk-columns
:let [value (->> row
(m/find-first #(-> % :column :name (= (:name pk-column))))
:value)]
;; ignore any PKs that don't have a value in this row.
:when value]
{:column pk-column, :value value})]
(when (seq dimensions)
{:lib/type :metabase.lib.drill-thru/drill-thru
:type :drill-thru/pk
;; return the dimensions sorted by column ID so the return value is determinate.
:dimensions (vec (sort-by #(get-in % [:column :id]) dimensions))}))))) | |
(defmethod lib.drill-thru.common/drill-thru-info-method :drill-thru/pk [_query _stage-number drill-thru] (select-keys drill-thru [:type :dimensions])) | |
(defmethod lib.drill-thru.common/drill-thru-method :drill-thru/pk
[query stage-number {:keys [dimensions], :as _pk-drill}]
(reduce
(fn [query {:keys [column value], :as _dimension}]
(lib.filter/filter query stage-number (lib.filter/= column value)))
query
dimensions)) | |