From 647181fcd6bcf94943641bc2db7b7053bb885774 Mon Sep 17 00:00:00 2001
From: Ngoc Khuat <qn.khuat@gmail.com>
Date: Fri, 16 Jun 2023 12:38:45 +0700
Subject: [PATCH] =?UTF-8?q?Rest=20of=20models=20to=20toucan2=20?=
 =?UTF-8?q?=F0=9F=8E=89=20(#31385)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* User to toucan2

* Pulse to toucan2

* PulseCard to toucan 2

* PulseChannel and PulseChannelRecipient to toucan2

* Query, QueryCache, QueryExecution to toucan2

* Metric, Segment, MetricImportantField to toucan2

* ParameterCard to toucan2

* DataMigrations and FakeCard to toucan2

* NativeQuerySnippet to toucan2
---
 .../models/entity_id_test.clj                 | 23 +++--
 src/metabase/db/data_migrations.clj           | 13 ++-
 src/metabase/lib/metadata/jvm.clj             |  4 +-
 src/metabase/models/interface.clj             |  5 +
 src/metabase/models/metric.clj                | 32 ++++---
 .../models/metric_important_field.clj         | 18 ++--
 src/metabase/models/native_query_snippet.clj  | 36 ++++----
 src/metabase/models/parameter_card.clj        | 38 ++++----
 src/metabase/models/pulse.clj                 | 38 ++++----
 src/metabase/models/pulse_card.clj            | 16 ++--
 src/metabase/models/pulse_channel.clj         | 47 ++++++----
 .../models/pulse_channel_recipient.clj        | 17 +++-
 src/metabase/models/query.clj                 | 21 +++--
 src/metabase/models/query_cache.clj           | 18 ++--
 src/metabase/models/query_execution.clj       | 32 +++++--
 src/metabase/models/segment.clj               | 33 ++++---
 src/metabase/models/user.clj                  | 92 +++++++++++--------
 test/metabase/models/revision_test.clj        | 56 +++++------
 test/metabase/models/user_test.clj            | 12 +--
 test/metabase/test/util.clj                   | 20 ++--
 20 files changed, 328 insertions(+), 243 deletions(-)

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 6c0cae6fa03..7c23b26ccd4 100644
--- a/enterprise/backend/test/metabase_enterprise/models/entity_id_test.clj
+++ b/enterprise/backend/test/metabase_enterprise/models/entity_id_test.clj
@@ -33,7 +33,7 @@
   - not exported in serialization; or
   - exported as a child of something else (eg. timeline_event under timeline)
   so they don't need a generated entity_id."
-  #{:metabase.db.data-migrations/DataMigrations
+  #{:model/DataMigrations
     :model/HTTPAction
     :model/ImplicitAction
     :model/QueryAction
@@ -46,32 +46,31 @@
     :metabase.models.collection.root/RootCollection
     :metabase.models.collection-permission-graph-revision/CollectionPermissionGraphRevision
     :model/DashboardCardSeries
-    :metabase.models.field-values/FieldValues
     :model/LoginHistory
     :model/FieldValues
-    :metabase.models.metric-important-field/MetricImportantField
+    :model/MetricImportantField
     :model/ModelIndex
     :model/ModelIndexValue
     :model/ModerationReview
-    :metabase.models.parameter-card/ParameterCard
+    :model/ParameterCard
     :metabase.models.permissions/Permissions
     :metabase.models.permissions-group/PermissionsGroup
     :metabase.models.permissions-group-membership/PermissionsGroupMembership
     :metabase.models.permissions-revision/PermissionsRevision
     :model/PersistedInfo
-    :metabase.models.pulse-card/PulseCard
-    :metabase.models.pulse-channel/PulseChannel
-    :metabase.models.pulse-channel-recipient/PulseChannelRecipient
-    :metabase.models.query/Query
-    :metabase.models.query-cache/QueryCache
-    :metabase.models.query-execution/QueryExecution
+    :model/PulseCard
+    :model/PulseChannel
+    :model/PulseChannelRecipient
+    :model/Query
+    :model/QueryCache
+    :model/QueryExecution
     :model/Revision
-    :metabase.models.revision-test/FakedCard
+    :model/FakedCard
     :model/Secret
     :model/Session
     :model/TaskHistory
     :model/TimelineEvent
-    :metabase.models.user/User
+    :model/User
     :model/ViewLog
     :metabase-enterprise.sandbox.models.group-table-access-policy/GroupTableAccessPolicy})
 
diff --git a/src/metabase/db/data_migrations.clj b/src/metabase/db/data_migrations.clj
index 7744de6d08c..ca853b241c9 100644
--- a/src/metabase/db/data_migrations.clj
+++ b/src/metabase/db/data_migrations.clj
@@ -17,14 +17,19 @@
    [metabase.models.setting :as setting :refer [Setting]]
    [metabase.util :as u]
    [metabase.util.log :as log]
-   [toucan.models :as models]
+   [methodical.core :as methodical]
    [toucan2.core :as t2]))
 
 (set! *warn-on-reflection* true)
 
 ;;; # Migration Helpers
+(def DataMigrations
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/DataMigrations)
 
-(models/defmodel ^:deprecated DataMigrations :data_migrations)
+(methodical/defmethod t2/table-name :model/DataMigrations [_model] :data_migrations)
+(derive :model/DataMigrations :metabase/model)
 
 (defn- ^:deprecated run-migration-if-needed!
   "Run migration defined by `migration-var` if needed. `ran-migrations` is a set of migrations names that have already
@@ -45,7 +50,7 @@
          (if catch?
            (log/warn (format "Data migration %s failed: %s" migration-name (.getMessage e)))
            (throw e))))
-      (t2/insert! DataMigrations
+      (t2/insert! :model/DataMigrations
         :id        migration-name
         :timestamp :%now))))
 
@@ -62,7 +67,7 @@
   "Run all data migrations defined by `defmigration`."
   []
   (log/info "Running all necessary data migrations, this may take a minute.")
-  (let [ran-migrations (t2/select-pks-set DataMigrations)]
+  (let [ran-migrations (t2/select-pks-set :model/DataMigrations)]
     (doseq [migration @data-migrations]
       (run-migration-if-needed! ran-migrations migration)))
   (log/info "Finished running data migrations."))
diff --git a/src/metabase/lib/metadata/jvm.clj b/src/metabase/lib/metadata/jvm.clj
index 2435a5df2c5..28ad6b985a0 100644
--- a/src/metabase/lib/metadata/jvm.clj
+++ b/src/metabase/lib/metadata/jvm.clj
@@ -15,8 +15,8 @@
     :metadata/table    :model/Table
     :metadata/field    :model/Field
     :metadata/card     :model/Card
