From f041c24d0fec4e19e8bfb6037bde1506dea28615 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cam=20Sau=CC=88l?= <cammsaul@gmail.com>
Date: Tue, 7 Jul 2015 01:31:29 -0700
Subject: [PATCH] associate default-fields directly on entity

---
 src/metabase/db.clj                     | 11 ++---------
 src/metabase/models/interface.clj       | 16 ++++++++++++----
 src/metabase/models/query_execution.clj | 16 +---------------
 src/metabase/models/user.clj            | 15 +++------------
 4 files changed, 18 insertions(+), 40 deletions(-)

diff --git a/src/metabase/db.clj b/src/metabase/db.clj
index 93ef900232e..4112655f812 100644
--- a/src/metabase/db.clj
+++ b/src/metabase/db.clj
@@ -253,13 +253,6 @@
 
 ;; ## SEL
 
-(defmulti default-fields
-  "The default fields that should be used for ENTITY by calls to `sel` if none are specified."
-  identity)
-
-(defmethod default-fields :default [_]
-  nil) ; by default return nil, which we'll take to mean "everything"
-
 (defmacro sel
   "Wrapper for korma `select` that calls `post-select` on results and provides a few other conveniences.
 
@@ -374,8 +367,8 @@
     `(let [[entity# field-keys#] (destructure-entity ~entity)                    ; pull out field-keys if passed entity vector like `[entity & field-keys]`
            entity# (entity->korma entity#)                                       ; entity## is the actual entity like `metabase.models.user/User` that we can dispatch on
            entity-select-form# (-> entity#                                       ; entity-select-form# is the tweaked version we'll pass to korma `select`
-                                   (assoc :fields (or field-keys#
-                                                      (default-fields entity#))))] ; tell korma which fields to grab. If `field-keys` weren't passed in vector do lookup at runtime
+                                   (assoc :fields (or field-keys#                ; tell korma which fields to grab. If `field-keys` weren't passed in vector do lookup at runtime
+                                                      (:metabase.models.interface/default-fields entity#))))]
        (when (config/config-bool :mb-db-logging)
          (log/debug "DB CALL: " (:name entity#)
                   (or (:fields entity-select-form#) "*")
diff --git a/src/metabase/models/interface.clj b/src/metabase/models/interface.clj
index e60cda9709d..85d79df5db2 100644
--- a/src/metabase/models/interface.clj
+++ b/src/metabase/models/interface.clj
@@ -1,5 +1,6 @@
 (ns metabase.models.interface
-  (:require [clojure.tools.logging :as log]
+  (:require (clojure.tools [logging :as log]
+                           [macro :refer [macrolet]])
             [clojure.walk :refer [macroexpand-all]]
             [korma.core :as k]
             [medley.core :as m]
@@ -44,7 +45,9 @@
     (when (metabase.config/config-bool :mb-db-logging)
       (clojure.tools.logging/debug
        "DB CALL: " (:name entity) id)))
-  (let [[obj] (k/select entity (k/where {:id id}) (k/limit 1))]
+  (let [[obj] (k/select (assoc entity :fields (::default-fields entity))
+                        (k/where {:id id})
+                        (k/limit 1))]
     (when obj
       (->> obj
            (internal-post-select entity)
@@ -56,14 +59,19 @@
                  [`(~k ~obj) `(update-in [~k] ~f)])
                (seq kvs))))
 
+(defmacro macrolet-entity-map [entity & entity-forms]
+  `(macrolet [(~'default-fields [m# & fields#] `(assoc ~m# ::default-fields [~@(map keyword fields#)]))
+              (~'hydration-keys [m# & fields#] `(assoc ~m# :hydration-keys #{~@(map keyword fields#)}))]
+     (-> (k/create-entity ~(name entity))
+         ~@entity-forms)))
+
 (defmacro defentity
   "Similar to korma `defentity`, but creates a new record type where you can specify protocol implementations."
   [entity entity-forms & specs]
   {:pre [vector? entity-forms]}
   (let [entity-symb               (symbol (format "%sEntity" (name entity)))
         internal-post-select-symb (symbol (format "internal-post-select-%s" (name entity)))
-        entity-map                (eval `(-> (k/create-entity ~(name entity))
-                                             ~@entity-forms))
+        entity-map                (eval `(macrolet-entity-map ~entity ~@entity-forms))
         type-fns                  (resolve-type-fns (:metabase.db/types entity-map))]
     `(do
        (defrecord ~entity-symb []
diff --git a/src/metabase/models/query_execution.clj b/src/metabase/models/query_execution.clj
index 60f2beac7a1..57dfb1258ea 100644
--- a/src/metabase/models/query_execution.clj
+++ b/src/metabase/models/query_execution.clj
@@ -9,6 +9,7 @@
 
 (defentity QueryExecution
   [(table :query_queryexecution)
+   (default-fields id uuid version json_query raw_query status started_at finished_at running_time error result_rows)
    (types {:json_query  :json
            :result_data :json
            :status      :keyword})]
@@ -18,18 +19,3 @@
     ;; sadly we have 2 ways to reference the row count :(
     (assoc query-execution
            :row_count (or result_rows 0))))
-
-;; default fields to return for `sel QueryExecution
-;; specifically excludes stored data columns
-(defmethod default-fields QueryExecution [_]
-  [:id
-   :uuid
-   :version
-   :json_query
-   :raw_query
-   :status
-   :started_at
-   :finished_at
-   :running_time
-   :error
-   :result_rows])
diff --git a/src/metabase/models/user.clj b/src/metabase/models/user.clj
index 38c2be4ac72..6052aa650aa 100644
--- a/src/metabase/models/user.clj
+++ b/src/metabase/models/user.clj
@@ -10,25 +10,16 @@
 
 (defentity User
   [(table :core_user)
-   (assoc :hydration-keys #{:author :creator :user})]
+   (default-fields id email date_joined first_name last_name last_login is_superuser)
+   (hydration-keys author creator user)]
 
   IEntityPostSelect
   (post-select [_ user]
     (assoc user :common_name (str (:first_name user) " " (:last_name user)))))
 
-;; fields to return for Users other `*than current-user*`
-(defmethod default-fields User [_]
-  [:id
-   :email
-   :date_joined
-   :first_name
-   :last_name
-   :last_login
-   :is_superuser])
-
 (def ^:const current-user-fields
   "The fields we should return for `*current-user*` (used by `metabase.middleware.current-user`)"
-  (concat (default-fields User)
+  (concat (:metabase.models.interface/default-fields User)
           [:is_active
            :is_staff])) ; but not `password` !
 
-- 
GitLab