mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 16:31:11 +00:00
Remove prefix-tree router as it's broken
This commit is contained in:
parent
4490fc1685
commit
e0786b73f0
4 changed files with 3 additions and 289 deletions
|
|
@ -1,7 +1,6 @@
|
||||||
(ns reitit.core
|
(ns reitit.core
|
||||||
(:require [meta-merge.core :refer [meta-merge]]
|
(:require [meta-merge.core :refer [meta-merge]]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[reitit.trie :as trie]
|
|
||||||
[reitit.segment :as segment]
|
[reitit.segment :as segment]
|
||||||
[reitit.impl :as impl #?@(:cljs [:refer [Route]])])
|
[reitit.impl :as impl #?@(:cljs [:refer [Route]])])
|
||||||
#?(:clj
|
#?(:clj
|
||||||
|
|
@ -220,47 +219,6 @@
|
||||||
(if-let [match (impl/fast-get lookup name)]
|
(if-let [match (impl/fast-get lookup name)]
|
||||||
(match params)))))))
|
(match params)))))))
|
||||||
|
|
||||||
(defn prefix-tree-router
|
|
||||||
"Creates a prefix-tree router from resolved routes and optional
|
|
||||||
expanded options. See [[router]] for available options"
|
|
||||||
([routes]
|
|
||||||
(prefix-tree-router routes {}))
|
|
||||||
([routes opts]
|
|
||||||
(let [compiled (compile-routes routes opts)
|
|
||||||
names (find-names routes opts)
|
|
||||||
[pl nl] (reduce
|
|
||||||
(fn [[pl nl] [p {:keys [name] :as data} result]]
|
|
||||||
(let [{:keys [params] :as route} (impl/create [p data result])
|
|
||||||
f #(if-let [path (impl/path-for route %)]
|
|
||||||
(->Match p data result % path)
|
|
||||||
(->PartialMatch p data result % params))]
|
|
||||||
[(trie/insert pl p (->Match p data result nil nil))
|
|
||||||
(if name (assoc nl name f) nl)]))
|
|
||||||
[nil {}] compiled)
|
|
||||||
lookup (impl/fast-map nl)]
|
|
||||||
^{:type ::router}
|
|
||||||
(reify
|
|
||||||
Router
|
|
||||||
(router-name [_]
|
|
||||||
:prefix-tree-router)
|
|
||||||
(routes [_]
|
|
||||||
compiled)
|
|
||||||
(options [_]
|
|
||||||
opts)
|
|
||||||
(route-names [_]
|
|
||||||
names)
|
|
||||||
(match-by-path [_ path]
|
|
||||||
(if-let [match (trie/lookup pl path {})]
|
|
||||||
(-> (:data match)
|
|
||||||
(assoc :params (:params match))
|
|
||||||
(assoc :path path))))
|
|
||||||
(match-by-name [_ name]
|
|
||||||
(if-let [match (impl/fast-get lookup name)]
|
|
||||||
(match nil)))
|
|
||||||
(match-by-name [_ name params]
|
|
||||||
(if-let [match (impl/fast-get lookup name)]
|
|
||||||
(match params)))))))
|
|
||||||
|
|
||||||
(defn segment-router
|
(defn segment-router
|
||||||
"Creates a special prefix-tree style segment router from resolved routes and optional
|
"Creates a special prefix-tree style segment router from resolved routes and optional
|
||||||
expanded options. See [[router]] for available options"
|
expanded options. See [[router]] for available options"
|
||||||
|
|
|
||||||
|
|
@ -1,241 +0,0 @@
|
||||||
(ns reitit.trie
|
|
||||||
(:require [reitit.impl :as impl]
|
|
||||||
[clojure.string :as str]))
|
|
||||||
|
|
||||||
;;
|
|
||||||
;; original https://github.com/pedestal/pedestal/blob/master/route/src/io/pedestal/http/route/prefix_tree.clj
|
|
||||||
;;
|
|
||||||
|
|
||||||
(declare insert)
|
|
||||||
|
|
||||||
(defn- char-key [s i]
|
|
||||||
(if (< i (count s))
|
|
||||||
(subs s i (inc i))))
|
|
||||||
|
|
||||||
(defn- maybe-wild-node [children]
|
|
||||||
(get children ":"))
|
|
||||||
|
|
||||||
(defn- maybe-catch-all-node [children]
|
|
||||||
(get children "*"))
|
|
||||||
|
|
||||||
(defprotocol Node
|
|
||||||
(lookup [this path params])
|
|
||||||
(get-segment [this])
|
|
||||||
(update-segment [this subs lcs])
|
|
||||||
(get-data [this])
|
|
||||||
(set-data [this data])
|
|
||||||
(get-chidren [this])
|
|
||||||
(add-child [this key child])
|
|
||||||
(insert-child [this key path-spec data]))
|
|
||||||
|
|
||||||
(extend-protocol Node
|
|
||||||
nil
|
|
||||||
(lookup [_ _ _])
|
|
||||||
(get-segment [_]))
|
|
||||||
|
|
||||||
(defrecord Match [data params])
|
|
||||||
|
|
||||||
(defn- wild-node [segment param children data]
|
|
||||||
(let [?wild (maybe-wild-node children)
|
|
||||||
?catch (maybe-catch-all-node children)
|
|
||||||
children' (impl/fast-map children)]
|
|
||||||
^{:type ::node}
|
|
||||||
(reify
|
|
||||||
Node
|
|
||||||
(lookup [_ path params]
|
|
||||||
(let [i (.indexOf ^String path "/")]
|
|
||||||
(if (pos? i)
|
|
||||||
(let [value (subs path 0 i)]
|
|
||||||
(let [child (impl/fast-get children' (char-key path (inc i)))
|
|
||||||
path' (subs path (inc i))
|
|
||||||
params (assoc params param value)]
|
|
||||||
(or (lookup child path' params)
|
|
||||||
(lookup ?wild path' params)
|
|
||||||
(lookup ?catch path' params))))
|
|
||||||
(->Match data (assoc params param path)))))
|
|
||||||
(get-segment [_]
|
|
||||||
segment)
|
|
||||||
(get-data [_]
|
|
||||||
data)
|
|
||||||
(set-data [_ data]
|
|
||||||
(wild-node segment param children data))
|
|
||||||
(get-chidren [_]
|
|
||||||
children)
|
|
||||||
(add-child [_ key child]
|
|
||||||
(wild-node segment param (assoc children key child) data))
|
|
||||||
(insert-child [_ key path-spec child-data]
|
|
||||||
(wild-node segment param (update children key insert path-spec child-data) data)))))
|
|
||||||
|
|
||||||
(defn- catch-all-node [segment children param data]
|
|
||||||
^{:type ::node}
|
|
||||||
(reify
|
|
||||||
Node
|
|
||||||
(lookup [_ path params]
|
|
||||||
(->Match data (assoc params param path)))
|
|
||||||
(get-segment [_]
|
|
||||||
segment)
|
|
||||||
(get-data [_]
|
|
||||||
data)
|
|
||||||
(get-chidren [_]
|
|
||||||
children)))
|
|
||||||
|
|
||||||
(defn- static-node [^String segment children data]
|
|
||||||
(let [size (count segment)
|
|
||||||
?wild (maybe-wild-node children)
|
|
||||||
?catch (maybe-catch-all-node children)
|
|
||||||
children' (impl/fast-map children)]
|
|
||||||
^{:type ::node}
|
|
||||||
(reify
|
|
||||||
Node
|
|
||||||
(lookup [_ path params]
|
|
||||||
(if (#?(:clj .equals, :cljs =) segment path)
|
|
||||||
(->Match data params)
|
|
||||||
(let [p (if (>= (count path) size) (subs path 0 size))]
|
|
||||||
(if (#?(:clj .equals, :cljs =) segment p)
|
|
||||||
(let [child (impl/fast-get children' (char-key path size))
|
|
||||||
path (subs path size)]
|
|
||||||
(or (lookup child path params)
|
|
||||||
(lookup ?wild path params)
|
|
||||||
(lookup ?catch path params)))))))
|
|
||||||
(get-segment [_]
|
|
||||||
segment)
|
|
||||||
(update-segment [_ subs lcs]
|
|
||||||
(static-node (subs segment lcs) children data))
|
|
||||||
(get-data [_]
|
|
||||||
data)
|
|
||||||
(set-data [_ data]
|
|
||||||
(static-node segment children data))
|
|
||||||
(get-chidren [_]
|
|
||||||
children)
|
|
||||||
(add-child [_ key child]
|
|
||||||
(static-node segment (assoc children key child) data))
|
|
||||||
(insert-child [_ key path-spec child-data]
|
|
||||||
(static-node segment (update children key insert path-spec child-data) data)))))
|
|
||||||
|
|
||||||
(defn- make-node
|
|
||||||
"Given a path-spec segment string and a payload object, return a new
|
|
||||||
tree node."
|
|
||||||
[segment data]
|
|
||||||
(cond
|
|
||||||
(impl/wild-param segment)
|
|
||||||
(wild-node segment (keyword (subs segment 1)) nil data)
|
|
||||||
|
|
||||||
(impl/catch-all-param segment)
|
|
||||||
(catch-all-node segment (keyword (subs segment 1)) nil data)
|
|
||||||
|
|
||||||
:else
|
|
||||||
(static-node segment nil data)))
|
|
||||||
|
|
||||||
(defn partition-wilds
|
|
||||||
"Given a path-spec string, return a seq of strings with wildcards
|
|
||||||
and catch-alls separated into their own strings. Eats the forward
|
|
||||||
slash following a wildcard."
|
|
||||||
[path-spec]
|
|
||||||
(let [groups (partition-by impl/wild? (str/split path-spec #"/"))
|
|
||||||
first-groups (butlast groups)
|
|
||||||
last-group (last groups)]
|
|
||||||
(flatten
|
|
||||||
(conj (mapv #(if (impl/wild? (first %))
|
|
||||||
%
|
|
||||||
(str (str/join "/" %) "/"))
|
|
||||||
first-groups)
|
|
||||||
(if (impl/wild? (first last-group))
|
|
||||||
last-group
|
|
||||||
(str/join "/" last-group))))))
|
|
||||||
|
|
||||||
(defn- new-node
|
|
||||||
"Given a path-spec and a payload object, return a new tree node. If
|
|
||||||
the path-spec contains wildcards or catch-alls, will return parent
|
|
||||||
node of a tree (linked list)."
|
|
||||||
[path-spec data]
|
|
||||||
(if (impl/contains-wilds? path-spec)
|
|
||||||
(let [parts (partition-wilds path-spec)]
|
|
||||||
(reduce (fn [child segment]
|
|
||||||
(when (impl/catch-all-param segment)
|
|
||||||
(throw (ex-info "catch-all may only appear at the end of a path spec"
|
|
||||||
{:patch-spec path-spec})))
|
|
||||||
(-> (make-node segment nil)
|
|
||||||
(add-child (subs (get-segment child) 0 1) child)))
|
|
||||||
(let [segment (last parts)]
|
|
||||||
(make-node segment data))
|
|
||||||
(reverse (butlast parts))))
|
|
||||||
(make-node path-spec data)))
|
|
||||||
|
|
||||||
(defn- calc-lcs
|
|
||||||
"Given two strings, return the end index of the longest common
|
|
||||||
prefix string."
|
|
||||||
[s1 s2]
|
|
||||||
(loop [i 1]
|
|
||||||
(cond (or (< (count s1) i)
|
|
||||||
(< (count s2) i))
|
|
||||||
(dec i)
|
|
||||||
|
|
||||||
(= (subs s1 0 i)
|
|
||||||
(subs s2 0 i))
|
|
||||||
(recur (inc i))
|
|
||||||
|
|
||||||
:else (dec i))))
|
|
||||||
|
|
||||||
(defn- split
|
|
||||||
"Given a node, a path-spec, a payload object to insert into the tree
|
|
||||||
and the lcs, split the node and return a new parent node with the
|
|
||||||
old contents of node and the new item as children.
|
|
||||||
lcs is the index of the longest common string in path-spec and the
|
|
||||||
segment of node."
|
|
||||||
[node path-spec data lcs]
|
|
||||||
(let [segment (get-segment node)
|
|
||||||
common (subs path-spec 0 lcs)
|
|
||||||
parent (new-node common nil)]
|
|
||||||
(if (= common path-spec)
|
|
||||||
(-> (set-data parent data)
|
|
||||||
(add-child (char-key segment lcs) (update-segment node subs lcs)))
|
|
||||||
(-> parent
|
|
||||||
(add-child (char-key segment lcs) (update-segment node subs lcs))
|
|
||||||
(insert-child (char-key path-spec lcs) (subs path-spec lcs) data)))))
|
|
||||||
|
|
||||||
(defn insert
|
|
||||||
"Given a tree node, a path-spec and a payload object, return a new
|
|
||||||
tree with payload inserted."
|
|
||||||
[node path-spec data]
|
|
||||||
(let [segment (get-segment node)]
|
|
||||||
(cond (nil? node)
|
|
||||||
(new-node path-spec data)
|
|
||||||
|
|
||||||
(= segment path-spec)
|
|
||||||
(set-data node data)
|
|
||||||
|
|
||||||
;; handle case where path-spec is a wildcard param
|
|
||||||
(impl/wild-param path-spec)
|
|
||||||
(let [lcs (calc-lcs segment path-spec)
|
|
||||||
common (subs path-spec 0 lcs)]
|
|
||||||
(if (= common segment)
|
|
||||||
(let [path-spec (subs path-spec (inc lcs))]
|
|
||||||
(insert-child node (subs path-spec 0 1) path-spec data))
|
|
||||||
(throw (ex-info "route conflict"
|
|
||||||
{:node node
|
|
||||||
:path-spec path-spec
|
|
||||||
:segment segment}))))
|
|
||||||
|
|
||||||
;; in the case where path-spec is a catch-all, node should always be nil.
|
|
||||||
;; getting here means we have an invalid route specification
|
|
||||||
(impl/catch-all-param path-spec)
|
|
||||||
(throw (ex-info "route conflict"
|
|
||||||
{:node node
|
|
||||||
:path-spec path-spec
|
|
||||||
:segment segment}))
|
|
||||||
|
|
||||||
:else
|
|
||||||
(let [lcs (calc-lcs segment path-spec)]
|
|
||||||
(cond (= lcs (count segment))
|
|
||||||
(insert-child node (char-key path-spec lcs) (subs path-spec lcs) data)
|
|
||||||
|
|
||||||
:else
|
|
||||||
(split node path-spec data lcs))))))
|
|
||||||
|
|
||||||
(defn view
|
|
||||||
"Returns a view representation of a prefix-tree."
|
|
||||||
[x]
|
|
||||||
(vec (concat
|
|
||||||
[(get-segment x)]
|
|
||||||
(some->> (get-chidren x) vals seq (map view))
|
|
||||||
(some->> (get-data x) vector))))
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
(ns reitit.prefix-tree-perf-test
|
(ns reitit.prefix-tree-perf-test
|
||||||
(:require [clojure.test :refer :all]
|
(:require [clojure.test :refer :all]
|
||||||
[io.pedestal.http.route.prefix-tree :as p]
|
[io.pedestal.http.route.prefix-tree :as p]
|
||||||
[reitit.trie :as trie]
|
|
||||||
[reitit.segment :as segment]
|
[reitit.segment :as segment]
|
||||||
[criterium.core :as cc]))
|
[criterium.core :as cc]))
|
||||||
|
|
||||||
|
|
@ -70,7 +69,7 @@
|
||||||
(p/insert acc p d))
|
(p/insert acc p d))
|
||||||
nil routes))
|
nil routes))
|
||||||
|
|
||||||
(def reitit-tree
|
#_(def reitit-tree
|
||||||
(reduce
|
(reduce
|
||||||
(fn [acc [p d]]
|
(fn [acc [p d]]
|
||||||
(trie/insert acc p d))
|
(trie/insert acc p d))
|
||||||
|
|
@ -101,7 +100,7 @@
|
||||||
;; 0.8ms (flattened matching)
|
;; 0.8ms (flattened matching)
|
||||||
;; 0.8ms (return route-data)
|
;; 0.8ms (return route-data)
|
||||||
;; 0.8ms (fix payloads)
|
;; 0.8ms (fix payloads)
|
||||||
(cc/quick-bench
|
#_(cc/quick-bench
|
||||||
(dotimes [_ 1000]
|
(dotimes [_ 1000]
|
||||||
(trie/lookup reitit-tree "/v1/orgs/1/topics" {})))
|
(trie/lookup reitit-tree "/v1/orgs/1/topics" {})))
|
||||||
|
|
||||||
|
|
@ -120,5 +119,5 @@
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(p/lookup pedestal-tree "/v1/orgs/1/topics")
|
(p/lookup pedestal-tree "/v1/orgs/1/topics")
|
||||||
(trie/lookup reitit-tree "/v1/orgs/1/topics" {})
|
#_(trie/lookup reitit-tree "/v1/orgs/1/topics" {})
|
||||||
(segment/lookup reitit-segment "/v1/orgs/1/topics"))
|
(segment/lookup reitit-segment "/v1/orgs/1/topics"))
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@
|
||||||
)))
|
)))
|
||||||
|
|
||||||
r/linear-router :linear-router
|
r/linear-router :linear-router
|
||||||
#_#_r/prefix-tree-router :prefix-tree-router
|
|
||||||
r/segment-router :segment-router
|
r/segment-router :segment-router
|
||||||
r/mixed-router :mixed-router))
|
r/mixed-router :mixed-router))
|
||||||
|
|
||||||
|
|
@ -102,7 +101,6 @@
|
||||||
r/lookup-router :lookup-router
|
r/lookup-router :lookup-router
|
||||||
r/single-static-path-router :single-static-path-router
|
r/single-static-path-router :single-static-path-router
|
||||||
r/linear-router :linear-router
|
r/linear-router :linear-router
|
||||||
r/prefix-tree-router :prefix-tree-router
|
|
||||||
r/segment-router :segment-router
|
r/segment-router :segment-router
|
||||||
r/mixed-router :mixed-router))
|
r/mixed-router :mixed-router))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue