為您的驅動程式實作多方法
實作多方法可讓您運用 Metabase 現有的驅動程式碼,方法是擴充這些方法以適用於您的特定資料庫。
讓我們先將重點放在 Fox Pro ‘98 的主要驅動程式檔案 src/metabase/driver/foxpro98.clj
。看看這段範例程式碼
;; Define a namespace for the driver
(ns com.mycompany.metabase.driver.foxpro98
(:require [metabase.driver :as driver]))
;; Can you include a different method here as an example?
(defmethod driver/display-name :foxpro98 [_]
"Visual FoxPro '98")
讓我們逐步瞭解每個程式碼區塊。
驅動程式命名空間
;; Define a namespace for the driver
(ns com.mycompany.metabase.driver.foxpro98
(:require [metabase.driver :as driver]))
每個 Metabase 驅動程式都存在於自己的命名空間中
在此案例中,命名空間為 com.mycompany.metabase.driver.foxpro98
。所有核心 Metabase 驅動程式都位於 metabase.driver.<name-goes-here>
命名空間中。最好使用符合 Java 套件命名慣例 的名稱。
許多驅動程式會進一步細分為其他命名空間
尤其是較大的驅動程式。一般而言,驅動程式會有一個 query-processor
命名空間 (例如,com.mycompany.metabase.driver.foxpro98.query-processor
),其中包含將 MBQL 查詢 (使用 Metabase 圖形化查詢產生器建立的查詢) 轉換為原生查詢 (例如 SQL) 的邏輯。查詢處理器通常是驅動程式中最複雜的部分,因此將該邏輯分開有助於簡化工作流程。有些驅動程式也有個別的 sync
命名空間,其中包含 Metabase 的 資料庫同步 所使用的方法實作。
驅動程式初始化
所有驅動程式都可以包含額外的程式碼,以便在使用 metabase.driver/initialize!
初始化驅動程式時 (也就是在驅動程式第一次建立資料庫連線之前) 執行一次 (而且只執行一次)。(事實上,Metabase 使用 metabase.driver/initialize!
來延遲載入驅動程式。) 只有在少數情況下才應使用 metabase.driver/initialize
,例如配置資源或設定某些系統屬性。
metabase.driver
多方法
metabase.driver
命名空間 定義了一系列 多方法,而驅動程式會為它們提供實作,如同我們的範例
(defmethod driver/display-name :foxpro98 [_]
"Visual FoxPro '98")
上述 Metabase 驅動程式的四個主要功能都透過多方法實作。這些方法會依據驅動程式的關鍵字 :foxpro98
(在我們的案例中) 進行分派。事實上,這就是 Metabase 驅動程式的全部 – 一個關鍵字!沒有任何類別或物件可見 – 只有一個關鍵字。
您可以瀏覽 metabase.driver
命名空間,以取得您可以實作的完整多方法清單。閱讀每個方法的說明字串,並決定是否需要實作它。大多數方法都是選用的。
列出可用的驅動程式多方法
若要快速查詢所有驅動程式多方法的清單,您可以執行下列指令
clojure -M:run driver-methods
這會列印所有驅動程式命名空間和多方法的清單。這包括許多項目,例如 sql
和 sql-jdbc
多方法,以及測試擴充功能多方法。
如果您也想查看方法的說明字串,請執行
clojure -M:run driver-methods docs
父驅動程式
許多驅動程式共用實作細節,而且為同步方法等撰寫完整的實作會牽涉到許多重複的程式碼。因此,許多高階功能會在共用的「父」驅動程式中部分或完整實作,例如最常見的父驅動程式 :sql-jdbc
。「父」驅動程式類似於物件導向程式設計中的超類別。
您可以透過在 外掛程式資訊清單 中列出父驅動程式來定義驅動程式父驅動程式。
像 :sql-jdbc
這類的父驅動程式旨在作為驅動程式的通用抽象「基底類別」,這些驅動程式可以共用其大部分的實作;在 :sql-jdbc
的案例中,它適用於以 SQL 為基礎且在底層使用 JDBC 驅動程式的驅動程式。:sql-jdbc
和其他父驅動程式為 Metabase 驅動程式的四個主要功能提供許多方法實作。事實上,:sql-jdbc
提供諸如 driver/execute-prepared-statement!
之類項目的實作,因此使用它作為父驅動程式的驅動程式不需要自行提供實作。不過,各種父驅動程式會定義自己的多方法來實作。
值得注意的父驅動程式
這些父驅動程式非常重要。
:sql-jdbc
可以作為具有 JDBC 驅動程式之以 SQL 為基礎的資料庫的父驅動程式使用。:sql-jdbc
實作了四個主要功能中的大多數,但您必須實作在metabase.driver.sql-jdbc.*
命名空間中找到的sql-jdbc
多方法,以及metabase.driver.sql.*
命名空間中的某些方法。
:sql
本身是:sql-jdbc
的父驅動程式;它可以用於沒有 JDBC 驅動程式的以 SQL 為基礎的資料庫,例如 BigQuery。:sql
實作了大量的驅動程式功能,但您必須實作在metabase.driver.sql.*
命名空間中找到的某些方法才能使用它。
- 有些驅動程式使用其他「具體」的驅動程式作為其父驅動程式 – 例如,
:redshift
使用:postgres
作為父驅動程式,僅提供方法實作來覆寫 postgres 驅動程式 (在需要時)。
呼叫父驅動程式實作
您可以使用 get-method
取得父驅動程式的方法實作
(defmethod driver/mbql->native :bigquery [driver query]
((get-method driver/mbql-native :sql) driver query))
這相當於在物件導向程式設計中呼叫 super.someMethod()
。
您必須將驅動程式引數以原樣傳遞至父實作,以便該方法呼叫的任何方法都使用正確的實作。以下是您應避免的兩種呼叫父驅動程式的方式
(defmethod driver/mbql->native :bigquery [_ query]
;; BAD! If :sql's implementation of mbql->native calls any other methods, it won't use the :bigquery implementation
((get-method driver/mbql->native :sql) :sql query))
也請避免
(defmethod driver/mbql->native :bigquery [_ query]
;; BAD! If someone else creates a driver using :bigquery as a parent, any methods called by :sql's implementation
;; of mbql->native will use :bigquery method implementations instead of custom ones for that driver
((get-method driver/mbql->native :sql) :bigquery query))
多個父驅動程式
眼尖的讀者可能已經注意到,BigQuery 被提及同時具有 :sql
和 :google
作為父驅動程式。允許並支援這種多重繼承!您可以透過以下方式定義具有多個父驅動程式的驅動程式
(driver/register! :bigquery, :parent #{:sql :google})
在某些情況下,兩個父驅動程式都可能為某個方法提供實作;若要修正這種不明確性,只需為您的驅動程式提供實作,並如上所述將它們傳遞至慣用的父驅動程式實作即可。
對於以外掛程式形式出貨的驅動程式,您會在外掛程式資訊清單中註冊方法。
從 REPL 和 CIDER 中使用驅動程式
必須在本機安裝 metabase-core
並建置驅動程式 uberjar 會很麻煩,尤其是當您必須重複此動作來測試每個變更時。幸運的是,您可以執行指令,就像一切都是一個大型專案的一部分一樣
啟動 REPL。
clojure -A:dev:drivers:drivers-dev
您需要重建驅動程式並將其安裝在您的 ./plugins
目錄中,並在您進行變更時重新啟動 Metabase。
閱讀其他 Metabase 版本的文件。