From 9a9216fc8ba31673dfe4846308a100fc87095dfb Mon Sep 17 00:00:00 2001
From: metamben <103100869+metamben@users.noreply.github.com>
Date: Thu, 24 Aug 2023 20:49:55 +0300
Subject: [PATCH] Add find-visible-column-for-legacy-ref (#33447)

---
 frontend/src/metabase-lib/fields.ts |  9 +++++++++
 src/metabase/lib/core.cljc          |  1 +
 src/metabase/lib/field.cljc         | 15 ++++++++++++++
 src/metabase/lib/js.cljs            |  9 +++++++++
 test/metabase/lib/field_test.cljc   | 31 +++++++++++++++++++++++++++++
 5 files changed, 65 insertions(+)

diff --git a/frontend/src/metabase-lib/fields.ts b/frontend/src/metabase-lib/fields.ts
index dc7f188a91a..dc5f52b2c1d 100644
--- a/frontend/src/metabase-lib/fields.ts
+++ b/frontend/src/metabase-lib/fields.ts
@@ -1,4 +1,5 @@
 import * as ML from "cljs/metabase.lib.js";
+import type { FieldReference } from "metabase-types/api";
 import type { Clause, ColumnMetadata, Query } from "./types";
 
 export function fields(query: Query, stageIndex: number): Clause[] {
@@ -30,3 +31,11 @@ export function fieldableColumns(
 export function _fieldId(column: ColumnMetadata): number | null {
   return ML.field_id(column);
 }
+
+export function findVisibleColumnForLegacyRef(
+  query: Query,
+  stageIndex: number,
+  fieldRef: FieldReference,
+): ColumnMetadata | null {
+  return ML.find_visible_column_for_legacy_ref(query, stageIndex, fieldRef);
+}
diff --git a/src/metabase/lib/core.cljc b/src/metabase/lib/core.cljc
index 3e5e9821d89..ae0befbcefe 100644
--- a/src/metabase/lib/core.cljc
+++ b/src/metabase/lib/core.cljc
@@ -148,6 +148,7 @@
   field-id
   fieldable-columns
   fields
+  find-visible-column-for-ref
   remove-field
   with-fields]
  [lib.filter
diff --git a/src/metabase/lib/field.cljc b/src/metabase/lib/field.cljc
index d6303d83c24..d303edcef8b 100644
--- a/src/metabase/lib/field.cljc
+++ b/src/metabase/lib/field.cljc
@@ -705,3 +705,18 @@
       :source/native              (throw (ex-info (native-query-fields-edit-error) {:query query :stage stage-number}))
       ;; Default case: do nothing and return the query unchaged.
       query)))
+
+(mu/defn find-visible-column-for-ref :- [:maybe lib.metadata/ColumnMetadata]
+  "Return the visible column in `query` at `stage-number` referenced by `field-ref`.
+  If `stage-number` is omitted, the last stage is used."
+  ([query field-ref]
+   (find-visible-column-for-ref query -1 field-ref))
+
+  ([query        :- ::lib.schema/query
+    stage-number :- :int
+    field-ref]
+   (let [stage (lib.util/query-stage query stage-number)
+         columns (lib.metadata.calculation/visible-columns query stage-number stage)
+         ref->col (zipmap (map lib.ref/ref columns) columns)
+         col-ref (lib.equality/find-closest-matching-ref query field-ref (keys ref->col))]
+     (ref->col col-ref))))
diff --git a/src/metabase/lib/js.cljs b/src/metabase/lib/js.cljs
index ef5966fc96e..ed78f6e11ca 100644
--- a/src/metabase/lib/js.cljs
+++ b/src/metabase/lib/js.cljs
@@ -427,6 +427,15 @@
   [a-query stage-number column]
   (lib.core/remove-field a-query stage-number column))
 
+(defn ^:export find-visible-column-for-legacy-ref
+  "Return the visible column in `a-query` at `stage-number` referenced by `legacy-ref`."
+  [a-query stage-number legacy-ref]
+  (let [ref (-> legacy-ref
+                (js->clj :keywordize-keys true)
+                (update 0 keyword)
+                convert/->pMBQL)]
+    (lib.core/find-visible-column-for-ref a-query stage-number ref)))
+
 (defn ^:export join-strategy
   "Get the strategy (type) of a given join as an opaque JoinStrategy object."
   [a-join]
diff --git a/test/metabase/lib/field_test.cljc b/test/metabase/lib/field_test.cljc
index 32284d50d6a..9f8993fa0ec 100644
--- a/test/metabase/lib/field_test.cljc
+++ b/test/metabase/lib/field_test.cljc
@@ -1251,3 +1251,34 @@
                     (lib/add-field    -1 (second columns))
                     (lib.util/query-stage -1)
                     :fields)))))))
+
+(deftest ^:parallel find-visible-column-for-ref-test
+  (testing "precise references"
+    (doseq [query-var [#'lib.tu/query-with-expression
+                       #'lib.tu/query-with-join-with-explicit-fields
+                       #'lib.tu/query-with-source-card]
+            :let [query @query-var]
+            col (lib/visible-columns query)
+            :let [col-ref (lib/ref col)]]
+      (testing (str "ref " col-ref " of " (symbol query-var))
+        (is (= (dissoc col :lib/source-uuid)
+               (dissoc (lib/find-visible-column-for-ref query col-ref) :lib/source-uuid))))))
+  (testing "reference by ID instead of name"
+    (let [query lib.tu/query-with-source-card
+          col-ref [:field
+                   {:lib/uuid "ae24a9b0-cbb5-40b6-bace-c8a5ac6a7e42"
+                    :base-type :type/Integer
+                    :effective-type :type/Integer}
+                   (meta/id :checkins :user-id)]]
+      (is (=? {:lib/type :metadata/column
+               :base-type :type/Integer
+               :semantic-type :type/FK
+               :name "USER_ID"
+               :lib/card-id 1
+               :lib/source :source/card
+               :lib/source-column-alias "USER_ID"
+               :effective-type :type/Integer
+               :id (meta/id :checkins :user-id)
+               :lib/desired-column-alias "USER_ID"
+               :display-name "User ID"}
+              (lib/find-visible-column-for-ref query col-ref))))))
-- 
GitLab