From 36107b6e93c8ebe66a422c37f87abaf8c79d73d1 Mon Sep 17 00:00:00 2001
From: Cam Saul <1455846+camsaul@users.noreply.github.com>
Date: Tue, 19 Jul 2022 21:43:18 -0700
Subject: [PATCH] Remove `u/key-by` (#24131)

* Remove `u/key-by`

* Fix typo

* SORT THE NAMESPACES
---
 .../middleware/row_level_restrictions.clj     |  7 ++++---
 src/metabase/api/card.clj                     |  2 +-
 src/metabase/api/persist.clj                  |  3 ++-
 src/metabase/api/search.clj                   |  3 ++-
 src/metabase/api/table.clj                    |  4 ++--
 src/metabase/models/field.clj                 |  8 +++----
 src/metabase/models/params.clj                | 21 ++++++++++---------
 .../middleware/add_dimension_projections.clj  |  6 +++---
 .../query_processor/middleware/annotate.clj   |  2 +-
 .../middleware/expand_macros.clj              | 13 ++++++------
 .../middleware/upgrade_field_literals.clj     |  5 +++--
 src/metabase/query_processor/util.clj         |  4 ++--
 .../sync_metadata/fields/sync_instances.clj   |  7 ++++---
 src/metabase/task/persist_refresh.clj         |  5 ++---
 src/metabase/util.clj                         | 11 ----------
 test/metabase/api/permissions_test.clj        |  7 ++++---
 .../middleware/add_implicit_clauses_test.clj  |  3 ++-
 .../middleware/add_implicit_joins_test.clj    |  2 +-
 .../middleware/add_source_metadata_test.clj   |  6 +++---
 .../middleware/annotate_test.clj              |  3 ++-
 .../field_visibility_test.clj                 |  9 ++++----
 .../nested_queries_test.clj                   |  3 ++-
 test/metabase/util_test.clj                   |  6 ------
 23 files changed, 67 insertions(+), 73 deletions(-)

diff --git a/enterprise/backend/src/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions.clj b/enterprise/backend/src/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions.clj
index 8dbdbc76bbe..9be54ed97b4 100644
--- a/enterprise/backend/src/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions.clj
+++ b/enterprise/backend/src/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions.clj
@@ -4,6 +4,7 @@
   for [[metabase.models.permissions]] for a high-level overview of the Metabase permissions system."
   (:require [clojure.core.memoize :as memoize]
             [clojure.tools.logging :as log]
+            [medley.core :as m]
             [metabase-enterprise.sandbox.models.group-table-access-policy :as gtap :refer [GroupTableAccessPolicy]]
             [metabase.api.common :as api :refer [*current-user* *current-user-id* *current-user-permissions-set*]]
             [metabase.db.connection :as mdb.connection]
@@ -87,7 +88,7 @@
   (when-let [gtaps (some->> (query->all-table-ids query)
                             ((comp seq filter) table-should-have-segmented-permissions?)
                             tables->gtaps)]
-    (u/key-by :table_id gtaps)))
+    (m/index-by :table_id gtaps)))
 
 
 ;;; +----------------------------------------------------------------------------------------------------------------+
