 (defn set-method [method]
   (SetMethod. method))
 
-(defn merge-result
-  [context match value]
-  (let [{:keys [pathsets] :as context} (update-context value (assoc context :pathsets []) match)]
-    [(dissoc context :pathsets) pathsets]))
-
 (defn merge-results
   [context results]
-  (loop [context context paths [] results results]
-    (if-let [[match value] (first results)]
-      (let [[context new-paths] (merge-result context match value)]
-        (recur context (into paths new-paths) (rest results)))
-      [context (->> paths
-                    (core/optimize (:graph context))
-                    core/collapse)])))
+  (letfn [(optimize-pathsets [{:keys [pathsets graph] :as context}]
+            (assoc context :pathsets (->> pathsets
+                                          (core/optimize graph)
+                                          core/collapse
+                                          (into []))))]
+    (let [context (reduce (fn [context [match value]]
+                            (update-context value context match))
+                          context
+                          results)
+          context (optimize-pathsets context)]
+      context)))
+
+(defn init-context
+  [method pathsets env]
+  {:method method
+   :pathsets pathsets
+   :env env
+   :graph {}
+   :request pathsets
+   :matched []
+   :optimized []
+   :missing []})
 
 (defn execute
-  [route-tree method runner pathsets]
-  (letfn [(match-and-run [{:keys [method] :as context} pathset]
+  [route-tree context runner]
+  (letfn [(context-result [context]
+            (dissoc context :method :pathsets :env))
+          (match-and-run [{:keys [method] :as context} pathset]
             (let [matches (match route-tree method pathset)
                   results (run context pathset matches runner)]
               results))
-          (execute* [context pathsets]
+          (execute* [{:keys [pathsets] :as context}]
             (lazy-seq
               (if (seq pathsets)
                 (let [results (mapcat (partial match-and-run context) pathsets)

  (Router. (route-tree routes)))

(defrecord RouterDatasource
  [router ctx]
  core/IDataSource
  (get [_ pathsets cb]
    ;; TODO: doesn't impl `:missing`
    (cb (get router pathsets ctx)))
  (set [_ pathmaps cb]
    (cb (set router pathmaps ctx)))
  (call [_ path args queries cb]
    (cb (call router path args queries ctx))))

(defn as-datasource
  ([router]
   (as-datasource router {}))
  ([router ctx]
   (RouterDatasource. router ctx)))

  (update-context [{:keys [path value] :as pv} context {:keys [suffix]}]
    (let [context (-> context
                      (update :graph graph/set-path-value pv)
                      (update :optimized conj path))]
      (cond-> context
              (and (core/ref? value) (seq suffix))
              (update :pathsets conj (into (:path value) suffix)))))
