 ;; Replace values with these during first pass over Query.
 ;; Include associated Field ID so appropriate the info can be found during Field resolution
 (defrecord ValuePlaceholder [field-id value]
-  IResolveField
+  IResolve
   (resolve-field [this field-id->fields]
     (-> (:field-id this)
         field-id->fields

  "Resolve the `Fields` in an EXPANDED-QUERY-DICT."
  [expanded-query-dict field-ids]
  (if-not (seq field-ids) expanded-query-dict ; No need to do a DB call or walk expanded-query-dict if we didn't see any Field IDs
          (let [fields (->> (sel :many :id->fields [field/Field :name :base_type :special_type] :id [in field-ids])
                            (m/map-vals #(set/rename-keys % {:id           :field-id
                                                             :name         :field-name
                                                             :special_type :special-type
                                                             :base_type    :base-type})))]
            ;; 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))))


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


;; ## -------------------- Protocols --------------------

(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.")
  (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
  IResolve {:resolve-field (fn [this _] this)
            :resolve-table (fn [this _] this)})

(extend nil
  IResolve {:resolve-field (constantly nil)
            :resolve-table (constantly nil)})


;; ## -------------------- Expansion - Impl --------------------
