diff --git a/enterprise/backend/test/metabase_enterprise/models/entity_id_test.clj b/enterprise/backend/test/metabase_enterprise/models/entity_id_test.clj index f1f8ddcb28a3cb7f82532492782fe195d22c5ac7..76b2bf5642e223f896487e1f12b90dc06a3e6656 100644 --- a/enterprise/backend/test/metabase_enterprise/models/entity_id_test.clj +++ b/enterprise/backend/test/metabase_enterprise/models/entity_id_test.clj @@ -46,7 +46,7 @@ :metabase.models.collection.root/RootCollection :metabase.models.collection-permission-graph-revision/CollectionPermissionGraphRevision :model/DashboardCardSeries - :metabase.models.field-values/FieldValues + :model/FieldValues :metabase.models.login-history/LoginHistory :metabase.models.metric-important-field/MetricImportantField :metabase.models.moderation-review/ModerationReview diff --git a/src/metabase/models/dimension.clj b/src/metabase/models/dimension.clj index 2f8e713bf1de1a88b8a2d08a3dbed79a39a4b571..81c4bb8afbcf323ec582b3d66c62de49353cda47 100644 --- a/src/metabase/models/dimension.clj +++ b/src/metabase/models/dimension.clj @@ -6,22 +6,30 @@ [metabase.models.interface :as mi] [metabase.models.serialization :as serdes] [metabase.util.date-2 :as u.date] - [toucan.models :as models])) + [methodical.core :as methodical] + [toucan2.core :as t2])) ;;; Possible values for Dimension.type : ;;; ;;; :internal ;;; :external -(models/defmodel Dimension :dimension) +(def Dimension + "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], now it's a reference to the toucan2 model name. + We'll keep this till we replace all the symbols in our codebase." + :model/Dimension) -(mi/define-methods - Dimension - {:types (constantly {:type :keyword}) - :properties (constantly {::mi/timestamped? true - ::mi/entity-id true})}) +(methodical/defmethod t2/table-name :model/Dimension [_model] :dimension) -(defmethod serdes/hash-fields Dimension +(doto :model/Dimension + (derive :metabase/model) + (derive :hook/entity-id) + (derive :hook/timestamped?)) + +(t2/deftransforms :model/Dimension + {:type mi/transform-keyword}) + +(defmethod serdes/hash-fields :model/Dimension [_dimension] [(serdes/hydrated-hash :field) (serdes/hydrated-hash :human_readable_field) diff --git a/src/metabase/models/field_values.clj b/src/metabase/models/field_values.clj index 41508c7d0ae454907179c361a06b18624b657e30..228acfb025c26f54ff238e556384ccac89a3989a 100644 --- a/src/metabase/models/field_values.clj +++ b/src/metabase/models/field_values.clj @@ -29,9 +29,9 @@ [metabase.util.i18n :refer [trs tru]] [metabase.util.log :as log] [metabase.util.schema :as su] + [methodical.core :as methodical] [schema.core :as s] [toucan.db :as db] - [toucan.models :as models] [toucan2.core :as t2])) (def ^Integer category-cardinality-threshold @@ -77,7 +77,21 @@ ;;; | Entity & Lifecycle | ;;; +----------------------------------------------------------------------------------------------------------------+ -(models/defmodel FieldValues :metabase_fieldvalues) +(def FieldValues + "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], now it's a reference to the toucan2 model name. + We'll keep this till we replace all the symbols in our codebase." + :model/FieldValues) + +(methodical/defmethod t2/table-name :model/FieldValues [_model] :metabase_fieldvalues) + +(doto :model/FieldValues + (derive :metabase/model) + (derive :hook/timestamped?)) + +(t2/deftransforms :model/FieldValues + {:human_readable_values mi/transform-json-no-keywordization + :values mi/transform-json + :type mi/transform-keyword}) (defn- assert-valid-human-readable-values [{human-readable-values :human_readable_values}] (when (s/check (s/maybe [(s/maybe su/NonBlankString)]) human-readable-values) @@ -117,7 +131,8 @@ [field-or-id] (t2/delete! FieldValues :field_id (u/the-id field-or-id))) -(defn- pre-insert [{:keys [field_id] :as field-values}] +(t2/define-before-insert :model/FieldValues + [{:keys [field_id] :as field-values}] (u/prog1 (merge {:type :full} field-values) (assert-valid-human-readable-values field-values) @@ -126,22 +141,23 @@ (when (= (:type <>) :full) (clear-advanced-field-values-for-field! field_id)))) -(defn- pre-update [{:keys [id type field_id values hash_key] :as field-values}] - (u/prog1 field-values - (assert-valid-human-readable-values field-values) - (when (or type hash_key) - (throw (ex-info (tru "Can't update type or hash_key for a FieldValues.") - {:type type - :hash_key hash_key - :status-code 400}))) - ;; if we're updating the values of a Full FieldValues, delete all Advanced FieldValues of this field - (when (and values - (= (or type (t2/select-one-fn :type FieldValues :id id)) - :full)) - (clear-advanced-field-values-for-field! (or field_id - (t2/select-one-fn :field_id FieldValues :id id)))))) - -(defn- post-select [field-values] +(t2/define-before-update :model/FieldValues + [field-values] + (let [{:keys [type values hash_key]} (t2/changes field-values)] + (u/prog1 field-values + (assert-valid-human-readable-values field-values) + (when (or type hash_key) + (throw (ex-info (tru "Can't update type or hash_key for a FieldValues.") + {:type type + :hash_key hash_key + :status-code 400}))) + ;; if we're updating the values of a Full FieldValues, delete all Advanced FieldValues of this field + (when (and values + (= (:type field-values) :full)) + (clear-advanced-field-values-for-field! (:field_id field-values)))))) + +(t2/define-after-select :model/FieldValues + [field-values] (cond-> field-values (contains? field-values :human_readable_values) (update :human_readable_values (fn [human-readable-values] @@ -163,17 +179,8 @@ :else []))))) -(mi/define-methods - FieldValues - {:properties (constantly {::mi/timestamped? true}) - :types (constantly {:human_readable_values :json-no-keywordization - :values :json - :type :keyword}) - :pre-insert pre-insert - :pre-update pre-update - :post-select post-select}) - -(defmethod serdes/hash-fields FieldValues + +(defmethod serdes/hash-fields :model/FieldValues [_field-values] [(serdes/hydrated-hash :field)]) diff --git a/src/metabase/models/interface.clj b/src/metabase/models/interface.clj index 4b26ee1e095f7de06ee087a8e5451459f87727b3..d2d6f6fd598ab0f441d1f3f0e1917c33c7562ff1 100644 --- a/src/metabase/models/interface.clj +++ b/src/metabase/models/interface.clj @@ -405,6 +405,11 @@ {:in json-in :out json-out-with-keywordization}) +(def transform-json-no-keywordization + "Transform for json-no-keywordization" + {:in json-in + :out json-out-without-keywordization}) + (def transform-encrypted-json "Transform for encrypted json." {:in encrypted-json-in diff --git a/src/metabase/models/params.clj b/src/metabase/models/params.clj index ba818326ee63b3f05d5c81d3284b08b71b3a14a5..8c2d22431285256e7ee108b4e08174874c77af1a 100644 --- a/src/metabase/models/params.clj +++ b/src/metabase/models/params.clj @@ -25,7 +25,8 @@ [metabase.util.schema :as su] [schema.core :as s] [toucan.hydrate :refer [hydrate]] - [toucan2.core :as t2])) + [toucan2.core :as t2] + [toucan2.realize :as t2.realize])) ;;; +----------------------------------------------------------------------------------------------------------------+ ;;; | SHARED | @@ -77,7 +78,8 @@ (defn- field-ids->param-field-values-ignoring-current-user [param-field-ids] - (t2/select-fn->fn :field_id identity ['FieldValues :values :human_readable_values :field_id] + (t2/select-fn->fn :field_id (comp identity t2.realize/realize) + ['FieldValues :values :human_readable_values :field_id] :type :full :field_id [:in param-field-ids])) diff --git a/test/metabase/test/util.clj b/test/metabase/test/util.clj index e04f92598e5d82dff7b1ed4af05e13a755d13fc0..f12663e4561bd16e1c40029252975f163bfa0fe4 100644 --- a/test/metabase/test/util.clj +++ b/test/metabase/test/util.clj @@ -143,7 +143,7 @@ :is_sample false :name (tu.random/random-name)}) - Dimension + :model/Dimension (fn [_] {:name (tu.random/random-name) :type "internal"})