Skip to content
Snippets Groups Projects
Unverified Commit a7e59b98 authored by Alexander Polyankin's avatar Alexander Polyankin Committed by GitHub
Browse files

Expect broken field refs in filter drills (#46691)

* Handle column matching errors

* Fix test

* Fix test

* Fix test

* Fix test

* Fix test
parent 2cf4f2d4
No related branches found
No related tags found
No related merge requests found
...@@ -45,11 +45,12 @@ ...@@ -45,11 +45,12 @@
(nil? value) (nil? value)
(lib.drill-thru.common/mbql-stage? query stage-number)) (lib.drill-thru.common/mbql-stage? query stage-number))
(when-let [drill (column-extract-drill-for-column query column)] (when-let [drill (column-extract-drill-for-column query column)]
(merge drill (when-let [drill-details (lib.drill-thru.column-filter/prepare-query-for-drill-addition
{:lib/type :metabase.lib.drill-thru/drill-thru query stage-number column column-ref :expression)]
:type :drill-thru/column-extract} (merge drill
(lib.drill-thru.column-filter/prepare-query-for-drill-addition drill-details
query stage-number column column-ref :expression))))) {:lib/type :metabase.lib.drill-thru/drill-thru
:type :drill-thru/column-extract})))))
(mu/defn extractions-for-drill :- [:sequential ::lib.schema.extraction/extraction] (mu/defn extractions-for-drill :- [:sequential ::lib.schema.extraction/extraction]
"Returns the extractions from a given drill." "Returns the extractions from a given drill."
......
...@@ -39,10 +39,10 @@ ...@@ -39,10 +39,10 @@
[metabase.lib.util :as lib.util] [metabase.lib.util :as lib.util]
[metabase.util.malli :as mu])) [metabase.util.malli :as mu]))
(mu/defn prepare-query-for-drill-addition :- [:map (mu/defn prepare-query-for-drill-addition :- [:maybe [:map
[:query ::lib.schema/query] [:query ::lib.schema/query]
[:stage-number :int] [:stage-number :int]
[:column lib.filter/ColumnWithOperators]] [:column lib.filter/ColumnWithOperators]]]
"If the column we're filtering on is an aggregation, the filtering must happen in a later stage. This function returns "If the column we're filtering on is an aggregation, the filtering must happen in a later stage. This function returns
a map with that possibly-updated `:query` and `:stage-number`, plus the `:column` for filtering in that stage (with a map with that possibly-updated `:query` and `:stage-number`, plus the `:column` for filtering in that stage (with
filter operators, as returned by [[lib.filter/filterable-columns]]). filter operators, as returned by [[lib.filter/filterable-columns]]).
...@@ -85,7 +85,9 @@ ...@@ -85,7 +85,9 @@
(and (:lib/source-uuid column) (and (:lib/source-uuid column)
(m/find-first #(= (:lib/source-uuid %) (:lib/source-uuid column)) (m/find-first #(= (:lib/source-uuid %) (:lib/source-uuid column))
columns)))] columns)))]
(assoc base :column filter-column))) ;; If we cannot find the matching column, don't allow to drill
(when filter-column
(assoc base :column filter-column))))
(mu/defn column-filter-drill :- [:maybe ::lib.schema.drill-thru/drill-thru.column-filter] (mu/defn column-filter-drill :- [:maybe ::lib.schema.drill-thru/drill-thru.column-filter]
"Filtering at the column level, based on its type. Displays a submenu of eg. \"Today\", \"This Week\", etc. for date "Filtering at the column level, based on its type. Displays a submenu of eg. \"Today\", \"This Week\", etc. for date
...@@ -96,22 +98,21 @@ ...@@ -96,22 +98,21 @@
[query :- ::lib.schema/query [query :- ::lib.schema/query
stage-number :- :int stage-number :- :int
{:keys [column column-ref value]} :- ::lib.schema.drill-thru/context] {:keys [column column-ref value]} :- ::lib.schema.drill-thru/context]
;; Note: original code uses an addition `clicked.column.field_ref != null` condition.
(when (and (lib.drill-thru.common/mbql-stage? query stage-number) (when (and (lib.drill-thru.common/mbql-stage? query stage-number)
column column
(nil? value) (nil? value)
(not (lib.types.isa/structured? column))) (not (lib.types.isa/structured? column)))
(let [initial-op (when-not (lib.types.isa/temporal? column) ; Date fields have special handling in the FE. ;; When the column we would be filtering on is an aggregation, it can't be filtered without adding a stage.
(-> (lib.filter.operator/filter-operators column) (when-let [drill-details (prepare-query-for-drill-addition query stage-number column column-ref :filter)]
first (let [initial-op (when-not (lib.types.isa/temporal? column) ; Date fields have special handling in the FE.
(assoc :lib/type :operator/filter)))] (-> (lib.filter.operator/filter-operators column)
first
(merge (assoc :lib/type :operator/filter)))]
{:lib/type :metabase.lib.drill-thru/drill-thru (merge
:type :drill-thru/column-filter drill-details
:initial-op initial-op} {:lib/type :metabase.lib.drill-thru/drill-thru
;; When the column we would be filtering on is an aggregation, it can't be filtered without adding a stage. :type :drill-thru/column-filter
(prepare-query-for-drill-addition query stage-number column column-ref :filter))))) :initial-op initial-op})))))
(defmethod lib.drill-thru.common/drill-thru-info-method :drill-thru/column-filter (defmethod lib.drill-thru.common/drill-thru-info-method :drill-thru/column-filter
[_query _stage-number {:keys [initial-op]}] [_query _stage-number {:keys [initial-op]}]
......
...@@ -120,13 +120,13 @@ ...@@ -120,13 +120,13 @@
(not (lib.types.isa/foreign-key? column))) (not (lib.types.isa/foreign-key? column)))
;; For aggregate columns, we want to introduce a new stage when applying the drill-thru. ;; For aggregate columns, we want to introduce a new stage when applying the drill-thru.
;; [[lib.drill-thru.column-filter/prepare-query-for-drill-addition]] handles this. (#34346) ;; [[lib.drill-thru.column-filter/prepare-query-for-drill-addition]] handles this. (#34346)
(let [adjusted (lib.drill-thru.column-filter/prepare-query-for-drill-addition (when-let [drill-details (lib.drill-thru.column-filter/prepare-query-for-drill-addition
query stage-number column column-ref :filter)] query stage-number column column-ref :filter)]
(merge {:lib/type :metabase.lib.drill-thru/drill-thru (merge drill-details
{:lib/type :metabase.lib.drill-thru/drill-thru
:type :drill-thru/quick-filter :type :drill-thru/quick-filter
:operators (operators-for (:column adjusted) value) :operators (operators-for (:column drill-details) value)
:value value} :value value}))))
adjusted))))
(defmethod lib.drill-thru.common/drill-thru-info-method :drill-thru/quick-filter (defmethod lib.drill-thru.common/drill-thru-info-method :drill-thru/quick-filter
[_query _stage-number drill-thru] [_query _stage-number drill-thru]
......
...@@ -231,6 +231,17 @@ ...@@ -231,6 +231,17 @@
(lib/available-drill-thrus query -1) (lib/available-drill-thrus query -1)
(m/find-first #(= (:type %) :drill-thru/column-filter)))))))) (m/find-first #(= (:type %) :drill-thru/column-filter))))))))
(deftest ^:parallel column-filter-unavailable-for-broken-ref-test
(testing "do not return column filter drill when the corresponding filterable column cannot be found"
(let [query (lib/query meta/metadata-provider (meta/table-metadata :orders))
subtotal (m/find-first #(= (:name %) "SUBTOTAL") (lib/returned-columns query))]
(is (nil?
(->> {:column subtotal
:column-ref [:field {:lib/uuid (str (random-uuid))} 999]
:value nil}
(lib/available-drill-thrus query -1)
(m/find-first #(= (:type %) :drill-thru/column-filter))))))))
(deftest ^:parallel native-models-with-renamed-columns-test (deftest ^:parallel native-models-with-renamed-columns-test
(testing "Generate sane queries for native query models with renamed columns (#22715 #36583)" (testing "Generate sane queries for native query models with renamed columns (#22715 #36583)"
(let [metadata-provider (lib.tu/mock-metadata-provider (let [metadata-provider (lib.tu/mock-metadata-provider
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment