                      [:index :desc]]
               :limit 1}))
 
+(defn- process-items
+  "Recalculates and updates statistics in the specifed items"
+  [storage account {:keys [index balance] :or {index -1 balance 0M}} items]
+  (loop [item (first items)
+         remaining (rest items)
+         last-index index
+         last-balance balance]
+    (let [new-index (+ last-index 1)
+          new-balance (+ last-balance (polarize-quantity item account))]
+      (upsert-item storage (assoc item
+                                  :balance new-balance
+                                  :index new-index))
+      ; TODO if the item does not require updating, exit the loop and return nil
+      (if (seq remaining)
+        (recur (first remaining)
+               (rest remaining)
+               new-index
+               new-balance)
+        [new-index new-balance]))))
+
 (defn- recalculate-account
   "Recalculates statistics for items in the the specified account
   as of the specified date"

                                    :transaction-date transaction-date}
                                   {:limit 1})))

; TODO delete
(defn- upsert-item
  "Updates the specified transaction item"
  [storage {:keys [id transaction-date] :as item}]
  (if (:id item)
    (do
      (update-transaction-item storage item)
      (find-item-by-id storage id transaction-date))
    (create-transaction-item storage item)))

(defn- update-item-index-and-balance
  "Updates only the index and balance attributes of an item, returning true if

  (doseq [item (:items transaction)]
    (as-> item i
      (assoc i :transaction-id (:id transaction))
      (upsert-item storage i))))

(defn- find-base-item