-    :metadata/metric   :metabase.models.metric/Metric
-    :metadata/segment  :metabase.models.segment/Segment))
+    :metadata/metric   :model/Metric
+    :metadata/segment  :model/Segment))
 
 (defn- instance->metadata [instance metadata-type]
   (some-> instance
diff --git a/src/metabase/models/interface.clj b/src/metabase/models/interface.clj
index 75d8f83705b..71ac57d770a 100644
--- a/src/metabase/models/interface.clj
+++ b/src/metabase/models/interface.clj
@@ -446,6 +446,11 @@
   {:in  validate-cron-string
    :out identity})
 
+(def transform-metric-segment-definition
+  "Transform for inner queries like those in Metric definitions."
+  {:in  (comp json-in normalize-metric-segment-definition)
+   :out (comp (catch-normalization-exceptions normalize-metric-segment-definition) json-out-with-keywordization)})
+
 ;; --- predefined hooks
 
 (t2/define-before-insert :hook/timestamped?
diff --git a/src/metabase/models/metric.clj b/src/metabase/models/metric.clj
index b5b6f6b07af..76561a23ec7 100644
--- a/src/metabase/models/metric.clj
+++ b/src/metabase/models/metric.clj
@@ -20,22 +20,33 @@
    [metabase.util.log :as log]
    [metabase.util.malli :as mu]
    [methodical.core :as methodical]
-   [toucan.models :as models]
    [toucan2.core :as t2]
    [toucan2.tools.hydrate :as t2.hydrate]))
 
-(models/defmodel Metric :metric)
+(def Metric
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/Metric)
 
