         (update ::data/count - (count extant)))))
 
 
-(extend-type Table
+(extend Table
 
   ITable
 
-  ;; Records
-
-  (scan
-    ([this]
-     (-scan this nil))
-    ([this opts]
-     (-scan this opts)))
-
-
-  (get-records
-    ([this id-keys]
-     (-get-records this id-keys nil))
-    ([this id-keys opts]
-     (-get-records this id-keys opts)))
-
-
-  (insert
-    ([this records]
-     (-insert this records nil))
-    ([this records opts]
-     (-insert this records opts)))
-
-
-  (delete
-    [this id-keys]
-    (-delete this id-keys)))
+  {:scan -scan
+   :get-records -get-records
+   :insert -insert
+   :delete -delete
+   :flush! -flush!})

                           patch-link (assoc ::patch patch-link)
                           data-link (assoc ::data data-link)))]
       (when-not (s/valid? ::node-data root-data)
         (throw (ex-info
                  "Cannot serialize invalid root data"
                  {:type ::invalid-root
                   :errors (s/explain-data ::node-data root-data)})))
       (let [node (mdag/store-node! (.store table) nil root-data)]
         (->Table
           (.store table)
           (assoc (.table-info table)
                  ::node/id (::node/id node)
                  ::data/size (node/reachable-size node))
           (::node/data node)
           nil
           false
           (._meta table))))
     ; Table is clean, return directly.
     table)))




(defn- -scan
  ([table]
   (-scan table nil))
  ([^Table table opts]
   (let [lexicoder (table-lexicoder table)
         start-key (some->> (:start-key opts) (key/encode lexicoder))
         end-key (some->> (:end-key opts) (key/encode lexicoder))]
     (->>
       (patch/patch-seq
         ; Merged patch data to apply to the records.
         (patch/filter-patch
           (.pending table) ; TODO: merge ::patch
           {:fields (:fields opts)
            :start-key start-key
            :end-key end-key})
         ; Lazy sequence of matching records from the index tree.
         (when-let [data-node (mdag/get-data
                                (.store table)
                                (::data (.root-data table)))]
           (if (or start-key end-key)
             (index/read-range
               (.store table)
               data-node
               (:fields opts)
               start-key
               end-key)
             (index/read-all
               (.store table)
               data-node
               (:fields opts)))))
       (patch/remove-tombstones)
       (map (key-decoder lexicoder))))))


(defn- -get-records
  ([table id-keys]
   (-get-records table id-keys nil))
  ([^Table table id-keys opts]
   (let [lexicoder (table-lexicoder table)
         id-keys (into #{} (map (partial key/encode lexicoder)) id-keys)
         patch-map (.pending table) ; TODO: merge ::patch
         patch-entries (select-keys patch-map id-keys)
         extra-keys (apply disj id-keys (keys patch-entries))
         patch-entries (patch/filter-patch patch-entries {:fields (:fields opts)})
         data-entries (when-let [data-node (and (seq extra-keys)
                                                (mdag/get-data
                                                  (.store table)
                                                  (::data (.root-data table))))]
                        (index/read-batch
                          (.store table)
                          data-node
                          (:fields opts)
                          extra-keys))]
     (->> (concat patch-entries data-entries)
          (patch/remove-tombstones)
          (map (key-decoder lexicoder))))))


(defn- -insert
  ([table records]
   (-insert table records nil))
  ([table records opts]
   (let [{:keys [merge-record merge-field]} opts
         lexicoder (table-lexicoder table)
         update-record (cond
                         merge-record merge-record
                         merge-field
                         (fn merge-fields
                           [_ old-data new-data]
                           (reduce
                             (fn [data field-key]
                               (assoc data
                                      field-key
                                      (merge-field field-key
                                                   (get old-data field-key)
                                                   (get new-data field-key))))
                             {} (distinct (concat (keys old-data) (keys new-data)))))
                         :else
                         (fn merge-simple
                           [_ old-data new-data]
                           (into {}
                                 (filter (comp some? val))
                                 (merge old-data new-data))))
         extant (into {} (get-records table (map first records)))
         new-records (map
                       (fn [[k data]]
                         [(key/encode lexicoder k)
                          (update-record k (get extant k) data)])
                       records)]
     ; Add new data maps to pending changes.
     (-> table
         (update-pending into new-records)
         (update ::data/count + (- (count records) (count extant)))))))


(defn- -delete
