From 2e328a254ca97964e209f354416d4151d7030822 Mon Sep 17 00:00:00 2001
From: Cal Herries <39073188+calherries@users.noreply.github.com>
Date: Wed, 31 May 2023 12:56:32 +0300
Subject: [PATCH] Apply schema filters in Admin > Uploads > Select a schema
 dropdown (#31029)

* Apply inclusion and exclusion patterns to `driver/syncable-schemas` for sql-jdbc drivers

* Fix kondo

* Fix postgres test

* Remove unnecessary test DB names
---
 src/metabase/driver/sql_jdbc.clj       |  7 +++-
 test/metabase/driver/h2_test.clj       |  2 +-
 test/metabase/driver/mysql_test.clj    |  2 +-
 test/metabase/driver/postgres_test.clj |  4 +--
 test/metabase/driver/sql_jdbc_test.clj | 46 ++++++++++++++++++++++++--
 5 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/src/metabase/driver/sql_jdbc.clj b/src/metabase/driver/sql_jdbc.clj
index 04f35b7d4da..dae5b5f77b4 100644
--- a/src/metabase/driver/sql_jdbc.clj
+++ b/src/metabase/driver/sql_jdbc.clj
@@ -10,6 +10,8 @@
    [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync]
    [metabase.driver.sql-jdbc.sync.interface :as sql-jdbc.sync.interface]
    [metabase.driver.sql.query-processor :as sql.qp]
+   [metabase.driver.sync :as driver.s]
+   [metabase.driver.util :as driver.u]
    [metabase.query-processor.writeback :as qp.writeback]
    [metabase.util.honeysql-extensions :as hx]))
 