-(doto Metric
+(methodical/defmethod t2/table-name :model/Metric [_model] :metric)
+
+(doto :model/Metric
+  (derive :metabase/model)
+  (derive :hook/timestamped?)
+  (derive :hook/entity-id)
   (derive ::mi/read-policy.full-perms-for-perms-set)
   (derive ::mi/write-policy.superuser)
   (derive ::mi/create-policy.superuser))
 
-(defn- pre-update [{:keys [creator_id id], :as updates}]
-  (u/prog1 updates
+(t2/deftransforms :model/Metric
+  {:definition mi/transform-metric-segment-definition})
+
+(t2/define-before-update :model/Metric
+  [{:keys [creator_id id], :as metric}]
+  (u/prog1 (t2/changes metric)
     ;; throw an Exception if someone tries to update creator_id
-    (when (contains? updates :creator_id)
-      (when (not= creator_id (t2/select-one-fn :creator_id Metric :id id))
+    (when (contains? <> :creator_id)
+      (when (not= (:creator_id <>) (t2/select-one-fn :creator_id Metric :id id))
         (throw (UnsupportedOperationException. (tru "You cannot update the creator_id of a Metric.")))))))
 
 (defmethod mi/perms-objects-set Metric
@@ -44,13 +55,6 @@
                   (t2/select-one ['Table :db_id :schema :id] :id (u/the-id (:table_id metric))))]
     (mi/perms-objects-set table read-or-write)))
 
-(mi/define-methods
- Metric
- {:types      (constantly {:definition :metric-segment-definition})
-  :properties (constantly {::mi/timestamped? true
-                           ::mi/entity-id    true})
-  :pre-update pre-update})
-
 (mu/defn ^:private definition-description :- [:maybe ::lib.schema.common/non-blank-string]
   "Calculate a nice description of a Metric's definition."
   [metadata-provider :- lib.metadata/MetadataProvider
diff --git a/src/metabase/models/metric_important_field.clj b/src/metabase/models/metric_important_field.clj
index bf88ba2ce75..630e8b5d268 100644
--- a/src/metabase/models/metric_important_field.clj
+++ b/src/metabase/models/metric_important_field.clj
@@ -2,14 +2,20 @@
   "Intersection table for `Metric` and `Field`; this is used to keep track of the top 0-3 important fields for a metric as shown in the Getting Started guide."
   (:require
    [metabase.models.interface :as mi]
-   [toucan.models :as models]))
+   [methodical.core :as methodical]
+   [toucan2.core :as t2]))
 
-(models/defmodel MetricImportantField :metric_important_field)
+(def MetricImportantField
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/MetricImportantField)
 
-(doto MetricImportantField
+(methodical/defmethod t2/table-name :model/MetricImportantField [_model] :metric_important_field)
+
+(doto :model/MetricImportantField
+  (derive :metabase/model)
   (derive ::mi/read-policy.always-allow)
   (derive ::mi/write-policy.superuser))
 
-(mi/define-methods
- MetricImportantField
- {:types (constantly {:definition :json})})
+(t2/deftransforms :model/MetricImportantField
+ {:definition mi/transform-json})
diff --git a/src/metabase/models/native_query_snippet.clj b/src/metabase/models/native_query_snippet.clj
index 4577c9c0a91..793dbb19d7a 100644
--- a/src/metabase/models/native_query_snippet.clj
+++ b/src/metabase/models/native_query_snippet.clj
@@ -7,36 +7,40 @@
    [metabase.util :as u]
    [metabase.util.i18n :refer [deferred-tru tru]]
    [metabase.util.schema :as su]
+   [methodical.core :as methodical]
    [schema.core :as s]
-   [toucan.models :as models]
    [toucan2.core :as t2]))
 
 ;;; ----------------------------------------------- Entity & Lifecycle -----------------------------------------------
 
-(models/defmodel NativeQuerySnippet :native_query_snippet)
+(def NativeQuerySnippet
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/NativeQuerySnippet)
 
-(defmethod collection/allowed-namespaces NativeQuerySnippet
+(methodical/defmethod t2/table-name :model/NativeQuerySnippet [_model] :native_query_snippet)
+
+(doto :model/NativeQuerySnippet
+  (derive :metabase/model)
+  (derive :hook/timestamped?)
+  (derive :hook/entity-id))
+
+(defmethod collection/allowed-namespaces :model/NativeQuerySnippet
   [_]
   #{:snippets})
 
-(defn- pre-insert [snippet]
+(t2/define-before-insert :model/NativeQuerySnippet [snippet]
   (u/prog1 snippet
     (collection/check-collection-namespace NativeQuerySnippet (:collection_id snippet))))
 
-(defn- pre-update [{:keys [creator_id id], :as updates}]
-  (u/prog1 updates
+(t2/define-before-update :model/NativeQuerySnippet
+  [{:keys [creator_id id], :as snippet}]
+  (u/prog1 (t2/changes snippet)
     ;; throw an Exception if someone tries to update creator_id
-    (when (contains? updates :creator_id)
-      (when (not= creator_id (t2/select-one-fn :creator_id NativeQuerySnippet :id id))
+    (when (contains? <> :creator_id)
+      (when (not= (:creator_id <>) (t2/select-one-fn :creator_id NativeQuerySnippet :id id))
         (throw (UnsupportedOperationException. (tru "You cannot update the creator_id of a NativeQuerySnippet.")))))
-    (collection/check-collection-namespace NativeQuerySnippet (:collection_id updates))))
-
-(mi/define-methods
- NativeQuerySnippet
- {:properties (constantly {::mi/timestamped? true
-                           ::mi/entity-id    true})
-  :pre-insert pre-insert
-  :pre-update pre-update})
+    (collection/check-collection-namespace NativeQuerySnippet (:collection_id snippet))))
 
 (defmethod serdes/hash-fields NativeQuerySnippet
   [_snippet]
diff --git a/src/metabase/models/parameter_card.clj b/src/metabase/models/parameter_card.clj
index 147ed89ed6c..4601c827a18 100644
--- a/src/metabase/models/parameter_card.clj
+++ b/src/metabase/models/parameter_card.clj
@@ -5,10 +5,24 @@
    [metabase.util.i18n :refer [tru]]
    [metabase.util.malli :as mu]
    [metabase.util.malli.schema :as ms]
-   [toucan.models :as models]
+   [methodical.core :as methodical]
    [toucan2.core :as t2]))
 
-(models/defmodel ParameterCard :parameter_card)
+;;; ----------------------------------------------- Entity & Lifecycle -----------------------------------------------
+(def ParameterCard
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/ParameterCard)
+
+(methodical/defmethod t2/table-name :model/ParameterCard [_model] :parameter_card)
+
+(doto :model/ParameterCard
+  (derive :metabase/model)
+  (derive :hook/timestamped?)
+  (derive :hook/entity-id))
+
+(t2/deftransforms :model/ParameterCard
+ {:parameterized_object_type mi/transform-keyword})
 
 (defonce ^{:doc "Set of valid parameterized_object_type for a ParameterCard"}
   valid-parameterized-object-type #{"dashboard" "card"})
@@ -19,26 +33,16 @@
     (throw (ex-info (tru "invalid parameterized_object_type")
                     {:allowed-types valid-parameterized-object-type}))))
 
-;;; ----------------------------------------------- Entity & Lifecycle -----------------------------------------------
-
-(defn- pre-insert
+(t2/define-before-insert :model/ParameterCard
   [pc]
   (u/prog1 pc
     (validate-parameterized-object-type pc)))
 
-(defn- pre-update
+(t2/define-before-update :model/ParameterCard
   [pc]
-  (u/prog1 pc
-    (when (:parameterized_object_type pc)
-      (validate-parameterized-object-type pc))))
-
-(mi/define-methods
- ParameterCard
- {:properties (constantly {::mi/timestamped? true
-                           ::mi/entity-id    true})
-  :types      (constantly {:parameterized_object_type :keyword})
-  :pre-insert pre-insert
-  :pre-update pre-update})
+  (u/prog1 (t2/changes pc)
+    (when (:parameterized_object_type <>)
+      (validate-parameterized-object-type <>))))
 
 (defn delete-all-for-parameterized-object!
   "Delete all ParameterCard for a give Parameterized Object and NOT listed in the optional
diff --git a/src/metabase/models/pulse.clj b/src/metabase/models/pulse.clj
index ee76bc2af22..b44a14c8600 100644
--- a/src/metabase/models/pulse.clj
+++ b/src/metabase/models/pulse.clj
@@ -32,22 +32,36 @@
    [metabase.util :as u]
    [metabase.util.i18n :refer [deferred-tru tru]]
    [metabase.util.schema :as su]
+   [methodical.core :as methodical]
    [schema.core :as s]
-   [toucan.models :as models]
    [toucan2.core :as t2]))
 
 ;;; ----------------------------------------------- Entity & Lifecycle -----------------------------------------------
 
-(models/defmodel Pulse :pulse)
+(def Pulse
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/Pulse)
 
-(derive Pulse ::mi/read-policy.full-perms-for-perms-set)
+(methodical/defmethod t2/table-name :model/Pulse [_model] :pulse)
+(methodical/defmethod t2/model-for-automagic-hydration [:default :pulse]  [_original-model _k] :model/Pulse)
+
+(doto :model/Pulse
+  (derive :metabase/model)
+  (derive :hook/timestamped?)
+  (derive :hook/entity-id)
+  (derive ::mi/read-policy.full-perms-for-perms-set))
+
+(t2/deftransforms :model/Pulse
+  {:parameters mi/transform-json})
 
 (defn- assert-valid-parameters [{:keys [parameters]}]
   (when (s/check (s/maybe [{:id su/NonBlankString, s/Keyword s/Any}]) parameters)
     (throw (ex-info (tru ":parameters must be a sequence of maps with String :id keys")
                     {:parameters parameters}))))
 
-(defn- pre-insert [notification]
+(t2/define-before-insert :model/Pulse
+  [notification]
   (let [defaults      {:parameters []}
         dashboard-id  (:dashboard_id notification)
         collection-id (if dashboard-id
@@ -66,8 +80,9 @@
   only be done when the associated dashboard is being moved to a new collection."
   false)
 
-(defn- pre-update [notification]
-  (let [{:keys [collection_id dashboard_id]} (t2/select-one [Pulse :collection_id :dashboard_id] :id (u/the-id notification))]
+(t2/define-before-update :model/Pulse
+  [notification]
+  (let [{:keys [collection_id dashboard_id]} (t2/original notification)]
     (when (and dashboard_id
                (contains? notification :collection_id)
                (not= (:collection_id notification) collection_id)
@@ -77,7 +92,7 @@
                (contains? notification :dashboard_id)
                (not= (:dashboard_id notification) dashboard_id))
       (throw (ex-info (tru "dashboard ID of a dashboard subscription cannot be modified") notification))))
-  (u/prog1 notification
+  (u/prog1 (t2/changes notification)
     (assert-valid-parameters notification)
     (collection/check-collection-namespace Pulse (:collection_id notification))))
 
@@ -143,15 +158,6 @@
         (and (mi/current-user-has-full-permissions? :read notification)
              (current-user-is-creator? notification)))))
 
-(mi/define-methods
- Pulse
- {:hydration-keys (constantly [:pulse])
-  :properties     (constantly {::mi/timestamped? true
-                               ::mi/entity-id    true})
-  :pre-insert     pre-insert
-  :pre-update     pre-update
-  :types          (constantly {:parameters :json})})
-
 (defmethod serdes/hash-fields Pulse
   [_pulse]
   [:name (serdes/hydrated-hash :collection) :created_at])
diff --git a/src/metabase/models/pulse_card.clj b/src/metabase/models/pulse_card.clj
index f92e854bc18..a3c37ce765a 100644
--- a/src/metabase/models/pulse_card.clj
+++ b/src/metabase/models/pulse_card.clj
@@ -1,18 +1,22 @@
 (ns metabase.models.pulse-card
   (:require
-   [metabase.models.interface :as mi]
    [metabase.models.serialization :as serdes]
    [metabase.util :as u]
    [metabase.util.schema :as su]
+   [methodical.core :as methodical]
    [schema.core :as s]
-   [toucan.models :as models]
    [toucan2.core :as t2]))
 
-(models/defmodel PulseCard :pulse_card)
+(def PulseCard
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/PulseCard)
 
-(mi/define-methods
- PulseCard
- {:properties (constantly {::mi/entity-id true})})
+(methodical/defmethod t2/table-name :model/PulseCard [_model] :pulse_card)
+
+(doto :model/PulseCard
+  (derive :metabase/model)
+  (derive :hook/entity-id))
 
 (defmethod serdes/hash-fields PulseCard
   [_pulse-card]
diff --git a/src/metabase/models/pulse_channel.clj b/src/metabase/models/pulse_channel.clj
index d0b9096af3e..59bd8d40ce4 100644
--- a/src/metabase/models/pulse_channel.clj
+++ b/src/metabase/models/pulse_channel.clj
@@ -12,7 +12,6 @@
    [metabase.util.i18n :refer [tru]]
    [methodical.core :as methodical]
    [schema.core :as s]
-   [toucan.models :as models]
    [toucan2.core :as t2]))
 
 ;; ## Static Definitions
@@ -113,12 +112,27 @@
 
 ;; ## Entity
 
-(models/defmodel PulseChannel :pulse_channel)
+(def PulseChannel
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/PulseChannel)
 
-(doto PulseChannel
+(methodical/defmethod t2/table-name :model/PulseChannel [_model] :pulse_channel)
+(methodical/defmethod t2/model-for-automagic-hydration [:default :pulse_channel] [_original-model _k] :model/PulseChannel)
+
+(doto :model/PulseChannel
+  (derive :metabase/model)
+  (derive :hook/timestamped?)
+  (derive :hook/entity-id)
   (derive ::mi/read-policy.always-allow)
   (derive ::mi/write-policy.superuser))
 
+(t2/deftransforms :model/PulseChannel
+ {:details mi/transform-json
+  :channel_type mi/transform-keyword
+  :schedule_type mi/transform-keyword
+  :schedule_frame mi/transform-keyword})
+
 (mi/define-simple-hydration-method recipients
   :recipients
   "Return the `PulseChannelRecipients` associated with this `pulse-channel`."
@@ -141,14 +155,14 @@
   in [[update-notification-channels!]] which creates/deletes/updates several channels sequentially."
   true)
 
-(defn- pre-delete
-  "This function is called by [[metabase.models.pulse-channel/pre-delete]] when the `PulseChannel` is about to be
-  deleted. Archives `Pulse` if the channel being deleted is its last channel."
+(t2/define-before-delete :model/PulseChannel
   [{pulse-id :pulse_id, pulse-channel-id :id}]
+  ;; This function is called by [[metabase.models.pulse-channel/pre-delete]] when the `PulseChannel` is about to be
+  ;; deleted. Archives `Pulse` if the channel being deleted is its last channel."
   (when *archive-parent-pulse-when-last-channel-is-deleted*
     (let [other-channels-count (t2/count PulseChannel :pulse_id pulse-id, :id [:not= pulse-channel-id])]
       (when (zero? other-channels-count)
-        (t2/update! :metabase.models.pulse/Pulse pulse-id {:archived true})))))
+        (t2/update! :model/Pulse pulse-id {:archived true})))))
 
 ;; we want to load this at the top level so the Setting the namespace defines gets loaded
 (def ^:private ^{:arglists '([email-addresses])} validate-email-domains*
@@ -193,18 +207,13 @@
               (throw (ex-info (tru "Wrong email address for User {0}." id)
                               {:status-code 403})))))))))
 
-(mi/define-methods
- PulseChannel
- {:hydration-keys (constantly [:pulse_channel])
-  :types          (constantly {:details        :json
-                               :channel_type   :keyword
-                               :schedule_type  :keyword
-                               :schedule_frame :keyword})
-  :properties     (constantly {::mi/timestamped? true
-                               ::mi/entity-id    true})
-  :pre-delete     pre-delete
-  :pre-insert     validate-email-domains
-  :pre-update     validate-email-domains})
+(t2/define-before-insert :model/PulseChannel
+  [pulse-channel]
+  (validate-email-domains pulse-channel))
+
+(t2/define-before-update :model/PulseChannel
+  [pulse-channel]
+  (validate-email-domains (mi/pre-update-changes pulse-channel)))
 
 (defmethod serdes/hash-fields PulseChannel
   [_pulse-channel]
diff --git a/src/metabase/models/pulse_channel_recipient.clj b/src/metabase/models/pulse_channel_recipient.clj
index 77c339f654e..b3493e49593 100644
--- a/src/metabase/models/pulse_channel_recipient.clj
+++ b/src/metabase/models/pulse_channel_recipient.clj
@@ -1,14 +1,21 @@
 (ns metabase.models.pulse-channel-recipient
   (:require
-   [toucan.models :as models]
+   [methodical.core :as methodical]
    [toucan2.core :as t2]))
 
-(models/defmodel PulseChannelRecipient :pulse_channel_recipient)
+(def PulseChannelRecipient
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/PulseChannelRecipient)
+
+(methodical/defmethod t2/table-name :model/PulseChannelRecipient [_model] :pulse_channel_recipient)
+
+(derive :model/PulseChannelRecipient :metabase/model)
 
 ;;; Deletes `PulseChannel` if the recipient being deleted is its last recipient. (This only applies
 ;;; to PulseChannels with User subscriptions; Slack PulseChannels and ones with email address subscriptions are not
 ;;; automatically deleted.
-(t2/define-before-delete PulseChannelRecipient
+(t2/define-before-delete :model/PulseChannelRecipient
   [{channel-id :pulse_channel_id, pulse-channel-recipient-id :id}]
   (let [other-recipients-count (t2/count PulseChannelRecipient
                                          :pulse_channel_id channel-id
@@ -16,7 +23,7 @@
         last-recipient?        (zero? other-recipients-count)]
     (when last-recipient?
       ;; make sure this channel doesn't have any email-address (non-User) recipients.
-      (let [details              (t2/select-one-fn :details :metabase.models.pulse-channel/PulseChannel :id channel-id)
+      (let [details              (t2/select-one-fn :details :model/PulseChannel :id channel-id)
             has-email-addresses? (seq (:emails details))]
         (when-not has-email-addresses?
-          (t2/delete! :metabase.models.pulse-channel/PulseChannel :id channel-id))))))
+          (t2/delete! :model/PulseChannel :id channel-id))))))
diff --git a/src/metabase/models/query.clj b/src/metabase/models/query.clj
index 3e07bf17297..c3950983a7f 100644
--- a/src/metabase/models/query.clj
+++ b/src/metabase/models/query.clj
@@ -7,17 +7,24 @@
    [metabase.mbql.normalize :as mbql.normalize]
    [metabase.models.interface :as mi]
    [metabase.util.honey-sql-2 :as h2x]
-   [toucan.models :as models]
-   [toucan2.core :as t2]))
+   [methodical.core :as methodical]
+   [toucan2.core :as t2]
+   [toucan2.model :as t2.model]))
 
 (set! *warn-on-reflection* true)
 
