diff --git a/frontend/src/metabase/services.js b/frontend/src/metabase/services.js index bdc959dc8cd8e72536802509bb3473136e47a435..c380838cea2e3b6f9cfb4a3ca581c97f2252810a 100644 --- a/frontend/src/metabase/services.js +++ b/frontend/src/metabase/services.js @@ -212,7 +212,7 @@ export const LdapApi = { }; export const MetabaseApi = { - db_list: GET("/api/database"), + db_list: GET("/api/database", res => res["data"]), db_create: POST("/api/database"), db_validate: POST("/api/database/validate"), db_add_sample_dataset: POST("/api/database/sample_dataset"), diff --git a/src/metabase/api/database.clj b/src/metabase/api/database.clj index d562b5ae586b8dabae47471b5c257f24636d1796..9a548840b05d14dca6561355b21be68520ba503f 100644 --- a/src/metabase/api/database.clj +++ b/src/metabase/api/database.clj @@ -22,6 +22,7 @@ [metabase.models.table :refer [Table]] [metabase.public-settings :as public-settings] [metabase.sample-data :as sample-data] + [metabase.server.middleware.offset-paging :as offset-paging] [metabase.sync.analyze :as analyze] [metabase.sync.field-values :as sync-field-values] [metabase.sync.schedules :as sync.schedules] @@ -165,8 +166,15 @@ (cond-> dbs (and (source-query-cards-exist?) virtual-db-metadata) (concat [virtual-db-metadata])))) -(defn- dbs-list [& {:keys [include-tables? include-saved-questions-db? include-saved-questions-tables?]}] - (when-let [dbs (seq (filter mi/can-read? (db/select Database {:order-by [:%lower.name :%lower.engine]})))] +(defn- dbs-list [& {:keys [include-tables? + include-saved-questions-db? + include-saved-questions-tables? + limit + offset]}] + (when-let [dbs (seq (filter mi/can-read? (db/select Database + {:order-by [:%lower.name :%lower.engine] + :limit limit + :offset offset})))] (cond-> (add-native-perms-info dbs) include-tables? add-tables include-saved-questions-db? (add-saved-questions-virtual-database :include-tables? include-saved-questions-tables?)))) @@ -210,10 +218,15 @@ (if (seq include_cards) true include-tables?))] - (or (dbs-list :include-tables? include-tables? - :include-saved-questions-db? include-saved-questions-db? - :include-saved-questions-tables? include-saved-questions-tables?) - []))) + {:data (or (dbs-list :include-tables? include-tables? + :include-saved-questions-db? include-saved-questions-db? + :include-saved-questions-tables? include-saved-questions-tables? + :limit offset-paging/*limit* + :offset offset-paging/*offset*) + []) + :limit offset-paging/*limit* + :offset offset-paging/*offset* + :total (db/count Database)})) ;;; --------------------------------------------- GET /api/database/:id ---------------------------------------------- diff --git a/test/metabase/api/database_test.clj b/test/metabase/api/database_test.clj index 3d4ee13ee49938c4f5053624ff8b371ceeb52523..3147b5e028b3a5fb5ceb99e04d6fc686d4e964fb 100644 --- a/test/metabase/api/database_test.clj +++ b/test/metabase/api/database_test.clj @@ -357,17 +357,27 @@ (testing "Database details *should not* come back for Rasta since she's not a superuser" (let [expected-keys (-> (into #{:features :native_permissions} (keys (Database (mt/id)))) (disj :details))] - (doseq [db ((mt/user->client :rasta) :get 200 "database")] + (doseq [db (:data ((mt/user->client :rasta) :get 200 "database"))] (testing (format "Database %s %d %s" (:engine db) (u/the-id db) (pr-str (:name db))) (is (= expected-keys (set (keys db))))))))) + (doseq [query-param ["?limit=2" + "?limit=2&offset=1"]] + (testing query-param + (mt/with-temp* + [Database [{db-id :id1, db-name :name1} {:engine (u/qualified-name ::test-driver)}] + Database [{db-id :id2, db-name :name2} {:engine (u/qualified-name ::test-driver)}]] + + (let [db (:data ((mt/user->client :rasta) :get 200 (str "database" query-param)))] + (is (= 2 (count db))))))) + ;; ?include=tables and ?include_tables=true mean the same thing so test them both the same way (doseq [query-param ["?include_tables=true" "?include=tables"]] (testing query-param (mt/with-temp Database [{db-id :id, db-name :name} {:engine (u/qualified-name ::test-driver)}] - (doseq [db ((mt/user->client :rasta) :get 200 (str "database" query-param))] + (doseq [db (:data ((mt/user->client :rasta) :get 200 (str "database" query-param)))] (testing (format "Database %s %d %s" (:engine db) (u/the-id db) (pr-str (:name db))) (is (= (expected-tables db) (:tables db)))))))))) @@ -381,7 +391,7 @@ :id mbql.s/saved-questions-virtual-database-id :features ["basic-aggregations"] :is_saved_questions true} - (last ((mt/user->client :lucky) :get 200 "database?saved=true")))))) + (last (:data ((mt/user->client :lucky) :get 200 "database?saved=true"))))))) (testing "We should not include the saved questions virtual DB if there aren't any cards" (not-any? @@ -389,7 +399,7 @@ ((mt/user->client :lucky) :get 200 "database?saved=true"))) (testing "Omit virtual DB if nested queries are disabled" (tu/with-temporary-setting-values [enable-nested-queries false] - (every? some? ((mt/user->client :lucky) :get 200 "database?saved=true")))))) + (every? some? (:data ((mt/user->client :lucky) :get 200 "database?saved=true"))))))) (deftest fetch-databases-with-invalid-driver-test (testing "GET /api/database" @@ -400,7 +410,7 @@ "?saved=true" "?include=tables"]] (testing (format "\nparams = %s" (pr-str params)) - (let [db-ids (set (map :id ((mt/user->client :lucky) :get 200 (str "database" params))))] + (let [db-ids (set (map :id (:data ((mt/user->client :lucky) :get 200 (str "database" params)))))] (testing "DB should still come back, even though driver is invalid :shrug:" (is (contains? db-ids db-id))))))))))) @@ -436,14 +446,14 @@ (letfn [(fetch-virtual-database [] (some #(when (= (:name %) "Saved Questions") %) - ((mt/user->client :crowberto) :get 200 (str "database" params))))] + (:data ((mt/user->client :crowberto) :get 200 (str "database" params)))))] (testing "Check that we get back 'virtual' tables for Saved Questions" (testing "The saved questions virtual DB should be the last DB in the list" (mt/with-temp Card [card (card-with-native-query "Kanye West Quote Views Per Month")] ;; run the Card which will populate its result_metadata column ((mt/user->client :crowberto) :post 202 (format "card/%d/query" (u/the-id card))) ;; Now fetch the database list. The 'Saved Questions' DB should be last on the list - (let [response (last ((mt/user->client :crowberto) :get 200 (str "database" params)))] + (let [response (last (:data ((mt/user->client :crowberto) :get 200 (str "database" params))))] (is (schema= SavedQuestionsDB response)) (check-tables-included response (virtual-table-for-card card))))) @@ -467,7 +477,7 @@ ((mt/user->client :crowberto) :post 202 (format "card/%d/query" (u/the-id card)))) ;; Now fetch the database list. The 'Saved Questions' DB should be last on the list. Cards should have their ;; Collection name as their Schema - (let [response (last ((mt/user->client :crowberto) :get 200 (str "database" params)))] + (let [response (last (:data ((mt/user->client :crowberto) :get 200 (str "database" params))))] (is (schema= SavedQuestionsDB response)) (check-tables-included