Logic for updating Metabase Field models from metadata fetched from a physical DB. The basic idea here is to look at the metadata we get from calling
A note on terminology used in
Other notes:
| (ns metabase.sync.sync-metadata.fields (:require [metabase.driver.util :as driver.u] [metabase.models.table :as table] [metabase.sync.fetch-metadata :as fetch-metadata] [metabase.sync.interface :as i] [metabase.sync.sync-metadata.fields.our-metadata :as fields.our-metadata] [metabase.sync.sync-metadata.fields.sync-instances :as sync-instances] [metabase.sync.sync-metadata.fields.sync-metadata :as sync-metadata] [metabase.sync.util :as sync-util] [metabase.util.log :as log] [metabase.util.malli :as mu] [metabase.util.malli.schema :as ms] [toucan2.core :as t2] [toucan2.util :as t2.util])) |
+----------------------------------------------------------------------------------------------------------------+ | PUTTING IT ALL TOGETHER | +----------------------------------------------------------------------------------------------------------------+ | |
(mu/defn- sync-and-update! :- ms/IntGreaterThanOrEqualToZero "Sync Field instances (i.e., rows in the Field table in the Metabase application DB) for a Table, and update metadata properties (e.g. base type and comment/remark) as needed. Returns number of Fields synced." [table :- i/TableInstance db-metadata :- [:set i/TableMetadataField]] (+ (sync-instances/sync-instances! table db-metadata (fields.our-metadata/our-metadata table)) ;; Now that tables are synced and fields created as needed make sure field properties are in sync. ;; Re-fetch our metadata because there might be somethings that have changed after calling ;; `sync-instances` (sync-metadata/update-metadata! table db-metadata (fields.our-metadata/our-metadata table)))) | |
(mu/defn sync-fields! :- [:map [:updated-fields ms/IntGreaterThanOrEqualToZero] [:total-fields ms/IntGreaterThanOrEqualToZero]] "Sync the Fields in the Metabase application database for all the Tables in a `database`." [database :- i/DatabaseInstance] (sync-util/with-error-handling (format "Error syncing Fields for Database ''%s''" (sync-util/name-for-logging database)) (let [driver (driver.u/database->driver database) schemas? (driver.u/supports? driver :schemas database) fields-metadata (if schemas? (fetch-metadata/fields-metadata database :schema-names (sync-util/sync-schemas database)) (fetch-metadata/fields-metadata database))] (transduce (comp (partition-by (juxt :table-name :table-schema)) (map (fn [table-metadata] (let [fst (first table-metadata) table (t2/select-one :model/Table :db_id (:id database) :%lower.name (t2.util/lower-case-en (:table-name fst)) :%lower.schema (some-> fst :table-schema t2.util/lower-case-en) {:where sync-util/sync-tables-clause}) updated (if table (try ;; TODO: decouple nested field columns sync from field sync. This will allow ;; describe-fields to be used for field sync for databases with nested field columns ;; Also this should be a driver method, not a sql-jdbc.sync method (let [all-metadata (fetch-metadata/include-nested-fields-for-table (set table-metadata) database table)] (sync-and-update! table all-metadata)) (catch Exception e (log/error e) 0)) 0)] {:total-fields (count table-metadata) :updated-fields updated})))) (partial merge-with +) {:total-fields 0 :updated-fields 0} fields-metadata)))) | |
Sync the Fields in the Metabase application database for a specific | (mu/defn sync-fields-for-table! ([table :- i/TableInstance] (sync-fields-for-table! (table/database table) table)) ([database :- i/DatabaseInstance table :- i/TableInstance] (sync-util/with-error-handling (format "Error syncing Fields for Table ''%s''" (sync-util/name-for-logging table)) (let [db-metadata (fetch-metadata/table-fields-metadata database table) ;; TODO: decouple nested field columns sync from field sync. This will allow ;; describe-fields to be used for field sync for databases with nested field columns ;; Also this should be a driver method, not a sql-jdbc.sync method db-metadata (fetch-metadata/include-nested-fields-for-table db-metadata database table)] {:total-fields (count db-metadata) :updated-fields (sync-and-update! table db-metadata)})))) |