# Реализация мультиметодов для вашего драйвера Реализация мультиметодов позволяет вам воспользоваться преимуществами существующего кода драйвера Glarus BI, расширив эти методы для работы с вашей конкретной базой данных. Давайте сначала сосредоточимся на основном файле драйвера для нашего Fox Pro '98 `src/metabase/driver/foxpro98.clj`. Взгляните на этот пример кода: ```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") ``` Давайте пройдёмся по каждому блоку кода. ## Пространства имён драйверов ```clj ;; 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.`. Вероятно, лучше использовать имена, соответствующие [соглашениям об именовании пакетов Java](https://en.wikipedia.org/wiki/Java_package#Package_naming_conventions). ### Многие драйверы разбиты на дополнительные пространства имён Особенно крупные драйверы. Обычно драйвер имеет пространство имён `query-processor` (например, `com.mycompany.metabase.driver.foxpro98.query-processor`), которое содержит логику для преобразования запросов MBQL (запросов, созданных с помощью графического конструктора запросов Glarus BI) в собственные запросы (например, SQL). Процессор запросов часто является самой сложной частью драйвера, поэтому разделение этой логики может упростить работу с ним. Некоторые драйверы также имеют отдельное пространство имён `sync`, в котором есть реализации методов, используемых Glarus BI для [синхронизации базы данных](../../databases/sync-scan.md). ## Инициализация драйвера Все драйверы могут включать дополнительный код, который будет выполняться один раз (и только один раз) с использованием `metabase.driver/initialize!`, когда Glarus BI инициализирует драйвер, то есть до того, как драйвер впервые установит соединение с базой данных. (На самом деле Glarus BI использует `metabase.driver/initialize!` для ленивой загрузки драйвера.) Есть лишь несколько случаев, когда вы должны использовать `metabase.driver/initialize`, например, для выделения ресурсов или установки определённых системных свойств. ## Мультиметоды `metabase.driver` [Пространство имён `metabase.driver`](https://github.com/metabase/metabase/blob/master/src/metabase/driver.clj) определяет ряд [мультиметодов](https://clojure.org/ reference/multimethods), а драйверы предоставляют для них реализации, как в нашем примере: ```clj (defmethod driver/display-name :foxpro98 [_] "Visual FoxPro '98") ``` Все четыре основные функции драйвера Glarus BI, описанные выше, реализуются с помощью мультиметодов. Эти методы отправляют ключевое слово драйвера, в нашем случае `:foxpro98`. На самом деле, это то, чем является драйвер Glarus BI — ключевое слово! Здесь нет классов или объектов — только одно ключевое слово. Вы можете просмотреть [пространство имён `metabase.driver`](https://github.com/metabase/metabase/blob/master/src/metabase/driver.clj) для получения полного списка мультиметодов, которые вы могли бы реализовать. Прочтите строку документации для каждого метода и решите, нужно ли вам его реализовать. Большинство методов являются необязательными. ## Список доступных мультиметодов драйвера Чтобы быстро просмотреть список всех мультиметодов драйвера, вы можете запустить команду ```sh clojure -M:run driver-methods ``` которая отобразит список всех пространств имён драйверов и мультиметодов (`sql`, `sql-jdbc`, тестовых расширений и других). Если вы также хотите увидеть строки документации для методов, запустите: ```sh clojure -M:run driver-methods docs ``` ## Родительские драйверы Многие драйверы совместно используют детали реализации, и написание полных реализаций для методов синхронизации и т.п. потребовало бы большого количества повторяющегося кода. Таким образом, **многие функции высокого уровня частично или полностью реализованы в общих «родительских» драйверах**, таких как наиболее распространённый родитель `:sql-jdbc`. «Родительский» драйвер аналогичен суперклассу в объектно-ориентированном программировании. Вы можете определить родителя драйвера, указав его в [манифесте плагина](plugins.md). Родители, такие как `: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`: ```clj (defmethod driver/mbql->native :bigquery [driver query] ((get-method driver/mbql-native :sql) driver query)) ``` Это эквивалент вызова `super.someMethod()` в объектно-ориентированном программировании. Вы должны передать аргумент драйвера родительской реализации как есть, чтобы все методы, вызываемые этим методом, использовали правильную реализацию. Вот два способа вызова родительских методов, которых вам следует избегать: ```clj (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)) ``` также избегать: ```clj (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` в качестве родителя. Это множественное наследование разрешено и даже крайне полезно! Вы можете определить драйвер с несколькими родителями следующим образом: ```clj (driver/register! :bigquery, :parent #{:sql :google}) ``` В некоторых случаях оба родителя могут предоставить реализацию метода; чтобы исправить эту двусмысленность, просто предоставьте реализацию для своего драйвера и передайте её предпочтительной реализации родительского драйвера, как описано выше. Для драйверов, поставляемых в виде подключаемого модуля, вы должны зарегистрировать методы в манифесте подключаемого модуля. ## Работа с драйвером из REPL и в CIDER Необходимость устанавливать `metabase-core` локально и создавать драйверы uberjar была бы неприятной, особенно если вам приходилось повторять это, чтобы проверить каждое изменение. К счастью, вы можете запускать команды, как если бы всё было частью одного гигантского проекта: Чтобы начать работу с драйвером в REPL, выполните: ```sh clojure -A:dev:drivers:drivers-dev ``` Вам нужно будет пересобрать драйвер и установить его в каталог `./plugins`, а также перезапустить Glarus BI после внесения изменений.