                                                              :special_type :special-type
                                                              :base_type    :base-type
                                                              :table_id     :table-id})))]
+            (reset! *table-ids* (set (map :table-id (vals fields))))
             ;; This is performed depth-first so we don't end up walking the newly-created Field/Value objects
             ;; they may have nil values; this was we don't have to write an implementation of resolve-field for nil
             (walk/postwalk #(resolve-field % fields) expanded-query-dict))))


(defn- resolve-tables
  "Resolve the `Tables` in an EXPANDED-QUERY-DICT."
  [{{source-table-id :source-table} :query, database-id :database, :as expanded-query-dict}]
  ;; TODO - this doesn't handle join tables yet
  (let [table (sel :one :fields [Table :name :id] :id source-table-id)]
    (->> (assoc-in expanded-query-dict [:query :source-table] table)
         (walk/postwalk #(resolve-table % {(:id table) table})))))


;; ## -------------------- Public Interface --------------------

                                       (m/filter-vals identity <>))))

(def ^:private ^:dynamic *field-ids*
  "Bound to an atom containing a set of `Field` IDs referenced in the query being expanded."
  nil)

(def ^:private ^:dynamic *table-ids*
  "Bound to an atom containing a set of `Table` IDs referenced by `Fields` in the query being expanded."
  nil)

(defn- resolve-fields
