           (select-transaction-items s
                                     (prepare-criteria criteria)
                                     options)))))
+
+(defn find-item
+  "Returns the first item matching the specified criteria"
+  ([storage-spec criteria]
+   (find-item storage-spec criteria {}))
+  ([storage-spec criteria options]
+   (first (search-items storage-spec criteria options))))
 
 (defn- recalculate-account-item
   "Accepts a processing context and an item, updates

                 {:id id
                  :search-date search-date})))))

(defn- assoc-existing-transaction
  [{:keys [storage transaction] :as context}]
  (assoc context :existing (find-existing-transaction storage transaction)))

(defn- recalculate-indexes-and-balances-for-update
  [{:keys [storage base-items] :as context}]
  (doseq [item base-items]

  context)

(defn- update-transaction*
  [storage transaction]
  (->> transaction
       before-save
       (update-transaction storage)))

(defn- update-full-transaction
  "Update the transaction and associated items."
  [storage transaction]
  (update-transaction* storage transaction)
  (doseq [item (:items transaction)]
    (as-> item i
      (assoc i :transaction-id (:id transaction))
      (before-save-item i)
      (upsert-item storage i))))

(defn- find-base-item
  "Given an account ID and a date, finds the transaction item for that
  account that immediately precents the given date"
  [storage account-id as-of]
  ; TODO If no item is found, we need to know if it's because
  ; there is not item in this partition, or no item at all.
  ; I'm not sure of the storage layer is already walking back,
  ; but I'm guessing it is not.
  (find-item storage
             {:transaction-date [:< as-of]
              :account-id account-id}
             {:sort [[:transaction-date :desc]
                     [:index :desc]]
              :limit 1}))

(defn- recalculate-account
  "Recalculates statistics for items in the the specified account
  as of the specified date"
  [storage account-id as-of]
  (let [base-item (find-base-item storage account-id as-of)
        items (search-items storage
                            {:account-id account-id
                                     :transaction-date [:>= as-of]}
                            {:sort [:transaction-date :index]})]
    (pprint {:base-item base-item
             :items items})))

; Processing a transaction
; 1. Save the transaction and item records