@@ -145,4 +147,7 @@
 (defmethod driver/syncable-schemas :sql-jdbc
   [driver database]
   (with-open [conn ^java.sql.Connection (jdbc/get-connection (sql-jdbc.conn/db->pooled-connection-spec database))]
-    (into #{} (sql-jdbc.sync.interface/filtered-syncable-schemas driver conn (.getMetaData conn) nil nil))))
+    (let [schema-filter-prop   (driver.u/find-schema-filters-prop driver)
+          [inclusion-patterns
+           exclusion-patterns] (driver.s/db-details->schema-filter-patterns (:name schema-filter-prop) database)]
+      (into #{} (sql-jdbc.sync.interface/filtered-syncable-schemas driver conn (.getMetaData conn) inclusion-patterns exclusion-patterns)))))
diff --git a/test/metabase/driver/h2_test.clj b/test/metabase/driver/h2_test.clj
index 7e7e79ee18d..d649ba5ca8e 100644
--- a/test/metabase/driver/h2_test.clj
+++ b/test/metabase/driver/h2_test.clj
@@ -287,7 +287,7 @@
     (testing "`syncable-schemas` should return schemas that should be synced"
       (mt/with-empty-db
         (is (= #{"PUBLIC"}
-               (driver/syncable-schemas driver/*driver* (mt/id))))))))
+               (driver/syncable-schemas driver/*driver* (mt/db))))))))
 
 (deftest syncable-audit-db-test
   (mt/test-driver :h2
diff --git a/test/metabase/driver/mysql_test.clj b/test/metabase/driver/mysql_test.clj
index 72251cb8df1..22b2dca11e9 100644
--- a/test/metabase/driver/mysql_test.clj
+++ b/test/metabase/driver/mysql_test.clj
@@ -630,4 +630,4 @@
     (testing "`syncable-schemas` should return an empty set because mysql doesn't support schemas"
       (mt/with-empty-db
         (is (= #{}
-               (driver/syncable-schemas driver/*driver* (mt/id))))))))
+               (driver/syncable-schemas driver/*driver* (mt/db))))))))
diff --git a/test/metabase/driver/postgres_test.clj b/test/metabase/driver/postgres_test.clj
index 82ebe1b9bb4..013c54a190a 100644
--- a/test/metabase/driver/postgres_test.clj
+++ b/test/metabase/driver/postgres_test.clj
@@ -1172,7 +1172,7 @@
     (testing "`syncable-schemas` should return schemas that should be synced"
       (mt/with-empty-db
         (is (= #{"public"}
-               (driver/syncable-schemas driver/*driver* (mt/id))))))
+               (driver/syncable-schemas driver/*driver* (mt/db))))))
     (testing "metabase_cache schemas should be excluded"
       (mt/dataset test-data
         (mt/with-persistence-enabled [persist-models!]
@@ -1185,4 +1185,4 @@
               (is (some (partial re-matches #"metabase_cache(.*)")
                         (map :schema_name (jdbc/query conn-spec "SELECT schema_name from INFORMATION_SCHEMA.SCHEMATA;"))))
               (is (nil? (some (partial re-matches #"metabase_cache(.*)")
-                              (driver/syncable-schemas driver/*driver* (mt/id))))))))))))
+                              (driver/syncable-schemas driver/*driver* (mt/db))))))))))))
diff --git a/test/metabase/driver/sql_jdbc_test.clj b/test/metabase/driver/sql_jdbc_test.clj
index d34ce4cba2f..a47e05e9921 100644
--- a/test/metabase/driver/sql_jdbc_test.clj
+++ b/test/metabase/driver/sql_jdbc_test.clj
@@ -1,14 +1,16 @@
 (ns metabase.driver.sql-jdbc-test
   (:require
+   [clojure.set :as set]
    [clojure.test :refer :all]
    [metabase.db.metadata-queries :as metadata-queries]
    [metabase.driver :as driver]
+   [metabase.driver.sql-jdbc.sync.describe-database :as sql-jdbc.describe-database]
    [metabase.driver.sql-jdbc.test-util :as sql-jdbc.tu]
    [metabase.driver.util :as driver.u]
-   [metabase.models.field :refer [Field]]
-   [metabase.models.table :as table :refer [Table]]
+   [metabase.models :refer [Database Field Table]]
    [metabase.query-processor :as qp]
    [metabase.test :as mt]
+   [metabase.util :as u]
    [toucan2.core :as t2]))
 
 (set! *warn-on-reflection* true)
@@ -219,3 +221,43 @@
             (is (= 2
                    (mt/$ids users
                      (spliced-count-of :users [:= $last_login_time "09:30"]))))))))))
+
+(defn- find-schema-filters-prop [driver]
+  (first (filter (fn [conn-prop]
+                   (= :schema-filters (keyword (:type conn-prop))))
+                 (driver/connection-properties driver))))
+
+(deftest syncable-schemas-with-schema-filters-test
+  (mt/test-driver (set (for [driver (set/intersection (sql-jdbc.tu/sql-jdbc-drivers)
+                                                      (mt/normal-drivers-with-feature :actions))
+                             :when  (driver.u/find-schema-filters-prop driver)]
+                         driver))
+    (let [fake-schema-name (u/qualified-name ::fake-schema)]
+      (with-redefs [sql-jdbc.describe-database/all-schemas (let [orig sql-jdbc.describe-database/all-schemas]
+                                                             (fn [metadata]
+                                                               (eduction
+                                                                cat
+                                                                [(orig metadata) [fake-schema-name]])))]
+        (is (= #{"public" fake-schema-name}
+               (driver/syncable-schemas driver/*driver* (mt/db))))
+        (let [driver             (driver.u/database->driver (mt/db))
+              schema-filter-prop (find-schema-filters-prop driver)
+              filter-type-prop   (keyword (str (:name schema-filter-prop) "-type"))
+              patterns-type-prop (keyword (str (:name schema-filter-prop) "-patterns"))]
+          (testing "syncable-schemas works as expected"
+            (testing " with an inclusion filter"
+              (mt/with-temp Database [db-filtered {:engine  driver
+                                                   :details (-> (mt/db)
+                                                                :details
+                                                                (assoc filter-type-prop "inclusion"
+                                                                       patterns-type-prop "public"))}]
+                (is (= #{"public"}
+                       (driver/syncable-schemas driver/*driver* db-filtered)))))
+            (testing " with an exclusion filter"
+              (mt/with-temp Database [db-filtered {:engine  driver
+                                                   :details (-> (mt/db)
+                                                                :details
+                                                                (assoc filter-type-prop "exclusion"
+                                                                       patterns-type-prop "public"))}]
+                (is (= #{fake-schema-name}
+                       (driver/syncable-schemas driver/*driver* db-filtered)))))))))))
-- 
GitLab