 
 ;; ## -------------------- Protocols --------------------
 
-(defprotocol IResolveField
-  "Methods called during `Field` resolution. Placeholder types should implement this protocol."
+(defprotocol IResolve
+  "Methods called during `Field` and `Table` resolution. Placeholder types should implement this protocol."
   (resolve-field [this field-id->fields]
     "This method is called when walking the Query after fetching `Fields`.
      Placeholder objects should lookup the relevant Field in FIELD-ID->FIELDS and
-     return their expanded form. Other objects should just return themselves."))
+     return their expanded form. Other objects should just return themselves.")
+  (resolve-table [this table-id->tables]
+    "Called when walking the Query after `Fields` have been resolved and `Tables` have been fetched.
+     Objects like `Fields` can add relevant information like the name of their `Table`."))
 
 ;; Default impls are just identity
 (extend Object
-  IResolveField {:resolve-field (fn [this _] this)})
+  IResolve {:resolve-field (fn [this _] this)
+            :resolve-table (fn [this _] this)})
 
 (extend nil
-  IResolveField {:resolve-field (constantly nil)})
+  IResolve {:resolve-field (constantly nil)
+            :resolve-table (constantly nil)})
 
 
 ;; ## -------------------- Expansion - Impl --------------------

            [medley.core :as m]
            [swiss.arrows :refer [-<>]]
            [metabase.db :refer [sel]]
            [metabase.models.field :as field]
            [metabase.util :as u])
  (:import (clojure.lang Keyword)))



;; Replace Field IDs with these during first pass
(defrecord FieldPlaceholder [field-id]
  IResolve
  (resolve-field [this field-id->fields]
    (-> (:field-id this)
        field-id->fields
