mirror of
https://github.com/metosin/reitit.git
synced 2026-01-24 15:19:01 +00:00
Segment-router to rule 'em all
This commit is contained in:
parent
607e34c671
commit
8019cebdc7
2 changed files with 70 additions and 1 deletions
50
modules/reitit-core/src/reitit/segment.cljc
Normal file
50
modules/reitit-core/src/reitit/segment.cljc
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
(ns reitit.segment
|
||||||
|
(:require [reitit.impl :as impl]))
|
||||||
|
|
||||||
|
(defrecord Match [data params])
|
||||||
|
|
||||||
|
(defprotocol Segment
|
||||||
|
(-insert [this ps data])
|
||||||
|
(-lookup [this ps params]))
|
||||||
|
|
||||||
|
(extend-protocol Segment
|
||||||
|
nil
|
||||||
|
(-insert [this ps data])
|
||||||
|
(-lookup [this ps params]))
|
||||||
|
|
||||||
|
(defn- segments [^String path]
|
||||||
|
(mapv
|
||||||
|
(fn [^String p]
|
||||||
|
(if (impl/wild-param? p) (-> p (subs 1) keyword) p))
|
||||||
|
(.split path "/")))
|
||||||
|
|
||||||
|
;; TODO: catch-all
|
||||||
|
(defn- segment
|
||||||
|
([]
|
||||||
|
(segment {} #{} nil))
|
||||||
|
([children wilds data]
|
||||||
|
(let [children' (impl/fast-map children)]
|
||||||
|
(reify
|
||||||
|
Segment
|
||||||
|
(-insert [_ [p & ps] data]
|
||||||
|
(if-not p
|
||||||
|
(segment children wilds data)
|
||||||
|
(let [wilds (if (keyword? p) (conj wilds p) wilds)
|
||||||
|
children (update children p #(-insert (or % (segment)) ps data))]
|
||||||
|
(segment children wilds data))))
|
||||||
|
(-lookup [_ [p & ps] params]
|
||||||
|
(if (nil? p)
|
||||||
|
(assoc data :params params)
|
||||||
|
(or (-lookup (impl/fast-get children' p) ps params)
|
||||||
|
(some #(-lookup (impl/fast-get children' %) ps (assoc params % p)) wilds))))))))
|
||||||
|
|
||||||
|
(defn create [paths]
|
||||||
|
(reduce
|
||||||
|
(fn [segment [p data]]
|
||||||
|
(let [ps (segments p)]
|
||||||
|
(-insert segment ps (map->Match {:data data}))))
|
||||||
|
(segment) paths))
|
||||||
|
|
||||||
|
(defn lookup [segment ^String path]
|
||||||
|
(let [ps (.split path "/")]
|
||||||
|
(-lookup segment ps {})))
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
(: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.trie :as trie]
|
||||||
|
[reitit.segment :as segment]
|
||||||
[criterium.core :as cc]))
|
[criterium.core :as cc]))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
|
@ -75,6 +76,9 @@
|
||||||
(trie/insert acc p d))
|
(trie/insert acc p d))
|
||||||
nil routes))
|
nil routes))
|
||||||
|
|
||||||
|
(def reitit-segment
|
||||||
|
(segment/create routes))
|
||||||
|
|
||||||
(defn bench! []
|
(defn bench! []
|
||||||
|
|
||||||
;; 2.3ms
|
;; 2.3ms
|
||||||
|
|
@ -99,7 +103,22 @@
|
||||||
;; 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" {})))
|
||||||
|
|
||||||
|
;; 0.9ms (initial)
|
||||||
|
;; 0.5ms (protocols)
|
||||||
|
;; 1.0ms (with path params)
|
||||||
|
;; 1.0ms (Match records)
|
||||||
|
;; 0.63ms (Single sweep path params)
|
||||||
|
;; 0.51ms (Cleanup)
|
||||||
|
(cc/quick-bench
|
||||||
|
(dotimes [_ 1000]
|
||||||
|
(segment/lookup reitit-segment "/v1/orgs/1/topics"))))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(bench!))
|
(bench!))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(p/lookup pedestal-tree "/v1/orgs/1/topics")
|
||||||
|
(trie/lookup reitit-tree "/v1/orgs/1/topics" {})
|
||||||
|
(segment/lookup reitit-segment "/v1/orgs/1/topics"))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue