Skip to content
Snippets Groups Projects
Unverified Commit da7dedd9 authored by Ngoc Khuat's avatar Ngoc Khuat Committed by GitHub
Browse files

API for getting database usage (#27646)

* API for getting database usage

* use defmulti

* handle cases when database has no tables and add docstring

* sacrifice powerness in the light of beauty
parent 33d54e53
No related branches found
No related tags found
No related merge requests found
......@@ -43,6 +43,7 @@
[metabase.util.cron :as u.cron]
[metabase.util.honeysql-extensions :as hx]
[metabase.util.i18n :refer [deferred-tru trs tru]]
[metabase.util.malli.schema :as ms]
[metabase.util.schema :as su]
[schema.core :as s]
[toucan.db :as db]
......@@ -352,6 +353,69 @@
secret/expand-db-details-inferred-secret-values
(assoc :can-manage true)))))
(def ^:private database-usage-models
"List of models that are used to report usage on a database."
[:question :dataset :metric :segment])
(def ^:private always-false-hsql-expr
"A Honey SQL expression that is never true.
1 = 2"
[:= [:inline 1] [:inline 2]])
(defmulti ^:private database-usage-query
"Query that will returns the number of `model` that use the database with id `database-id`.
The query must returns a scalar, and the method could return `nil` in case no query is available."
{:arglists '([model database-id table-ids])}
(fn [model _database-id _table-ids] (keyword model)))
(defmethod database-usage-query :question
[_ db-id _table-ids]
{:select [[:%count.* :question]]
:from [:report_card]
:where [:and
[:= :database_id db-id]
[:= :dataset false]]})
(defmethod database-usage-query :dataset
[_ db-id _table-ids]
{:select [[:%count.* :dataset]]
:from [:report_card]
:where [:and
[:= :database_id db-id]
[:= :dataset true]]})
(defmethod database-usage-query :metric
[_ _db-id table-ids]
{:select [[:%count.* :metric]]
:from [:metric]
:where (if table-ids
[:in :table_id table-ids]
always-false-hsql-expr)})
(defmethod database-usage-query :segment
[_ _db-id table-ids]
{:select [[:%count.* :segment]]
:from [:segment]
:where (if table-ids
[:in :table_id table-ids]
always-false-hsql-expr)})
(api/defendpoint GET "/:id/usage_info"
"Get usage info for a database.
Returns a map with keys are models and values are the number of entities that use this database."
[id]
{id ms/IntGreaterThanZero}
(api/check-superuser)
(api/check-404 (db/exists? Database :id id))
(let [table-ids (db/select-ids Table :db_id id)]
(first (mdb.query/query
{:select [:*]
:from (for [model database-usage-models
:let [query (database-usage-query model id table-ids)]
:when query]
[query model])}))))
;;; ----------------------------------------- GET /api/database/:id/metadata -----------------------------------------
......
......@@ -10,7 +10,7 @@
[metabase.driver.util :as driver.u]
[metabase.mbql.schema :as mbql.s]
[metabase.models
:refer [Card Collection Database Field FieldValues Table]]
:refer [Card Collection Database Field FieldValues Table Metric Segment]]
[metabase.models.database :as database :refer [protected-password]]
[metabase.models.permissions :as perms]
[metabase.models.permissions-group :as perms-group]
......@@ -153,6 +153,54 @@
(is (= {:errors {:include "value may be nil, or if non-nil, value must be one of: `tables`, `tables.fields`."}}
(mt/user-http-request :lucky :get 400 (format "database/%d?include=schemas" (mt/id))))))))
(deftest get-database-usage-info-test
(mt/with-temp*
[Database [{db-id :id}]
Table [{table-id-1 :id} {:db_id db-id}]
Table [{table-id-2 :id} {:db_id db-id}]
;; question
Card [_ {:database_id db-id
:table_id table-id-1
:dataset false}]
;; dataset
Card [_ {:database_id db-id
:table_id table-id-1
:dataset true}]
Card [_ {:database_id db-id
:table_id table-id-2
:dataset true
:archived true}]
Metric [_ {:table_id table-id-1}]
Metric [_ {:table_id table-id-1}]
Metric [_ {:table_id table-id-2}]
Segment [_ {:table_id table-id-2}]]
(testing "should require admin"
(is (= "You don't have permissions to do that."
(mt/user-http-request :rasta :get 403 (format "database/%d/usage_info" db-id)))))
(testing "return the correct usage info"
(is (= {:question 1
:dataset 2
:metric 3
:segment 1}
(mt/user-http-request :crowberto :get 200 (format "database/%d/usage_info" db-id)))))
(testing "404 if db does not exist"
(let [non-existing-db-id (inc (db/select-one-id Database {:order-by [[:id :desc]]}))]
(is (= "Not found."
(mt/user-http-request :crowberto :get 404
(format "database/%d/usage_info" non-existing-db-id)))))))
(mt/with-temp*
[Database [{db-id :id}]]
(testing "should work with DB that has no tables"
(is (= {:question 0
:dataset 0
:metric 0
:segment 0}
(mt/user-http-request :crowberto :get 200 (format "database/%d/usage_info" db-id)))))))
(defn- create-db-via-api! [& [m]]
(let [db-name (mt/random-name)]
(try
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment