From 96bbf025f1a59127df1cf5a7fec199f2a5260ee2 Mon Sep 17 00:00:00 2001
From: Cal Herries <39073188+calherries@users.noreply.github.com>
Date: Fri, 2 Jun 2023 12:50:28 +0300
Subject: [PATCH] Add missing reverse migration for
 AddJoinAliasToVisualizationSettingsFieldRefs (#31150)

* Add reverse migration for AddJoinAliasToVisualizationSettingsFieldRefs

* Limit selections to query_type="query"

* Make like strings more specific

* Fix where clause

* Further optimize where clause

* Rename and refactor

* Update test name

* Fix indentation and naming consistency
---
 resources/migrations/000_migrations.yaml    |  2 +-
 src/metabase/db/custom_migrations.clj       | 63 ++++++++++++++++-----
 test/metabase/db/custom_migrations_test.clj | 15 ++++-
 3 files changed, 61 insertions(+), 19 deletions(-)

diff --git a/resources/migrations/000_migrations.yaml b/resources/migrations/000_migrations.yaml
index 28b79cb3e84..a34955633a3 100644
--- a/resources/migrations/000_migrations.yaml
+++ b/resources/migrations/000_migrations.yaml
@@ -14788,7 +14788,7 @@ databaseChangeLog:
       comment: Added 0.47.0 - Add join-alias to the report_card.visualization_settings.column_settings field refs
       changes:
         - customChange:
-            class: "metabase.db.custom_migrations.AddJoinAliasToVisualizationSettingsFieldRefs"
+            class: "metabase.db.custom_migrations.AddJoinAliasToColumnSettingsFieldRefs"
 
   - changeSet:
       id: v47.00-029
diff --git a/src/metabase/db/custom_migrations.clj b/src/metabase/db/custom_migrations.clj
index ca062bba66f..14c30806ae3 100644
--- a/src/metabase/db/custom_migrations.clj
+++ b/src/metabase/db/custom_migrations.clj
@@ -253,7 +253,18 @@
     ["field" id opts] ["field" id (not-empty (apply dissoc opts opts-to-remove))]
     _ field_ref))
 
-(defn- add-join-alias-to-visualization-field-refs [{:keys [visualization_settings result_metadata]}]
+(defn- remove-join-alias-from-column-settings-field-refs [visualization_settings]
+  (update visualization_settings "column_settings"
+          (fn [column_settings]
+            (into {}
+                  (map (fn [[k v]]
+                         (match (vec (json/parse-string k))
+                           ["ref" ["field" id opts]]
+                           [(json/generate-string ["ref" (remove-opts ["field" id opts] "join-alias")]) v]
+                           _ [k v]))
+                       column_settings)))))
+
+(defn- add-join-alias-to-column-settings-refs [{:keys [visualization_settings result_metadata]}]
   (let [result_metadata        (json/parse-string result_metadata)
         visualization_settings (json/parse-string visualization_settings)
         column-key->metadata   (group-by #(-> (get % "field_ref")
@@ -277,21 +288,43 @@
                                  _ [[k v]]))
                              column_settings)))))))
 