-(models/defmodel Query :query)
+(def Query
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/Query)
 
-(mi/define-methods
- Query
- {:types       (constantly {:query :json})
-  :primary-key (constantly :query_hash)})
+(methodical/defmethod t2/table-name :model/Query [_model] :query)
+(methodical/defmethod t2.model/primary-keys :model/Query [_model] [:query_hash])
+
+(t2/deftransforms :model/Query
+ {:query mi/transform-json})
+
+(derive :model/Query :metabase/model)
 
 ;;; Helper Fns
 
diff --git a/src/metabase/models/query_cache.clj b/src/metabase/models/query_cache.clj
index 80f0961d4d7..d544d52d70d 100644
--- a/src/metabase/models/query_cache.clj
+++ b/src/metabase/models/query_cache.clj
@@ -1,17 +1,17 @@
 (ns metabase.models.query-cache
   "A model used to cache query results in the database."
   (:require
-   [metabase.models.interface :as mi]
    [methodical.core :as methodical]
-   [toucan.models :as models]
    [toucan2.core :as t2]))
 
-(models/defmodel QueryCache :query_cache)
+(def QueryCache
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/QueryCache)
 
-(methodical/defmethod t2/primary-keys QueryCache
-  [_model]
-  [:query_hash])
+(methodical/defmethod t2/table-name :model/QueryCache [_model] :query_cache)
+(methodical/defmethod t2/primary-keys QueryCache [_model] [:query_hash])
 