@@ -178,7 +179,7 @@
 (s/defn ^:private reconcile-metadata :- (su/non-empty [su/Map])
   "Combine the metadata in `source-query-metadata` with the `table-metadata` from the Table being sandboxed."
   [source-query-metadata :- (su/non-empty [su/Map]) table-metadata]
-  (let [col-name->table-metadata (u/key-by :name table-metadata)]
+  (let [col-name->table-metadata (m/index-by :name table-metadata)]
     (vec
      (for [col   source-query-metadata
            :let  [table-col (get col-name->table-metadata (:name col))]
@@ -340,7 +341,7 @@
   final results metadata coming back matches what we'd get if the query was not running with a GTAP."
   [original-metadata metadata]
   (letfn [(merge-cols [cols]
-            (let [col-name->expected-col (u/key-by :name original-metadata)]
+            (let [col-name->expected-col (m/index-by :name original-metadata)]
               (for [col cols]
                 (merge
                  col
diff --git a/src/metabase/api/card.clj b/src/metabase/api/card.clj
index a0f437bf735..6c378b90ddd 100644
--- a/src/metabase/api/card.clj
+++ b/src/metabase/api/card.clj
@@ -85,7 +85,7 @@
   Make sure cards are returned in the same order as `card-ids`; `[in card-ids]` won't preserve the order."
   [card-ids :- [su/IntGreaterThanZero]]
   (when (seq card-ids)
-    (let [card-id->card (u/key-by :id (db/select Card, :id [:in (set card-ids)], :archived false))]
+    (let [card-id->card (m/index-by :id (db/select Card, :id [:in (set card-ids)], :archived false))]
       (filter identity (map card-id->card card-ids)))))
 
 ;; Return the 10 Cards most recently viewed by the current user, sorted by how recently they were viewed.
diff --git a/src/metabase/api/persist.clj b/src/metabase/api/persist.clj
index b31a69a74d9..7a3fef6eece 100644
--- a/src/metabase/api/persist.clj
+++ b/src/metabase/api/persist.clj
@@ -3,6 +3,7 @@
             [clojure.tools.logging :as log]
             [compojure.core :refer [GET POST]]
             [honeysql.helpers :as hh]
+            [medley.core :as m]
             [metabase.api.common :as api]
             [metabase.api.common.validation :as validation]
             [metabase.driver.ddl.interface :as ddl.i]
@@ -128,7 +129,7 @@
   - remove `:persist-models-enabled` from relevant [[Database]] options
   - schedule a task to [[metabase.driver.ddl.interface/unpersist]] each table"
   []
-  (let [id->db      (u/key-by :id (Database))
+  (let [id->db      (m/index-by :id (Database))
         enabled-dbs (filter (comp :persist-models-enabled :options) (vals id->db))]
     (log/info (tru "Disabling model persistence"))
     (doseq [db enabled-dbs]
diff --git a/src/metabase/api/search.clj b/src/metabase/api/search.clj
index 3383ec53fcf..7d9e6e84826 100644
--- a/src/metabase/api/search.clj
+++ b/src/metabase/api/search.clj
@@ -5,6 +5,7 @@
             [flatland.ordered.map :as ordered-map]
             [honeysql.core :as hsql]
             [honeysql.helpers :as hh]
+            [medley.core :as m]
             [metabase.api.common :as api]
             [metabase.db :as mdb]
             [metabase.models :refer [Database]]
@@ -145,7 +146,7 @@
   missing from `entity-columns` but found in `all-search-columns`."
   [model :- SearchableModel]
   (let [entity-columns                (search-config/columns-for-model model)
-        column-alias->honeysql-clause (u/key-by ->column-alias entity-columns)
+        column-alias->honeysql-clause (m/index-by ->column-alias entity-columns)
         cols-or-nils                  (canonical-columns model column-alias->honeysql-clause)]
     cols-or-nils))
 
diff --git a/src/metabase/api/table.clj b/src/metabase/api/table.clj
index cd5ad0fadb6..0e84fa7334c 100644
--- a/src/metabase/api/table.clj
+++ b/src/metabase/api/table.clj
@@ -313,8 +313,8 @@
    database."
   [card-id database-id metadata]
   (let [add-field-dimension-options #(assoc-field-dimension-options (driver.u/database->driver database-id) %)
-        underlying (u/key-by :id (when-let [ids (seq (keep :id metadata))]
-                                   (db/select Field :id [:in ids])))
+        underlying (m/index-by :id (when-let [ids (seq (keep :id metadata))]
+                                     (db/select Field :id [:in ids])))
         fields (for [{col-id :id :as col} metadata]
                  (-> col
                      (update :base_type keyword)
diff --git a/src/metabase/models/field.clj b/src/metabase/models/field.clj
index f7fd73b5e6c..cf4cc156d0e 100644
--- a/src/metabase/models/field.clj
+++ b/src/metabase/models/field.clj
@@ -227,8 +227,8 @@
     -> returns Fieldvalues of type :full for fields: [(Field 1) (Field 2)] "
   [fields model & conditions]
   (let [field-ids (set (map :id fields))]
-    (u/key-by :field_id (when (seq field-ids)
-                          (apply db/select model :field_id [:in field-ids] conditions)))))
+    (m/index-by :field_id (when (seq field-ids)
+                            (apply db/select model :field_id [:in field-ids] conditions)))))
 
 (defn nfc-field->parent-identifier
   "Take a nested field column field corresponding to something like an inner key within a JSON column,
@@ -333,8 +333,8 @@
                                     :when (and (isa? (:semantic_type field) :type/FK)
                                                (:fk_target_field_id field))]
                                 (:fk_target_field_id field)))
-        id->target-field (u/key-by :id (when (seq target-field-ids)
-                                         (readable-fields-only (db/select Field :id [:in target-field-ids]))))]
+        id->target-field (m/index-by :id (when (seq target-field-ids)
+                                           (readable-fields-only (db/select Field :id [:in target-field-ids]))))]
     (for [field fields
           :let  [target-id (:fk_target_field_id field)]]
       (assoc field :target (id->target-field target-id)))))
diff --git a/src/metabase/models/params.clj b/src/metabase/models/params.clj
index f109cac99b6..56a10c798c7 100644
--- a/src/metabase/models/params.clj
+++ b/src/metabase/models/params.clj
@@ -2,6 +2,7 @@
   "Utility functions for dealing with parameters for Dashboards and Cards."
   (:require [clojure.set :as set]
             [clojure.tools.logging :as log]
+            [medley.core :as m]
             [metabase.db.util :as mdb.u]
             [metabase.mbql.normalize :as mbql.normalize]
             [metabase.mbql.schema :as mbql.s]
@@ -95,13 +96,13 @@
   cases where more than one name Field exists for a Table, this just adds the first one it finds."
   [fields]
   (when-let [table-ids (seq (map :table_id fields))]
-    (u/key-by :table_id (-> (db/select Field:params-columns-only
-                              :table_id      [:in table-ids]
-                              :semantic_type (mdb.u/isa :type/Name))
-                            ;; run `metabase.models.field/infer-has-field-values` on these Fields so their values of
-                            ;; `has_field_values` will be consistent with what the FE expects. (e.g. we'll return
-                            ;; `list` instead of `auto-list`.)
-                            (hydrate :has_field_values)))))
+    (m/index-by :table_id (-> (db/select Field:params-columns-only
+                                :table_id      [:in table-ids]
+                                :semantic_type (mdb.u/isa :type/Name))
+                              ;; run `metabase.models.field/infer-has-field-values` on these Fields so their values of
+                              ;; `has_field_values` will be consistent with what the FE expects. (e.g. we'll return
+                              ;; `list` instead of `auto-list`.)
+                              (hydrate :has_field_values)))))
 
 (defn add-name-field
   "For all `fields` that are `:type/PK` Fields, look for a `:type/Name` Field belonging to the same Table. For each
@@ -152,9 +153,9 @@
   parameter widgets."
   [field-ids :- (s/maybe #{su/IntGreaterThanZero})]
   (when (seq field-ids)
-    (u/key-by :id (-> (db/select Field:params-columns-only :id [:in field-ids])
-                      (hydrate :has_field_values :name_field [:dimensions :human_readable_field])
-                      remove-dimensions-nonpublic-columns))))
+    (m/index-by :id (-> (db/select Field:params-columns-only :id [:in field-ids])
+                        (hydrate :has_field_values :name_field [:dimensions :human_readable_field])
+                        remove-dimensions-nonpublic-columns))))
 
 (defmulti ^:private ^{:hydrate :param_fields} param-fields
   "Add a `:param_fields` map (Field ID -> Field) for all of the Fields referenced by the parameters of a Card or
diff --git a/src/metabase/query_processor/middleware/add_dimension_projections.clj b/src/metabase/query_processor/middleware/add_dimension_projections.clj
index b9872203721..26d82f53b8b 100644
--- a/src/metabase/query_processor/middleware/add_dimension_projections.clj
+++ b/src/metabase/query_processor/middleware/add_dimension_projections.clj
@@ -60,9 +60,9 @@
   [fields :- [mbql.s/Field]]
   (when-let [field-ids (not-empty (set (mbql.u/match fields [:field (id :guard integer?) _] id)))]
     (letfn [(thunk []
-              (u/key-by :field_id (db/select [Dimension :id :field_id :name :human_readable_field_id]
-                                    :field_id [:in field-ids]
-                                    :type     "external")))]
+              (m/index-by :field_id (db/select [Dimension :id :field_id :name :human_readable_field_id]
+                                      :field_id [:in field-ids]
+                                      :type     "external")))]
       (if (qp.store/initialized?)
         (qp.store/cached [::fetch-dimensions field-ids]
           (thunk))
diff --git a/src/metabase/query_processor/middleware/annotate.clj b/src/metabase/query_processor/middleware/annotate.clj
index f8f276676f8..8a5ddbc3df2 100644
--- a/src/metabase/query_processor/middleware/annotate.clj
+++ b/src/metabase/query_processor/middleware/annotate.clj
@@ -518,7 +518,7 @@
   "Merge information about fields from `source-metadata` into the returned `cols`."
   [source-metadata cols dataset?]
   (let [index           (fn [col] (or (:id col) (:name col "")))
-        index->metadata (u/key-by index source-metadata)]
+        index->metadata (m/index-by index source-metadata)]
     (for [col cols]
       (if-let [source-metadata-for-field (-> col index index->metadata)]
         (merge-source-metadata-col source-metadata-for-field
diff --git a/src/metabase/query_processor/middleware/expand_macros.clj b/src/metabase/query_processor/middleware/expand_macros.clj
index 197c8ec56b7..4b32f8d8fc3 100644
--- a/src/metabase/query_processor/middleware/expand_macros.clj
+++ b/src/metabase/query_processor/middleware/expand_macros.clj
@@ -7,6 +7,7 @@
    TODO - this namespace is ancient and written with MBQL '95 in mind, e.g. it is case-sensitive.
    At some point this ought to be reworked to be case-insensitive and cleaned up."
   (:require [clojure.tools.logging :as log]
+            [medley.core :as m]
             [metabase.mbql.schema :as mbql.s]
             [metabase.mbql.util :as mbql.u]
             [metabase.models.metric :refer [Metric]]
@@ -60,12 +61,12 @@
 (s/defn ^:private metric-clauses->id->info :- {su/IntGreaterThanZero MetricInfo}
   [metric-clauses :- [mbql.s/metric]]
   (when (seq metric-clauses)
-    (u/key-by :id (for [metric (db/select [Metric :id :name :definition] :id [:in (set (map second metric-clauses))])
-                        :let   [errors (u/prog1 (metric-info-validation-errors metric)
-                                         (when <>
-                                           (log/warn (trs "Invalid metric: {0} reason: {1}" metric <>))))]
-                        :when  (not errors)]
-                    metric))))
+    (m/index-by :id (for [metric (db/select [Metric :id :name :definition] :id [:in (set (map second metric-clauses))])
+                          :let   [errors (u/prog1 (metric-info-validation-errors metric)
+                                           (when <>
+                                             (log/warn (trs "Invalid metric: {0} reason: {1}" metric <>))))]
+                          :when  (not errors)]
+                      metric))))
 
 (s/defn ^:private add-metrics-filters-this-level :- mbql.s/MBQLQuery
   [inner-query :- mbql.s/MBQLQuery this-level-metric-id->info :- {su/IntGreaterThanZero MetricInfo}]
diff --git a/src/metabase/query_processor/middleware/upgrade_field_literals.clj b/src/metabase/query_processor/middleware/upgrade_field_literals.clj
index 6f32030c7b5..0756a3e1398 100644
--- a/src/metabase/query_processor/middleware/upgrade_field_literals.clj
+++ b/src/metabase/query_processor/middleware/upgrade_field_literals.clj
@@ -2,6 +2,7 @@
   (:require [clojure.string :as str]
             [clojure.tools.logging :as log]
             [clojure.walk :as walk]
+            [medley.core :as m]
             [metabase.config :as config]
             [metabase.mbql.util :as mbql.u]
             [metabase.query-processor.middleware.resolve-fields :as qp.resolve-fields]
@@ -77,8 +78,8 @@
 
 (defn- upgrade-field-literals-one-level [{:keys [source-metadata], :as inner-query}]
   (let [source-aliases    (into #{} (keep :source_alias) source-metadata)
-        field-name->field (merge (u/key-by :name source-metadata)
-                                 (u/key-by (comp str/lower-case :name) source-metadata))]
+        field-name->field (merge (m/index-by :name source-metadata)
+                                 (m/index-by (comp str/lower-case :name) source-metadata))]
     (mbql.u/replace inner-query
       ;; don't upgrade anything inside `source-query` or `source-metadata`.
       (_ :guard (constantly (some (set &parents) [:source-query :source-metadata])))
diff --git a/src/metabase/query_processor/util.clj b/src/metabase/query_processor/util.clj
index 9f5cee93739..06aa74de61f 100644
--- a/src/metabase/query_processor/util.clj
+++ b/src/metabase/query_processor/util.clj
@@ -4,8 +4,8 @@
             [buddy.core.hash :as buddy-hash]
             [cheshire.core :as json]
             [clojure.string :as str]
+            [medley.core :as m]
             [metabase.driver :as driver]
-            [metabase.util :as u]
             [metabase.util.schema :as su]
             [schema.core :as s]))
 
@@ -126,7 +126,7 @@
   the metadata from a run from the query, and `pre-existing` should be the metadata from the database we wish to
   ensure survives."
   [fresh pre-existing]
-  (let [by-key (u/key-by (comp field-ref->key :field_ref) pre-existing)]
+  (let [by-key (m/index-by (comp field-ref->key :field_ref) pre-existing)]
     (for [{:keys [field_ref] :as col} fresh]
       (if-let [existing (get by-key (field-ref->key field_ref))]
         (merge col (select-keys existing preserved-keys))
diff --git a/src/metabase/sync/sync_metadata/fields/sync_instances.clj b/src/metabase/sync/sync_metadata/fields/sync_instances.clj
index a2ed8955c72..51d0ff9eefe 100644
--- a/src/metabase/sync/sync_metadata/fields/sync_instances.clj
+++ b/src/metabase/sync/sync_metadata/fields/sync_instances.clj
@@ -7,6 +7,7 @@
   functions `sync-nested-field-instances!` and `sync-nested-fields-of-one-field!`. All other functions in this
   namespace should ignore nested fields entirely; the will be invoked with those Fields as appropriate."
   (:require [clojure.tools.logging :as log]
+            [medley.core :as m]
             [metabase.models.field :as field :refer [Field]]
             [metabase.models.humanization :as humanization]
             [metabase.sync.interface :as i]
@@ -106,7 +107,7 @@
    db-metadata  :- #{i/TableMetadataField}
    our-metadata :- #{common/TableMetadataFieldWithID}
    parent-id    :- common/ParentID]
-  (let [known-fields (u/key-by common/canonical-name our-metadata)
+  (let [known-fields (m/index-by common/canonical-name our-metadata)
         our-metadata (atom our-metadata)]
     {:num-updates
      ;; Field sync logic below is broken out into chunks of 1000 fields for huge star schemas or other situations
@@ -182,8 +183,8 @@
   [table        :- i/TableInstance
    db-metadata  :- #{i/TableMetadataField}
    our-metadata :- #{common/TableMetadataFieldWithID}]
-  (let [name->field-metadata (u/key-by common/canonical-name db-metadata)
-        name->metabase-field (u/key-by common/canonical-name our-metadata)
+  (let [name->field-metadata (m/index-by common/canonical-name db-metadata)
+        name->metabase-field (m/index-by common/canonical-name our-metadata)
         all-field-names      (set (concat (keys name->field-metadata)
                                           (keys name->metabase-field)))]
     (sync-util/sum-for [field-name all-field-names
diff --git a/src/metabase/task/persist_refresh.clj b/src/metabase/task/persist_refresh.clj
index 8a76d88814d..e4db20d1a97 100644
--- a/src/metabase/task/persist_refresh.clj
+++ b/src/metabase/task/persist_refresh.clj
@@ -120,8 +120,7 @@
   "Seam for tests to pass in specific deletables to drop."
   [refresher deletables]
   (when (seq deletables)
-    (let [db-id->db    (u/key-by :id (db/select Database :id
-                                                [:in (map :database_id deletables)]))
+    (let [db-id->db    (m/index-by :id (db/select Database :id [:in (map :database_id deletables)]))
           unpersist-fn (fn []
                          (reduce (fn [stats persisted-info]
                                    ;; Since this could be long running, double check state just before deleting
@@ -379,7 +378,7 @@
   (some->> refresh-job-key
            task/job-info
            :triggers
-           (u/key-by (comp #(get % "db-id") qc/from-job-data :data))))
+           (m/index-by (comp #(get % "db-id") qc/from-job-data :data))))
 
 (defn job-info-for-individual-refresh
   "Return a set of PersistedInfo ids of all jobs scheduled for individual refreshes."
diff --git a/src/metabase/util.clj b/src/metabase/util.clj
index f0e6084ae3e..b71d6438e69 100644
--- a/src/metabase/util.clj
+++ b/src/metabase/util.clj
@@ -480,17 +480,6 @@
   `(do-with-auto-retries ~num-retries
      (fn [] ~@body)))
 
-(defn key-by
-  "Convert a sequential `coll` to a map of `(f item)` -> `item`.
-  This is similar to `group-by`, but the resultant map's values are single items from `coll` rather than sequences of
-  items. (Because only a single item is kept for each value of `f`, items producing duplicate values will be
-  discarded).
-
-     (key-by :id [{:id 1, :name :a} {:id 2, :name :b}]) -> {1 {:id 1, :name :a}, 2 {:id 2, :name :b}}"
-  {:style/indent 1}
-  [f coll]
-  (into {} (map (juxt f identity)) coll))
-
 (defn id
   "If passed an integer ID, returns it. If passed a map containing an `:id` key, returns the value if it is an integer.
   Otherwise returns `nil`.
diff --git a/test/metabase/api/permissions_test.clj b/test/metabase/api/permissions_test.clj
index 247b98949c2..ac2861ab71e 100644
--- a/test/metabase/api/permissions_test.clj
+++ b/test/metabase/api/permissions_test.clj
@@ -1,6 +1,7 @@
 (ns metabase.api.permissions-test
   "Tests for `/api/permissions` endpoints."
   (:require [clojure.test :refer :all]
+            [medley.core :as m]
             [metabase.api.permissions :as api.permissions]
             [metabase.models :refer [Database PermissionsGroup PermissionsGroupMembership Table User]]
             [metabase.models.permissions :as perms]
@@ -39,12 +40,12 @@
                               :name         (s/eq "Administrators")
                               :member_count su/IntGreaterThanZero}
                              (get id->group (:id (perms-group/admin)))))))]
-      (let [id->group (u/key-by :id (fetch-groups))]
+      (let [id->group (m/index-by :id (fetch-groups))]
         (check-default-groups-returned id->group))
 
       (testing "should return empty groups"
         (mt/with-temp PermissionsGroup [group]
-          (let [id->group (u/key-by :id (fetch-groups))]
+          (let [id->group (m/index-by :id (fetch-groups))]
             (check-default-groups-returned id->group)
             (testing "empty group should be returned"
               (is (schema= {:id           su/IntGreaterThanZero
@@ -70,7 +71,7 @@
   (testing "GET /permissions/group/:id"
     (let [{:keys [members]} (mt/user-http-request
                              :crowberto :get 200 (format "permissions/group/%d" (:id (perms-group/all-users))))
-          id->member        (u/key-by :user_id members)]
+          id->member        (m/index-by :user_id members)]
       (is (schema= {:first_name    (s/eq "Crowberto")
                     :last_name     (s/eq "Corv")
                     :email         (s/eq "crowberto@metabase.com")
diff --git a/test/metabase/query_processor/middleware/add_implicit_clauses_test.clj b/test/metabase/query_processor/middleware/add_implicit_clauses_test.clj
index 07c43798c31..8be91dc2142 100644
--- a/test/metabase/query_processor/middleware/add_implicit_clauses_test.clj
+++ b/test/metabase/query_processor/middleware/add_implicit_clauses_test.clj
@@ -1,5 +1,6 @@
 (ns metabase.query-processor.middleware.add-implicit-clauses-test
   (:require [clojure.test :refer :all]
+            [medley.core :as m]
             [metabase.mbql.util :as mbql.u]
             [metabase.models.field :refer [Field]]
             [metabase.query-processor :as qp]
@@ -15,7 +16,7 @@
   (testing "check we fetch Fields in the right order"
     (mt/with-temp-vals-in-db Field (mt/id :venues :price) {:position -1}
       (let [ids       (map second (#'qp.add-implicit-clauses/sorted-implicit-fields-for-table (mt/id :venues)))
-            id->field (u/key-by :id (db/select [Field :id :position :name :semantic_type] :id [:in ids]))]
+            id->field (m/index-by :id (db/select [Field :id :position :name :semantic_type] :id [:in ids]))]
         (is (= [ ;; sorted first because it has lowest positon
                 {:position -1, :name "PRICE", :semantic_type :type/Category}
                 ;; PK
diff --git a/test/metabase/query_processor/middleware/add_implicit_joins_test.clj b/test/metabase/query_processor/middleware/add_implicit_joins_test.clj
index 3a75af09579..d24dd343ed2 100644
--- a/test/metabase/query_processor/middleware/add_implicit_joins_test.clj
+++ b/test/metabase/query_processor/middleware/add_implicit_joins_test.clj
@@ -389,7 +389,7 @@
       (is (= #{"Child 1"}
              (#'qp.add-implicit-joins/join-dependencies child-1-child))))
     (testing "Sort by dependency order"
-      (let [alias->join (u/key-by :alias [parent child-1 child-2 child-1-child])]
+      (let [alias->join (m/index-by :alias [parent child-1 child-2 child-1-child])]
         (doseq [[original expected] {["Parent" "Child 1" "Child 2"]                 ["Parent" "Child 1" "Child 2"]
                                      ["Child 1" "Parent" "Child 2"]                 ["Parent" "Child 1" "Child 2"]
                                      ["Child 1" "Child 2" "Parent"]                 ["Parent" "Child 1" "Child 2"]
diff --git a/test/metabase/query_processor/middleware/add_source_metadata_test.clj b/test/metabase/query_processor/middleware/add_source_metadata_test.clj
index 99bcf3a4905..401475a58d7 100644
--- a/test/metabase/query_processor/middleware/add_source_metadata_test.clj
+++ b/test/metabase/query_processor/middleware/add_source_metadata_test.clj
@@ -1,11 +1,11 @@
 (ns metabase.query-processor.middleware.add-source-metadata-test
   (:require [clojure.string :as str]
             [clojure.test :refer :all]
+            [medley.core :as m]
             [metabase.driver :as driver]
             [metabase.query-processor :as qp]
             [metabase.query-processor.middleware.add-source-metadata :as add-source-metadata]
-            [metabase.test :as mt]
-            [metabase.util :as u]))
+            [metabase.test :as mt]))
 
 (defn- add-source-metadata [query]
   (driver/with-driver :h2
@@ -291,7 +291,7 @@
       (letfn [(ean-metadata [query]
                 (as-> query query
                   (get-in query [:query :source-metadata])
-                  (u/key-by :name query)
+                  (m/index-by :name query)
                   (get query "EAN")
                   (select-keys query [:name :display_name :base_type :semantic_type :id :field_ref])))]
         (let [base-query (mt/mbql-query orders
diff --git a/test/metabase/query_processor/middleware/annotate_test.clj b/test/metabase/query_processor/middleware/annotate_test.clj
index 888a77cf72c..c1c40becc56 100644
--- a/test/metabase/query_processor/middleware/annotate_test.clj
+++ b/test/metabase/query_processor/middleware/annotate_test.clj
@@ -1,5 +1,6 @@
 (ns metabase.query-processor.middleware.annotate-test
   (:require [clojure.test :refer :all]
+            [medley.core :as m]
             [metabase.driver :as driver]
             [metabase.models :refer [Card Field]]
             [metabase.query-processor :as qp]
@@ -640,7 +641,7 @@
       ;; these tests look at the metadata for just one column so it's easier to spot the differences.
       (letfn [(ean-metadata [result]
                 (as-> (:cols result) result
-                  (u/key-by :name result)
+                  (m/index-by :name result)
                   (get result "EAN")
                   (select-keys result [:name :display_name :base_type :semantic_type :id :field_ref])))]
         (testing "Make sure metadata is correct for the 'EAN' column with"
diff --git a/test/metabase/query_processor_test/field_visibility_test.clj b/test/metabase/query_processor_test/field_visibility_test.clj
index 86bf6393fb1..d93be05657e 100644
--- a/test/metabase/query_processor_test/field_visibility_test.clj
+++ b/test/metabase/query_processor_test/field_visibility_test.clj
@@ -1,6 +1,7 @@
 (ns metabase.query-processor-test.field-visibility-test
   "Tests for behavior of fields with different visibility settings."
   (:require [clojure.test :refer :all]
+            [medley.core :as m]
             [metabase.models.field :refer [Field]]
             [metabase.query-processor-test :as qp.test]
             [metabase.test :as mt]
@@ -20,16 +21,16 @@
 (deftest details-only-fields-test
   (mt/test-drivers (mt/normal-drivers)
     (testing "sanity check -- everything should be returned before making changes"
-      (is (= (u/key-by :id (qp.test/expected-cols :venues))
-             (u/key-by :id (venues-cols-from-query)))))
+      (is (= (m/index-by :id (qp.test/expected-cols :venues))
+             (m/index-by :id (venues-cols-from-query)))))
 
     (testing ":details-only fields should not be returned in normal queries"
       (tu/with-temp-vals-in-db Field (mt/id :venues :price) {:visibility_type :details-only}
-        (is (= (u/key-by :id (for [col (qp.test/expected-cols :venues)]
+        (is (= (m/index-by :id (for [col (qp.test/expected-cols :venues)]
                                (if (= (mt/id :venues :price) (u/the-id col))
                                  (assoc col :visibility_type :details-only)
                                  col)))
-               (u/key-by :id (venues-cols-from-query))))))))
+               (m/index-by :id (venues-cols-from-query))))))))
 
 
 ;;; ----------------------------------------------- :sensitive fields ------------------------------------------------
diff --git a/test/metabase/query_processor_test/nested_queries_test.clj b/test/metabase/query_processor_test/nested_queries_test.clj
index 266d8be6e44..4fc83787d6c 100644
--- a/test/metabase/query_processor_test/nested_queries_test.clj
+++ b/test/metabase/query_processor_test/nested_queries_test.clj
@@ -3,6 +3,7 @@
   (:require [clojure.test :refer :all]
             [honeysql.core :as hsql]
             [java-time :as t]
+            [medley.core :as m]
             [metabase.driver :as driver]
             [metabase.driver.sql.query-processor-test-util :as sql.qp-test-util]
             [metabase.mbql.schema :as mbql.s]
@@ -864,7 +865,7 @@
       (letfn [(ean-metadata [result]
                 (as-> result result
                   (get-in result [:data :results_metadata :columns])
-                  (u/key-by :name result)
+                  (m/index-by :name result)
                   (get result "EAN")
                   (select-keys result [:name :display_name :base_type :id :field_ref])))]
         (testing "Make sure metadata is correct for the 'EAN' column with"
diff --git a/test/metabase/util_test.clj b/test/metabase/util_test.clj
index f20799f6059..649f8f6bd2e 100644
--- a/test/metabase/util_test.clj
+++ b/test/metabase/util_test.clj
@@ -103,12 +103,6 @@
     (is (thrown? ClassCastException
                  (u/qualified-name false)))))
 
-(deftest ^:parallel key-by-test
-  (is (= {1 {:id 1, :name "Rasta"}
-          2 {:id 2, :name "Lucky"}}
-         (u/key-by :id [{:id 1, :name "Rasta"}
-                        {:id 2, :name "Lucky"}]))))
-
 (deftest ^:parallel remove-diacritical-marks-test
   (doseq [[s expected] {"üuuü" "uuuu"
                         "åéîü" "aeiu"
-- 
GitLab