-(define-migration AddJoinAliasToVisualizationSettingsFieldRefs
+(define-reversible-migration AddJoinAliasToColumnSettingsFieldRefs
+  (let [update-one! (fn [{:keys [id visualization_settings] :as card}]
+                      (let [updated (add-join-alias-to-column-settings-refs card)]
+                        (when (not= visualization_settings updated)
+                          (t2/query-one {:update :report_card
+                                         :set    {:visualization_settings updated}
+                                         :where  [:= :id id]}))))]
+    (run! update-one! (t2/reducible-query {:select [:id :visualization_settings :result_metadata]
+                                           :from   [:report_card]
+                                           :where  [:and
+                                                    [:or
+                                                     [:= :query_type nil]
+                                                     [:= :query_type "query"]]
+                                                    [:or
+                                                     [:like :visualization_settings "%ref\\\\\",[\\\\\"field%"]
+                                                     ; MySQL with NO_BACKSLASH_ESCAPES disabled
+                                                     [:like :visualization_settings "%ref\\\\\\\",[\\\\\\\"field%"]]
+                                                    [:like :result_metadata "%join-alias%"]]})))
   (let [update! (fn [{:keys [id visualization_settings]}]
-                  (t2/query-one {:update :report_card
-                                 :set    {:visualization_settings visualization_settings}
-                                 :where  [:= :id id]}))]
-    (run! update! (eduction (keep (fn [{:keys [id visualization_settings] :as card}]
-                                    (let [updated (add-join-alias-to-visualization-field-refs card)]
-                                      (when (not= visualization_settings updated)
-                                        {:id                     id
-                                         :visualization_settings updated}))))
-                            (t2/reducible-query {:select [:id :visualization_settings :result_metadata]
-                                                 :from   [:report_card]
-                                                 :where  [:and
-                                                          [:<> :result_metadata nil]
-                                                          [:<> :result_metadata "[]"]]})))))
+                  (let [updated (-> visualization_settings
+                                    json/parse-string
+                                    remove-join-alias-from-column-settings-field-refs
+                                    json/generate-string)]
+                    (when (not= visualization_settings updated)
+                      (t2/query-one {:update :report_card
+                                     :set    {:visualization_settings updated}
+                                     :where  [:= :id id]}))))]
+    (run! update! (t2/reducible-query {:select [:id :visualization_settings]
+                                       :from   [:report_card]
+                                       :where  [:and
+                                                [:or
+                                                 [:= :query_type nil]
+                                                 [:= :query_type "query"]]
+                                                [:or
+                                                 [:like :visualization_settings "%ref\\\\\",[\\\\\"field%"]
+                                                 [:like :visualization_settings "%ref\\\\\\\",[\\\\\\\"field%"]]
+                                                [:like :visualization_settings "%join-alias%"]]}))))
 
 (defn- update-card-row-on-downgrade-for-dashboard-tab
   [dashboard-id]
diff --git a/test/metabase/db/custom_migrations_test.clj b/test/metabase/db/custom_migrations_test.clj
index 7fa211f54d7..cb901df5fe8 100644
--- a/test/metabase/db/custom_migrations_test.clj
+++ b/test/metabase/db/custom_migrations_test.clj
@@ -180,10 +180,11 @@
                        ((:out mi/transform-result-metadata))
                        json/generate-string)))))))))
 
-(deftest add-join-alias-to-visualization-settings-field-refs-test
+(deftest add-join-alias-to-column-settings-field-refs-test
   (testing "Migrations v47.00-028: update visualization_settings.column_settings legacy field refs"
     (impl/test-migrations ["v47.00-028"] [migrate!]
-      (let [result_metadata
+      (let [{:keys [db-type ^javax.sql.DataSource data-source]} mdb.connection/*application-db*
+            result_metadata
             [{:field_ref [:field 1 nil]}
              {:field_ref [:field 1 {:join-alias "Self-joined Table"}]}
              {:field_ref [:field 2 {:source-field 3}]}
@@ -230,8 +231,16 @@
                                                         :database_id            database-id
                                                         :collection_id          nil})]
         (migrate!)
-        (testing "column_settings field refs are updated"
+        (testing "After the migration, column_settings field refs are updated to include join-alias"
           (is (= expected
+                 (-> (t2/query-one {:select [:visualization_settings]
+                                    :from   [:report_card]
+                                    :where  [:= :id card-id]})
+                     :visualization_settings
+                     json/parse-string))))
+        (db.setup/migrate! db-type data-source :down 46)
+        (testing "After reversing the migration, column_settings field refs are updated to remove join-alias"
+          (is (= visualization-settings
                  (-> (t2/query-one {:select [:visualization_settings]
                                     :from   [:report_card]
                                     :where  [:= :id card-id]})
-- 
GitLab