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)})))) |