Return all conflicts for IO

This commit is contained in:
Tommi Reiman 2017-08-21 20:44:16 +03:00
parent 9701a51c5a
commit 066f5752c2
3 changed files with 29 additions and 18 deletions

View file

@ -400,7 +400,7 @@ Routers can be configured via options. Options allow things like [`clojure.spec`
| `:expand` | Function of `arg opts => meta` to expand route arg to route meta-data (default `reitit.core/expand`) | `:expand` | Function of `arg opts => meta` to expand route arg to route meta-data (default `reitit.core/expand`)
| `:coerce` | Function of `route opts => route` to coerce resolved route, can throw or return `nil` | `:coerce` | Function of `route opts => route` to coerce resolved route, can throw or return `nil`
| `:compile` | Function of `route opts => handler` to compile a route handler | `:compile` | Function of `route opts => handler` to compile a route handler
| `:conflicts` | Function of `[route route] => side-effect` to handle conflicting routes (default `reitit.core/throw-on-conflicts!`)" | `:conflicts` | Function of `{route #{route}} => side-effect` to handle conflicting routes (default `reitit.core/throw-on-conflicts!`)"
## Special thanks ## Special thanks

View file

@ -60,17 +60,22 @@
(cond->> (->> (walk data opts) (map-meta merge-meta)) (cond->> (->> (walk data opts) (map-meta merge-meta))
coerce (into [] (keep #(coerce % opts))))) coerce (into [] (keep #(coerce % opts)))))
(defn first-conflicting-routes [routes] (defn conflicting-routes [routes]
(loop [[r & rest] routes] (some->>
(if (seq rest) (loop [[r & rest] routes, acc {}]
(or (some #(if (impl/conflicting-routes? r %) [r %]) rest) (if (seq rest)
(recur rest))))) (let [conflicting (set (keep #(if (impl/conflicting-routes? r %) %) rest))]
(recur rest (update acc r (fnil (comp set concat) #{}) conflicting)))
acc))
(filter (comp seq second))
(seq)
(into {})))
(defn throw-on-conflicts! [routes] (defn throw-on-conflicts! [conflicts]
(throw (throw
(ex-info (ex-info
(str "router contains conflicting routes: " routes) (str "router contains conflicting routes: " conflicts)
{:routes routes}))) {:conflicts conflicts})))
(defn name-lookup [[_ {:keys [name]}] opts] (defn name-lookup [[_ {:keys [name]}] opts]
(if name #{name})) (if name #{name}))
@ -206,14 +211,14 @@
| `:expand` | Function of `arg opts => meta` to expand route arg to route meta-data (default `reitit.core/expand`) | `:expand` | Function of `arg opts => meta` to expand route arg to route meta-data (default `reitit.core/expand`)
| `:coerce` | Function of `route opts => route` to coerce resolved route, can throw or return `nil` | `:coerce` | Function of `route opts => route` to coerce resolved route, can throw or return `nil`
| `:compile` | Function of `route opts => handler` to compile a route handler | `:compile` | Function of `route opts => handler` to compile a route handler
| `:conflicts` | Function of `[route route] => side-effect` to handle conflicting routes (default `reitit.core/throw-on-conflicts!`)" | `:conflicts` | Function of `{route #{route}} => side-effect` to handle conflicting routes (default `reitit.core/throw-on-conflicts!`)"
([data] ([data]
(router data {})) (router data {}))
([data opts] ([data opts]
(let [opts (meta-merge default-router-options opts) (let [opts (meta-merge default-router-options opts)
routes (resolve-routes data opts)] routes (resolve-routes data opts)]
(when-let [conflicts (:conflicts opts)] (when-let [conflicts (:conflicts opts)]
(when-let [conflicting-routes (first-conflicting-routes routes)] (when-let [conflicting (conflicting-routes routes)]
(conflicts conflicting-routes))) (conflicts conflicting)))
((if (some impl/contains-wilds? (map first routes)) ((if (some impl/contains-wilds? (map first routes))
linear-router lookup-router) routes opts)))) linear-router lookup-router) routes opts))))

View file

@ -139,12 +139,11 @@
:params {:id "1", :sub-id "2"}}) :params {:id "1", :sub-id "2"}})
(reitit/match-by-path router "/api/user/1/2")))))) (reitit/match-by-path router "/api/user/1/2"))))))
(deftest first-conflicting-routes-test (deftest conflicting-routes-test
(are [conflicting? data] (are [conflicting? data]
(let [routes (reitit/resolve-routes data {})] (let [routes (reitit/resolve-routes data {})
(= (if conflicting? routes) conflicts (-> routes (reitit/resolve-routes {}) (reitit/conflicting-routes))]
(reitit/first-conflicting-routes (if conflicting? (seq conflicts) (nil? conflicts)))
(reitit/resolve-routes routes {}))))
true [["/a"] true [["/a"]
["/a"]] ["/a"]]
@ -173,6 +172,14 @@
true [["/v2/public/messages/dataset/bulk"] true [["/v2/public/messages/dataset/bulk"]
["/v2/public/messages/dataset/:dataset-id"]]) ["/v2/public/messages/dataset/:dataset-id"]])
(testing "all conflicts are returned"
(is (= {["/a" {}] #{["/*d" {}] ["/:b" {}]},
["/:b" {}] #{["/c" {}] ["/*d" {}]},
["/c" {}] #{["/*d" {}]}}))
(-> [["/a"] ["/:b"] ["/c"] ["/*d"]]
(reitit/resolve-routes {})
(reitit/conflicting-routes)))
(testing "router with conflicting routes" (testing "router with conflicting routes"
(testing "throws by default" (testing "throws by default"
(is (thrown-with-msg? (is (thrown-with-msg?
@ -186,4 +193,3 @@
(reitit/router (reitit/router
[["/a"] ["/a"]] [["/a"] ["/a"]]
{:conflicts (constantly nil)}))))))) {:conflicts (constantly nil)})))))))