From 202322f93d91b71e62b59534c1e2fb9a5b6023a5 Mon Sep 17 00:00:00 2001
From: Kamil Mielnik <kamil@kamilmielnik.com>
Date: Tue, 26 Nov 2024 23:48:21 +0700
Subject: [PATCH] Add stage-number parameter to NativeParameterDimensionTarget
 (#50494)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Add stage-number parameter to NativeParameterDimensionTarget

* Update unit test

* Recognize native query dimension parameters with stage-number

* Update test setup

---------

Co-authored-by: Tamás Benkő <tamas@metabase.com>
---
 .../dashboard-filters/parameters.cy.spec.js   |  6 +++++-
 .../v1/parameters/utils/targets.ts            |  3 ++-
 .../parameters/utils/mapping-options.ts       |  6 ++++--
 .../utils/mapping-options.unit.spec.js        |  6 +++++-
 .../driver/common/parameters/values.clj       | 19 +++++++++++++++++--
 5 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/e2e/test/scenarios/dashboard-filters/parameters.cy.spec.js b/e2e/test/scenarios/dashboard-filters/parameters.cy.spec.js
index f5ec58ddb9d..b88bfb94274 100644
--- a/e2e/test/scenarios/dashboard-filters/parameters.cy.spec.js
+++ b/e2e/test/scenarios/dashboard-filters/parameters.cy.spec.js
@@ -298,7 +298,11 @@ describe("scenarios > dashboard > parameters", () => {
               {
                 parameter_id: matchingFilterType.id,
                 card_id,
-                target: ["dimension", ["template-tag", "filter"]],
+                target: [
+                  "dimension",
+                  ["template-tag", "filter"],
+                  { "stage-number": 0 },
+                ],
               },
             ],
           },
diff --git a/frontend/src/metabase-lib/v1/parameters/utils/targets.ts b/frontend/src/metabase-lib/v1/parameters/utils/targets.ts
index fb3f8eb5fc7..d249f819a1e 100644
--- a/frontend/src/metabase-lib/v1/parameters/utils/targets.ts
+++ b/frontend/src/metabase-lib/v1/parameters/utils/targets.ts
@@ -127,8 +127,9 @@ export function getParameterTargetField(
 
 export function buildDimensionTarget(
   dimension: TemplateTagDimension,
+  stageIndex: number,
 ): NativeParameterDimensionTarget {
-  return ["dimension", dimension.mbql()];
+  return ["dimension", dimension.mbql(), { "stage-number": stageIndex }];
 }
 
 export function buildColumnTarget(
diff --git a/frontend/src/metabase/parameters/utils/mapping-options.ts b/frontend/src/metabase/parameters/utils/mapping-options.ts
index 4bc142f0d78..83aa8ac02f1 100644
--- a/frontend/src/metabase/parameters/utils/mapping-options.ts
+++ b/frontend/src/metabase/parameters/utils/mapping-options.ts
@@ -64,6 +64,7 @@ function buildStructuredQuerySectionOptions(
 
 function buildNativeQuerySectionOptions(
   section: DimensionOptionsSection,
+  stageIndex: number,
 ): NativeParameterMappingOption[] {
   return section.items
     .flatMap(({ dimension }) =>
@@ -73,7 +74,7 @@ function buildNativeQuerySectionOptions(
       name: dimension.displayName(),
       icon: dimension.icon() ?? "",
       isForeign: false,
-      target: buildDimensionTarget(dimension),
+      target: buildDimensionTarget(dimension, stageIndex),
     }));
 }
 
@@ -184,6 +185,7 @@ export function getParameterMappingOptions(
 
   const legacyQuery = question.legacyQuery();
   const options: NativeParameterMappingOption[] = [];
+  const stageIndex = Lib.stageCount(question.query()) - 1;
 
   options.push(
     ...legacyQuery
@@ -196,7 +198,7 @@ export function getParameterMappingOptions(
         parameter ? dimensionFilterForParameter(parameter) : undefined,
       )
       .sections()
-      .flatMap(section => buildNativeQuerySectionOptions(section)),
+      .flatMap(section => buildNativeQuerySectionOptions(section, stageIndex)),
   );
 
   return options;
diff --git a/frontend/src/metabase/parameters/utils/mapping-options.unit.spec.js b/frontend/src/metabase/parameters/utils/mapping-options.unit.spec.js
index 5b5ef144dd4..d365641447b 100644
--- a/frontend/src/metabase/parameters/utils/mapping-options.unit.spec.js
+++ b/frontend/src/metabase/parameters/utils/mapping-options.unit.spec.js
@@ -357,7 +357,11 @@ describe("parameters/utils/mapping-options", () => {
         {
           name: "Created At",
           icon: "calendar",
-          target: ["dimension", ["template-tag", "created"]],
+          target: [
+            "dimension",
+            ["template-tag", "created"],
+            { "stage-number": 0 },
+          ],
           isForeign: false,
         },
       ]);
diff --git a/src/metabase/driver/common/parameters/values.clj b/src/metabase/driver/common/parameters/values.clj
index 6bb9c977f71..2b88639b16f 100644
--- a/src/metabase/driver/common/parameters/values.clj
+++ b/src/metabase/driver/common/parameters/values.clj
@@ -95,13 +95,28 @@
     #{[target-type [:template-tag (:name tag)]]
       [target-type [:template-tag {:id (:id tag)}]]}))
 
+(defn- tag-target-pred
+  "Returns a predicate recognizing parameter targets pointing to `tag`."
+  [tag]
+  (let [targets (tag-targets tag)]
+    (fn tag-target? [param-target]
+      (and (vector? param-target)
+           (> (count param-target) 1)
+           (targets (subvec param-target 0 2))
+           ;; legacy dimension params come without stage-number, 0 is the default
+           (= (get-in param-target [2 :stage-number] 0)
+              ;; Currently, we have no multi-stage native queries, so the stage-number is always 0.
+              ;; If in the future we introduce such queries, we can specify the stage-number of tags
+              ;; and they should match the stage-number of the parameter target.
+              (get tag :stage-number 0))))))
+
 (mu/defn- tag-params
   "Return params from the provided `params` list targeting the provided `tag`."
   [tag    :- mbql.s/TemplateTag
    params :- [:maybe [:sequential mbql.s/Parameter]]]
-  (let [targets (tag-targets tag)]
+  (let [tag-target? (tag-target-pred tag)]
     (seq (for [param params
-               :when (contains? targets (:target param))]
+               :when (tag-target? (:target param))]
            param))))
 
 ;;; FieldFilter Params (Field Filters) (e.g. WHERE {{x}})
-- 
GitLab