Logic for syncing the special Currently, this is only used by the Sample Database, but theoretically in the future we could add additional sample datasets and preconfigure them by populating this Table; or 3rd-party applications or users can add this table to their database for an enhanced Metabase experience out-of-the box. | (ns metabase.sync.sync-metadata.metabase-metadata (:require [clojure.string :as str] [metabase.driver :as driver] [metabase.driver.util :as driver.u] [metabase.models.database :refer [Database]] [metabase.models.field :refer [Field]] [metabase.models.table :refer [Table]] [metabase.sync.fetch-metadata :as fetch-metadata] [metabase.sync.interface :as i] [metabase.sync.util :as sync-util] [metabase.util :as u] [metabase.util.log :as log] [metabase.util.malli :as mu] [metabase.util.malli.schema :as ms] [toucan2.core :as t2])) |
(def ^:private KeypathComponents [:map [:table-name [:maybe ms/NonBlankString]] [:field-name [:maybe ms/NonBlankString]] [:k :keyword]]) | |
(mu/defn- parse-keypath :- KeypathComponents "Parse a `keypath` into components for easy use." ;; TODO: this does not support schemas in dbs :( [keypath :- ms/NonBlankString] ;; keypath will have one of three formats: ;; property (for database-level properties) ;; table_name.property ;; table_name.field_name.property (let [[first-part second-part third-part] (str/split keypath #"\.")] {:table-name (when second-part first-part) :field-name (when third-part second-part) :k (keyword (or third-part second-part first-part))})) | |
(mu/defn- set-property! :- :boolean "Set a property for a Field or Table in `database`. Returns `true` if a property was successfully set." [database :- i/DatabaseInstance {:keys [table-name field-name k]} :- KeypathComponents value] (boolean ;; ignore legacy entries that try to set field_type since it's no longer part of Field (when-not (= k :field_type) ;; fetch the corresponding Table, then set the Table or Field property (if table-name (when-let [table-id (t2/select-one-pk Table ;; TODO: this needs to support schemas :db_id (u/the-id database) :name table-name :active true)] (if field-name (pos? (t2/update! Field {:name field-name, :table_id table-id} {k value})) (pos? (t2/update! Table table-id {k value})))) (pos? (t2/update! Database (u/the-id database) {k value})))))) | |
Databases may include a table named The table should have the following schema: column | type | example --------+---------+------------------------------------------------- keypath | varchar | "products.created_at.description" value | varchar | "The date the product was added to our catalog."
This functionality is currently only used by the Sample Database. In order to use this functionality, drivers must
implement optional fn | (mu/defn- sync-metabase-metadata-table! [driver database :- i/DatabaseInstance metabase-metadata-table :- i/DatabaseMetadataTable] (doseq [{:keys [keypath value]} (driver/table-rows-seq driver database metabase-metadata-table)] (sync-util/with-error-handling (format "Error handling metabase metadata entry: set %s -> %s" keypath value) (or (set-property! database (parse-keypath keypath) value) (log/error (u/format-color 'red "Error syncing _metabase_metadata: no matching keypath: %s" keypath)))))) |
Is this TABLE the special | (mu/defn is-metabase-metadata-table? [table :- i/DatabaseMetadataTable] (= "_metabase_metadata" (u/lower-case-en (:name table)))) |
Sync the | (mu/defn sync-metabase-metadata! ([database :- i/DatabaseInstance] (sync-metabase-metadata! database (fetch-metadata/db-metadata database))) ([database :- i/DatabaseInstance db-metadata] (sync-util/with-error-handling (format "Error syncing _metabase_metadata table for %s" (sync-util/name-for-logging database)) (let [driver (driver.u/database->driver database)] ;; `sync-metabase-metadata-table!` relies on `driver/table-rows-seq` being defined (when (get-method driver/table-rows-seq driver) ;; If there's more than one metabase metadata table (in different schemas) we'll sync each one in turn. ;; Hopefully this is never the case. (doseq [table (:tables db-metadata)] (when (is-metabase-metadata-table? table) (sync-metabase-metadata-table! driver database table)))) {})))) |