-(mi/define-methods
- QueryCache
- {:properties (constantly {::mi/updated-at-timestamped? true})})
+(doto :model/QueryCache
+  (derive :metabase/model)
+  (derive :hook/updated-at-timestamped?))
diff --git a/src/metabase/models/query_execution.clj b/src/metabase/models/query_execution.clj
index f90785ce667..a75f3c03b1d 100644
--- a/src/metabase/models/query_execution.clj
+++ b/src/metabase/models/query_execution.clj
@@ -6,25 +6,37 @@
    [metabase.models.interface :as mi]
    [metabase.util :as u]
    [metabase.util.i18n :refer [tru]]
+   [methodical.core :as methodical]
    [schema.core :as s]
-   [toucan.models :as models]))
+   [toucan2.core :as t2]))
 
-(models/defmodel QueryExecution :query_execution)
+(def QueryExecution
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/QueryExecution)
+
+(methodical/defmethod t2/table-name :model/QueryExecution [_model] :query_execution)
+
+(derive :model/QueryExecution :metabase/model)
+
+(t2/deftransforms :model/QueryExecution
+  {:json_query mi/transform-json
+   :status     mi/transform-keyword
+   :context    mi/transform-keyword})
 
 (def ^:private ^{:arglists '([context])} validate-context
   (s/validator mbql.s/Context))
 
-(defn- pre-insert [{context :context, :as query-execution}]
+(t2/define-before-insert :model/QueryExecution
+  [{context :context, :as query-execution}]
   (u/prog1 query-execution
     (validate-context context)))
 
-(defn- post-select [{:keys [result_rows] :as query-execution}]
+(t2/define-after-select :model/QueryExecution
+  [{:keys [result_rows] :as query-execution}]
   ;; sadly we have 2 ways to reference the row count :(
   (assoc query-execution :row_count (or result_rows 0)))
 
-(mi/define-methods
- QueryExecution
- {:types       (constantly {:json_query :json, :status :keyword, :context :keyword})
-  :pre-insert  pre-insert
-  :pre-update  (fn [& _] (throw (Exception. (tru "You cannot update a QueryExecution!"))))
-  :post-select post-select})
+(t2/define-before-update :model/QueryExecution
+ [_query-execution]
+ (throw (Exception. (tru "You cannot update a QueryExecution!"))))
diff --git a/src/metabase/models/segment.clj b/src/metabase/models/segment.clj
index e96d3b2052e..97d6807ea49 100644
--- a/src/metabase/models/segment.clj
+++ b/src/metabase/models/segment.clj
@@ -19,22 +19,33 @@
    [metabase.util.log :as log]
    [metabase.util.malli :as mu]
    [methodical.core :as methodical]
-   [toucan.models :as models]
    [toucan2.core :as t2]
    [toucan2.tools.hydrate :as t2.hydrate]))
 
-(models/defmodel Segment :segment)
+(def Segment
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/Segment)
 
-(doto Segment
+(methodical/defmethod t2/table-name :model/Segment [_model] :segment)
+(methodical/defmethod t2/model-for-automagic-hydration [:default :segment] [_original-model _k] :model/Segment)
+
+(t2/deftransforms :model/Segment
+  {:definition mi/transform-metric-segment-definition})
+
+(doto :model/Segment
+  (derive :metabase/model)
+  (derive :hook/timestamped?)
+  (derive :hook/entity-id)
   (derive ::mi/read-policy.full-perms-for-perms-set)
   (derive ::mi/write-policy.superuser)
   (derive ::mi/create-policy.superuser))
 
-(defn- pre-update [{:keys [creator_id id], :as updates}]
-  (u/prog1 updates
+(t2/define-before-update :model/Segment  [{:keys [creator_id id], :as segment}]
+  (u/prog1 (t2/changes segment)
     ;; throw an Exception if someone tries to update creator_id
-    (when (contains? updates :creator_id)
-      (when (not= creator_id (t2/select-one-fn :creator_id Segment :id id))
+    (when (contains? <> :creator_id)
+      (when (not= (:creator_id <>) (t2/select-one-fn :creator_id Segment :id id))
         (throw (UnsupportedOperationException. (tru "You cannot update the creator_id of a Segment.")))))))
 
 (defmethod mi/perms-objects-set Segment
@@ -43,14 +54,6 @@
                   (t2/select-one ['Table :db_id :schema :id] :id (u/the-id (:table_id segment))))]
     (mi/perms-objects-set table read-or-write)))
 
-(mi/define-methods
- Segment
- {:types          (constantly {:definition :metric-segment-definition})
-  :properties     (constantly {::mi/timestamped? true
-                               ::mi/entity-id    true})
-  :hydration-keys (constantly [:segment])
-  :pre-update     pre-update})
-
 (mu/defn ^:private definition-description :- [:maybe ::lib.schema.common/non-blank-string]
   "Calculate a nice description of a Segment's definition."
   [metadata-provider :- lib.metadata/MetadataProvider
diff --git a/src/metabase/models/user.clj b/src/metabase/models/user.clj
index d5c1eaae5eb..3df58aefe03 100644
--- a/src/metabase/models/user.clj
+++ b/src/metabase/models/user.clj
@@ -21,9 +21,10 @@
    [metabase.util.log :as log]
    [metabase.util.password :as u.password]
    [metabase.util.schema :as su]
+   [methodical.core :as methodical]
    [schema.core :as schema]
-   [toucan.models :as models]
-   [toucan2.core :as t2])
+   [toucan2.core :as t2]
+   [toucan2.tools.default-fields :as t2.default-fields])
   (:import
    (java.util UUID)))
 
@@ -31,7 +32,24 @@
 
 ;;; ----------------------------------------------- Entity & Lifecycle -----------------------------------------------
 
-(models/defmodel User :core_user)
+(def User
+  "Used to be the toucan1 model name defined using [[toucan.models/defmodel]], not it's a reference to the toucan2 model name.
+  We'll keep this till we replace all these symbols in our codebase."
+  :model/User)
+
+(methodical/defmethod t2/table-name :model/User [_model] :core_user)
+(methodical/defmethod t2/model-for-automagic-hydration [:default :author]  [_original-model _k] :model/User)
+(methodical/defmethod t2/model-for-automagic-hydration [:default :creator] [_original-model _k] :model/User)
+(methodical/defmethod t2/model-for-automagic-hydration [:default :user]    [_original-model _k] :model/User)
+
+(doto :model/User
+  (derive :metabase/model)
+  (derive :hook/updated-at-timestamped?))
+
+(t2/deftransforms :model/User
+  {:login_attributes mi/transform-json-no-keywordization
+   :settings         mi/transform-encrypted-json
+   :sso_source       mi/transform-keyword})
 
 (def ^:private insert-default-values
   {:date_joined  :%now
@@ -50,7 +68,8 @@
       {:password_salt salt
        :password      (u.password/hash-bcrypt (str salt password))})))
 
-(defn- pre-insert [{:keys [email password reset_token locale], :as user}]
+(t2/define-before-insert :model/User
+  [{:keys [email password reset_token locale], :as user}]
   ;; these assertions aren't meant to be user-facing, the API endpoints should be validation these as well.
   (assert (u/email? email))
   (assert ((every-pred string? (complement str/blank?)) password))
@@ -69,7 +88,8 @@
    (when locale
      {:locale (i18n/normalized-locale-string locale)})))
 
-(defn- post-insert [{user-id :id, superuser? :is_superuser, :as user}]
+(t2/define-after-insert :model/User
+  [{user-id :id, superuser? :is_superuser, :as user}]
   (u/prog1 user
     ;; add the newly created user to the magic perms groups
     (binding [perms-group-membership/*allow-changing-all-users-group-members* true]
@@ -83,12 +103,16 @@
         :user_id  user-id
         :group_id (:id (perms-group/admin))))))
 
-(defn- pre-update
-  [{reset-token :reset_token, superuser? :is_superuser, active? :is_active, :keys [email id locale], :as user}]
+(t2/define-before-update :model/User
+  [{:keys [id] :as user}]
   ;; when `:is_superuser` is toggled add or remove the user from the 'Admin' group as appropriate
-  (let [in-admin-group?  (t2/exists? PermissionsGroupMembership
-                           :group_id (:id (perms-group/admin))
-                           :user_id  id)]
+  (let [{reset-token :reset_token
+         superuser? :is_superuser
+         active? :is_active
+         :keys [email locale]}    (t2/changes user)
+        in-admin-group?           (t2/exists? PermissionsGroupMembership
+                                              :group_id (:id (perms-group/admin))
+                                              :user_id  id)]
     ;; Do not let the last admin archive themselves
     (when (and in-admin-group?
                (false? active?))
@@ -105,22 +129,22 @@
         (and (not superuser?)
              in-admin-group?)
         (t2/delete! (t2/table-name PermissionsGroupMembership)
-          :group_id (u/the-id (perms-group/admin))
-          :user_id  id))))
-  ;; make sure email and locale are valid if set
-  (when email
-    (assert (u/email? email)))
-  (when locale
-    (assert (i18n/available-locale? locale) (tru "Invalid locale: {0}" (pr-str locale))))
-  ;; delete all subscriptions to pulses/alerts/etc. if the User is getting archived (`:is_active` status changes)
-  (when (false? active?)
-    (t2/delete! 'PulseChannelRecipient :user_id id))
-  ;; If we're setting the reset_token then encrypt it before it goes into the DB
-  (cond-> user
-    true        (merge (hashed-password-values user))
-    reset-token (update :reset_token u.password/hash-bcrypt)
-    locale      (update :locale i18n/normalized-locale-string)
-    email       (update :email u/lower-case-en)))
+                    :group_id (u/the-id (perms-group/admin))
+                    :user_id  id)))
+    ;; make sure email and locale are valid if set
+    (when email
+      (assert (u/email? email)))
+    (when locale
+      (assert (i18n/available-locale? locale) (tru "Invalid locale: {0}" (pr-str locale))))
+    ;; delete all subscriptions to pulses/alerts/etc. if the User is getting archived (`:is_active` status changes)
+    (when (false? active?)
+      (t2/delete! 'PulseChannelRecipient :user_id id))
+    ;; If we're setting the reset_token then encrypt it before it goes into the DB
+    (cond-> user
+      true        (merge (hashed-password-values (t2/changes user)))
+      reset-token (update :reset_token u.password/hash-bcrypt)
+      locale      (update :locale i18n/normalized-locale-string)
+      email       (update :email u/lower-case-en))))
 
 (defn add-common-name
   "Add a `:common_name` key to `user` by combining their first and last names, or using their email if names are `nil`."
@@ -131,7 +155,8 @@
     (cond-> user
       common-name (assoc :common_name common-name))))
 
-(defn- post-select [user]
+(t2/define-after-select :model/User
+  [user]
   (add-common-name user))
 
 (def ^:private default-user-columns
@@ -153,18 +178,7 @@
   "Sequence of columns Group Managers can see when fetching a list of Users.."
   (into non-admin-or-self-visible-columns [:is_superuser :last_login]))
 
-(mi/define-methods
- User
- {:default-fields (constantly default-user-columns)
-  :hydration-keys (constantly [:author :creator :user])
-  :properties     (constantly {::mi/updated-at-timestamped? true})
-  :pre-insert     pre-insert
-  :post-insert    post-insert
-  :pre-update     pre-update
-  :post-select    post-select
-  :types          (constantly {:login_attributes :json-no-keywordization
-                               :settings         :encrypted-json
-                               :sso_source       :keyword})})
+(t2.default-fields/define-default-fields :model/User default-user-columns)
 
 (defmethod serdes/hash-fields User
   [_user]
diff --git a/test/metabase/models/revision_test.clj b/test/metabase/models/revision_test.clj
index 1750f55ed20..0ad4ee201b5 100644
--- a/test/metabase/models/revision_test.clj
+++ b/test/metabase/models/revision_test.clj
@@ -7,6 +7,7 @@
    [metabase.models.revision.diff :refer [build-sentence]]
    [metabase.test :as mt]
    [metabase.util.i18n :refer [deferred-tru]]
+   [methodical.core :as methodical]
    [toucan.models :as models]
    [toucan2.core :as t2]
    [toucan2.tools.with-temp :as t2.with-temp]))
@@ -14,7 +15,8 @@
 (def ^:private reverted-to
   (atom nil))
 
-(models/defmodel ^:private FakedCard :report_card)
+(methodical/defmethod t2/table-name :model/FakedCard [_model] :report_card)
+(derive :model/FakedCard :metabase/model)
 
 (use-fixtures :each (fn [thunk]
                       (with-redefs [metabase.models.revision.diff/model-str->i18n-str (fn [model-str]
@@ -27,26 +29,26 @@
                                                                                           "FakeCard"      "FakeCard"))]
                         (thunk))))
 
-(defmethod revision/serialize-instance FakedCard
+(defmethod revision/serialize-instance :model/FakedCard
   [_model _id obj]
   (into {} (assoc obj :serialized true)))
 
-(defmethod revision/revert-to-revision! FakedCard
+(defmethod revision/revert-to-revision! :model/FakedCard
   [_model _id _user-id serialized-instance]
   (reset! reverted-to (dissoc serialized-instance :serialized)))
 
-(defmethod revision/diff-map FakedCard
+(defmethod revision/diff-map :model/FakedCard
   [_model o1 o2]
   {:o1 (when o1 (into {} o1)), :o2 (when o2 (into {} o2))})
 
-(defmethod revision/diff-strings FakedCard
+(defmethod revision/diff-strings :model/FakedCard
   [_model o1 o2]
   (when o1
     [(str "BEFORE=" (into {} o1) ",AFTER=" (into {} o2))]))
 
 (defn- push-fake-revision! [card-id & {:keys [message] :as object}]
   (revision/push-revision!
-    :entity   FakedCard
+    :entity   :model/FakedCard
     :id       card-id
     :user-id  (mt/user->id :rasta)
     :object   (dissoc object :message)
@@ -102,7 +104,7 @@
   (testing "Test that a newly created Card doesn't have any revisions"
     (t2.with-temp/with-temp [Card {card-id :id}]
       (is (= []
-             (revision/revisions FakedCard card-id))))))
+             (revision/revisions :model/FakedCard card-id))))))
 
 (deftest add-revision-test
   (testing "Test that we can add a revision"
@@ -112,11 +114,11 @@
                Revision
                {:model        "FakedCard"
                 :user_id      (mt/user->id :rasta)
-                :object       (mi/instance FakedCard {:name "Tips Created by Day", :serialized true})
+                :object       (mi/instance :model/FakedCard {:name "Tips Created by Day", :serialized true})
                 :is_reversion false
                 :is_creation  false
                 :message      "yay!"})]
-             (for [revision (revision/revisions FakedCard card-id)]
+             (for [revision (revision/revisions :model/FakedCard card-id)]
                (dissoc revision :timestamp :id :model_id)))))))
 
 (deftest sorting-test
@@ -128,7 +130,7 @@
                Revision
                {:model        "FakedCard"
                 :user_id      (mt/user->id :rasta)
-                :object       (mi/instance FakedCard {:name "Spots Created by Day", :serialized true})
+                :object       (mi/instance :model/FakedCard {:name "Spots Created by Day", :serialized true})
                 :is_reversion false
                 :is_creation  false
                 :message      nil})
@@ -136,11 +138,11 @@
                Revision
                {:model        "FakedCard"
                 :user_id      (mt/user->id :rasta)
-                :object       (mi/instance FakedCard {:name "Tips Created by Day", :serialized true})
+                :object       (mi/instance :model/FakedCard {:name "Tips Created by Day", :serialized true})
                 :is_reversion false
                 :is_creation  false
                 :message      nil})]
-             (->> (revision/revisions FakedCard card-id)
+             (->> (revision/revisions :model/FakedCard card-id)
                   (map #(dissoc % :timestamp :id :model_id))))))))
 
 (deftest delete-old-revisions-test
@@ -150,7 +152,7 @@
       (dorun (doseq [i (range (inc revision/max-revisions))]
                (push-fake-revision! card-id, :name (format "Tips Created by Day %d" i))))
       (is (= revision/max-revisions
-             (count (revision/revisions FakedCard card-id)))))))
+             (count (revision/revisions :model/FakedCard card-id)))))))
 
 (deftest do-not-record-if-object-is-not-changed-test
   (testing "Check that we don't record a revision if the object hasn't changed"
@@ -159,15 +161,15 @@
                            (push-fake-revision! card-id, :name (format "Tips Created by Day %s" x)))]
         (testing "first revision should be recorded"
           (new-revision 1)
-          (is (= 1 (count (revision/revisions FakedCard card-id)))))
+          (is (= 1 (count (revision/revisions :model/FakedCard card-id)))))
 
         (testing "repeatedly push reivisions with thesame object shouldn't create new revision"
           (dorun (repeatedly 5 #(new-revision 1)))
-          (is (= 1 (count (revision/revisions FakedCard card-id)))))
+          (is (= 1 (count (revision/revisions :model/FakedCard card-id)))))
 
         (testing "push a revision with different object should create new revision"
           (new-revision 2)
-          (is (= 2 (count (revision/revisions FakedCard card-id)))))))))
+          (is (= 2 (count (revision/revisions :model/FakedCard card-id)))))))))
 
 ;;; # REVISIONS+DETAILS
 
@@ -184,19 +186,19 @@
                                      :o2 {:name "Modified Name", :serialized true}}
               :has_multiple_changes false
               :description          "BEFORE={:name \"Initial Name\", :serialized true},AFTER={:name \"Modified Name\", :serialized true}."}
-             (let [revisions (revision/revisions FakedCard card-id)]
+             (let [revisions (revision/revisions :model/FakedCard card-id)]
                (assert (= 2 (count revisions)))
-               (-> (revision/add-revision-details FakedCard (first revisions) (last revisions))
+               (-> (revision/add-revision-details :model/FakedCard (first revisions) (last revisions))
                    (dissoc :timestamp :id :model_id)
                    mt/derecordize))))))
 
   (testing "test that we return a description even when there is no change between revision"
     (is (= "created a revision with no change."
-           (str (:description (revision/add-revision-details FakedCard {:name "Apple"} {:name "Apple"}))))))
+           (str (:description (revision/add-revision-details :model/FakedCard {:name "Apple"} {:name "Apple"}))))))
 
   (testing "that we return a descrtiopn when there is no previous revision"
     (is (= "modified this."
-           (str (:description (revision/add-revision-details FakedCard {:name "Apple"} nil)))))))
+           (str (:description (revision/add-revision-details :model/FakedCard {:name "Apple"} nil)))))))
 
 (deftest revisions+details-test
   (testing "Check that revisions+details pulls in user info and adds description"
@@ -212,7 +214,7 @@
                                        :o2 {:name "Tips Created by Day", :serialized true}}
                 :has_multiple_changes false
                 :description          "modified this."})]
-             (->> (revision/revisions+details FakedCard card-id)
+             (->> (revision/revisions+details :model/FakedCard card-id)
                   (map #(dissoc % :timestamp :id :model_id))
                   (map #(update % :description str))))))))
 
@@ -242,7 +244,7 @@
                                        :o2 {:name "Tips Created by Day", :serialized true}}
                 :has_multiple_changes false
                 :description          "modified this."})]
-             (->> (revision/revisions+details FakedCard card-id)
+             (->> (revision/revisions+details :model/FakedCard card-id)
                   (map #(dissoc % :timestamp :id :model_id))
                   (map #(update % :description str))))))))
 
@@ -252,8 +254,8 @@
   (testing "Check that revert defers to revert-to-revision!"
     (t2.with-temp/with-temp [Card {card-id :id}]
       (push-fake-revision! card-id, :name "Tips Created by Day")
-      (let [[{revision-id :id}] (revision/revisions FakedCard card-id)]
-        (revision/revert! :entity FakedCard, :id card-id, :user-id (mt/user->id :rasta), :revision-id revision-id)
+      (let [[{revision-id :id}] (revision/revisions :model/FakedCard card-id)]
+        (revision/revert! :entity :model/FakedCard, :id card-id, :user-id (mt/user->id :rasta), :revision-id revision-id)
         (is (= {:name "Tips Created by Day"}
                @reverted-to))))))
 
@@ -274,8 +276,8 @@
     (t2.with-temp/with-temp [Card {card-id :id}]
       (push-fake-revision! card-id, :name "Tips Created by Day")
       (push-fake-revision! card-id, :name "Spots Created by Day")
-      (let [[_ {old-revision-id :id}] (revision/revisions FakedCard card-id)]
-        (revision/revert! :entity FakedCard, :id card-id, :user-id (mt/user->id :rasta), :revision-id old-revision-id)
+      (let [[_ {old-revision-id :id}] (revision/revisions :model/FakedCard card-id)]
+        (revision/revert! :entity :model/FakedCard, :id card-id, :user-id (mt/user->id :rasta), :revision-id old-revision-id)
         (is (partial=
              [(mi/instance
                Revision
@@ -301,7 +303,7 @@
                 :is_reversion false
                 :is_creation  false
                 :message      nil})]
-             (->> (revision/revisions FakedCard card-id)
+             (->> (revision/revisions :model/FakedCard card-id)
                   (map #(dissoc % :timestamp :id :model_id)))))))))
 
 (deftest generic-models-revision-title+description-test
diff --git a/test/metabase/models/user_test.clj b/test/metabase/models/user_test.clj
index 97f110ad7c3..0e3df12ac57 100644
--- a/test/metabase/models/user_test.clj
+++ b/test/metabase/models/user_test.clj
@@ -414,7 +414,7 @@
                (t2/select-one-fn :reset_token User :id user-id)))))
 
     (testing "should clear out all existing Sessions"
-      (mt/with-temp* [User [{user-id :id}]]
+      (t2.with-temp/with-temp [User {user-id :id} {}]
         (dotimes [_ 2]
           (t2/insert! Session {:id (str (java.util.UUID/randomUUID)), :user_id user-id}))
         (letfn [(session-count [] (t2/count Session :user_id user-id))]
@@ -463,16 +463,16 @@
 
 (deftest delete-pulse-subscriptions-when-archived-test
   (testing "Delete a User's Pulse/Alert/Dashboard Subscription subscriptions when they get archived"
-    (mt/with-temp* [User                  [{user-id :id}]
-                    Pulse                 [{pulse-id :id}]
-                    PulseChannel          [{pulse-channel-id :id} {:pulse_id pulse-id}]
-                    PulseChannelRecipient [_ {:pulse_channel_id pulse-channel-id, :user_id user-id}]]
+    (t2.with-temp/with-temp [User                  {user-id :id}          {}
+                             Pulse                 {pulse-id :id}         {}
+                             PulseChannel          {pulse-channel-id :id} {:pulse_id pulse-id}
+                             PulseChannelRecipient _ {:pulse_channel_id pulse-channel-id, :user_id user-id}]
       (letfn [(subscription-exists? []
                 (t2/exists? PulseChannelRecipient :pulse_channel_id pulse-channel-id, :user_id user-id))]
         (testing "Sanity check: subscription should exist"
           (is (subscription-exists?)))
         (testing "user is updated but not archived: don't delete the subscription"
-          (is (pos? (t2/update! User user-id {:is_active true})))
+          (is (pos? (t2/update! User user-id {:is_active true :first_name "New name"})))
           (is (subscription-exists?)))
         (testing "archive the user"
           (is (pos? (t2/update! User user-id {:is_active false}))))
diff --git a/test/metabase/test/util.clj b/test/metabase/test/util.clj
index c019eda8c48..e13aa72b9a6 100644
--- a/test/metabase/test/util.clj
+++ b/test/metabase/test/util.clj
@@ -21,17 +21,11 @@
             Field
             FieldValues
             LoginHistory
-            Metric
-            NativeQuerySnippet
             Permissions
             PermissionsGroup
             PermissionsGroupMembership
             PersistedInfo
-            Pulse
-            PulseCard
-            PulseChannel
             Revision
-            Segment
             Setting
             Table
             TaskHistory
@@ -158,14 +152,14 @@
             :device_description "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/89.0.4389.86 Safari/537.36"
             :ip_address         "0:0:0:0:0:0:0:1"})
 
-   Metric
+   :model/Metric
    (fn [_] {:creator_id  (rasta-id)
             :definition  {}
             :description "Lookin' for a blueberry"
             :name        "Toucans in the rainforest"
             :table_id    (data/id :checkins)})
 
-   NativeQuerySnippet
+   :model/NativeQuerySnippet
    (fn [_] {:creator_id (user-id :crowberto)
             :name       (tu.random/random-name)
             :content    "1 = 1"})
@@ -187,16 +181,16 @@
    PermissionsGroup
    (fn [_] {:name (tu.random/random-name)})
 
-   Pulse
+   :model/Pulse
    (fn [_] {:creator_id (rasta-id)
             :name       (tu.random/random-name)})
 
-   PulseCard
+   :model/PulseCard
    (fn [_] {:position    0
             :include_csv false
             :include_xls false})
 
-   PulseChannel
+   :model/PulseChannel
    (constantly {:channel_type  :email
                 :details       {}
                 :schedule_type :daily
@@ -207,7 +201,7 @@
             :is_creation  false
             :is_reversion false})
 
-   Segment
+   :model/Segment
    (fn [_] {:creator_id  (rasta-id)
             :definition  {}
             :description "Lookin' for a blueberry"
@@ -247,7 +241,7 @@
       :time_matters true
       :creator_id   (rasta-id)})
 
-   User
+   :model/User
    (fn [_] {:first_name (tu.random/random-name)
             :last_name  (tu.random/random-name)
             :email      (tu.random/random-email)
-- 
GitLab