Реализация мультиметодов для вашего драйвера¶
Реализация мультиметодов позволяет вам воспользоваться преимуществами существующего кода драйвера Glarus BI, расширив эти методы для работы с вашей конкретной базой данных.
Давайте сначала сосредоточимся на основном файле драйвера для нашего 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]))
Каждый драйвер Glarus BI находится в своём собственном пространстве имён¶
В данном случае это пространство имён com.mycompany.metabase.driver.foxpro98.
Все основные драйверы Glarus BI находятся в пространствах имён metabase.driver.<name-goes-here>
. Вероятно, лучше использовать имена, соответствующие соглашениям об именовании пакетов Java.
Многие драйверы разбиты на дополнительные пространства имён¶
Особенно крупные драйверы. Обычно драйвер имеет пространство имён query-processor
(например, com.mycompany.metabase.driver.foxpro98.query-processor
), которое содержит логику для преобразования запросов MBQL (запросов, созданных с помощью графического конструктора запросов Glarus BI) в собственные запросы (например, SQL). Процессор запросов часто является самой сложной частью драйвера, поэтому разделение этой логики может упростить работу с ним. Некоторые драйверы также имеют отдельное пространство имён sync
, в котором есть реализации методов, используемых Glarus BI для синхронизации базы данных.
Инициализация драйвера¶
Все драйверы могут включать дополнительный код, который будет выполняться один раз (и только один раз) с использованием metabase.driver/initialize!
, когда Glarus BI инициализирует драйвер, то есть до того, как драйвер впервые установит соединение с базой данных. (На самом деле Glarus BI использует metabase.driver/initialize!
для ленивой загрузки драйвера.) Есть лишь несколько случаев, когда вы должны использовать metabase.driver/initialize
, например, для выделения ресурсов или установки определённых системных свойств.
Мультиметоды metabase.driver
¶
Пространство имён metabase.driver
определяет ряд [мультиметодов](https://clojure.org/ reference/multimethods), а драйверы предоставляют для них реализации, как в нашем примере:
(defmethod driver/display-name :foxpro98 [_]
"Visual FoxPro '98")
Все четыре основные функции драйвера Glarus BI, описанные выше, реализуются с помощью мультиметодов. Эти методы отправляют ключевое слово драйвера, в нашем случае :foxpro98
. На самом деле, это то, чем является драйвер Glarus BI — ключевое слово! Здесь нет классов или объектов — только одно ключевое слово.
Вы можете просмотреть пространство имён 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
и другие родительские компоненты предоставляют реализации для многих методов, необходимых для реализации четырёх основных функций. драйвера Glarus BI. На самом деле, :sql-jdbc
предоставляет реализации таких вещей, как driver/execute-prepared-statement!
, поэтому драйверу, использующему его в качестве родителя, не нужно предоставлять его самому. Однако различные родительские драйверы определяют свои собственные мультиметоды для реализации.
Известные родительские драйверы¶
:sql-jdbc
можно использовать в качестве родителя для баз данных на основе SQL с драйвером JDBC.:sql-jdbc
реализует большинство из четырёх основных функций, но вместо этого вы должны реализовать мультиметодыsql-jdbc
, найденные в пространствах имёнmetabase.driver.sql-jdbc.*
, а также некоторые методыmetabase. driver.sql.*
пространства имён.
:sql
сам является родителем:sql-jdbc
; его можно использовать для баз данных на основе SQL, которые не имеют драйвер JDBC, например BigQuery.:sql
реализует значительную часть функциональности драйвера, но вы должны реализовать некоторые методы из пространств имёнmetabase.driver.sql.*
, чтобы использовать его.
Драйверы, использующие API Google, такие как BigQuery и Google Analytics, могут использовать драйвер
:google
в качестве родителя.Некоторые драйверы используют другие «конкретные» драйверы в качестве своих родителей. Например,
: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
, а также перезапустить Glarus BI после внесения изменений.