mirror of
https://github.com/metosin/reitit.git
synced 2025-12-21 10:01:11 +00:00
3x faster default path-parameter decoding
This commit is contained in:
parent
10dc5702a1
commit
9ce898a0b4
4 changed files with 61 additions and 33 deletions
|
|
@ -19,15 +19,16 @@
|
|||
(java.util HashMap Map)
|
||||
(java.net URLEncoder URLDecoder))))
|
||||
|
||||
(defn map-kv
|
||||
"Applies a function to every value of a map.
|
||||
|
||||
(defn maybe-map-values
|
||||
"Applies a function to every value of a map, updates the value if not nil.
|
||||
Also works on vectors. Maintains key for maps, order for vectors."
|
||||
[f coll]
|
||||
(reduce-kv
|
||||
(fn [m k v]
|
||||
(assoc m k (f v)))
|
||||
(empty coll)
|
||||
(fn [coll k v]
|
||||
(if-let [v' (f v)]
|
||||
(assoc coll k v')
|
||||
coll))
|
||||
coll
|
||||
coll))
|
||||
|
||||
(defn wild? [s]
|
||||
|
|
@ -191,17 +192,19 @@
|
|||
#?(:clj (str/replace s #"[^A-Za-z0-9\!'\(\)\*_~.-]+" percent-encode)
|
||||
:cljs (js/encodeURIComponent s))))
|
||||
|
||||
(defn url-decode [s]
|
||||
(defn maybe-url-decode [s]
|
||||
(if s
|
||||
#?(:clj (if (.contains ^String s "%")
|
||||
(URLDecoder/decode
|
||||
(if (.contains ^String s "+")
|
||||
(.replace ^String s "+" "%2B")
|
||||
s)
|
||||
"UTF-8")
|
||||
s)
|
||||
"UTF-8"))
|
||||
:cljs (js/decodeURIComponent s))))
|
||||
|
||||
(defn url-decode [s]
|
||||
(or (maybe-url-decode s) s))
|
||||
|
||||
(defn form-encode [s]
|
||||
(if s
|
||||
#?(:clj (URLEncoder/encode ^String s "UTF-8")
|
||||
|
|
@ -217,7 +220,7 @@
|
|||
(defn url-decode-coll
|
||||
"URL-decodes maps and vectors"
|
||||
[coll]
|
||||
(map-kv url-decode coll))
|
||||
(maybe-map-values maybe-url-decode coll))
|
||||
|
||||
(defprotocol IntoString
|
||||
(into-string [_]))
|
||||
|
|
@ -251,7 +254,7 @@
|
|||
(defn path-params
|
||||
"Convert parameters' values into URL-encoded strings, suitable for URL paths"
|
||||
[params]
|
||||
(map-kv #(url-encode (into-string %)) params))
|
||||
(maybe-map-values #(url-encode (into-string %)) params))
|
||||
|
||||
(defn query-string
|
||||
"shallow transform of query parameters into query string"
|
||||
|
|
|
|||
|
|
@ -15,16 +15,16 @@
|
|||
(-lookup [_ _ _]))
|
||||
|
||||
(defn- -catch-all [children catch-all path-params p ps]
|
||||
(if catch-all
|
||||
(-lookup
|
||||
(impl/fast-get children catch-all)
|
||||
nil
|
||||
(assoc path-params catch-all (str/join "/" (cons p ps))))))
|
||||
(assoc path-params catch-all (str/join "/" (cons p ps)))))
|
||||
|
||||
(defn- segment
|
||||
([] (segment {} #{} nil nil))
|
||||
([children wilds catch-all match]
|
||||
(let [children' (impl/fast-map children)]
|
||||
(let [children' (impl/fast-map children)
|
||||
wilds? (seq wilds)]
|
||||
^{:type ::segment}
|
||||
(reify
|
||||
Segment
|
||||
|
|
@ -40,8 +40,8 @@
|
|||
(if (nil? p)
|
||||
(when match (assoc match :path-params path-params))
|
||||
(or (-lookup (impl/fast-get children' p) ps path-params)
|
||||
(some #(-lookup (impl/fast-get children' %) ps (assoc path-params % p)) wilds)
|
||||
(-catch-all children' catch-all path-params p ps))))))))
|
||||
(if wilds? (some #(-lookup (impl/fast-get children' %) ps (assoc path-params % p)) wilds))
|
||||
(if catch-all (-catch-all children' catch-all path-params p ps)))))))))
|
||||
|
||||
(defn insert [root path data]
|
||||
(-insert (or root (segment)) (impl/segments path) (map->Match {:data data})))
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
(:require [criterium.core :as cc]
|
||||
[reitit.perf-utils :refer :all]
|
||||
[reitit.ring :as ring]
|
||||
[clojure.string :as str]
|
||||
[reitit.core :as r]))
|
||||
[clojure.string :as str]))
|
||||
|
||||
;;
|
||||
;; start repl with `lein perf repl`
|
||||
|
|
@ -313,6 +312,7 @@
|
|||
|
||||
;; 40ns (httprouter)
|
||||
;; 140ns
|
||||
;; 120ns (faster decode params)
|
||||
(let [req (map->Req {:request-method :get, :uri "/user/repos"})]
|
||||
(title "static")
|
||||
(assert (= {:status 200, :body "/user/repos"} (app req)))
|
||||
|
|
@ -320,6 +320,7 @@
|
|||
|
||||
;; 160ns (httprouter)
|
||||
;; 990ns
|
||||
;; 830ns (faster decode params)
|
||||
(let [req (map->Req {:request-method :get, :uri "/repos/julienschmidt/httprouter/stargazers"})]
|
||||
(title "param")
|
||||
(assert (= {:status 200, :body "/repos/:owner/:repo/stargazers"} (app req)))
|
||||
|
|
@ -327,6 +328,7 @@
|
|||
|
||||
;; 30µs (httprouter)
|
||||
;; 190µs
|
||||
;; 160µs (faster decode params)
|
||||
(let [requests (mapv route->req routes)]
|
||||
(title "all")
|
||||
(cc/quick-bench
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
(:require [criterium.core :as cc]
|
||||
[reitit.perf-utils :refer :all]
|
||||
[ring.util.codec]
|
||||
[reitit.impl])
|
||||
[reitit.impl]
|
||||
[reitit.impl :as impl])
|
||||
(:import (java.net URLDecoder URLEncoder)))
|
||||
|
||||
;;
|
||||
|
|
@ -163,8 +164,30 @@
|
|||
"1"]]
|
||||
(test! f s))))
|
||||
|
||||
(defn url-encode-coll! []
|
||||
|
||||
(suite "url-encode-coll")
|
||||
|
||||
;; 740ns
|
||||
(test "something to decode")
|
||||
(test! impl/url-decode-coll
|
||||
{:a "aja%20hiljaa+sillalla"
|
||||
:b "aja_hiljaa_sillalla"
|
||||
:c "1+1"
|
||||
:d "1"})
|
||||
|
||||
;; 124ns
|
||||
;; 50ns (maybe-map-values)
|
||||
(test "nothing to decode")
|
||||
(test! impl/url-decode-coll
|
||||
{:a "aja+20hiljaa+sillalla"
|
||||
:b "aja_hiljaa_sillalla"
|
||||
:c "1+1"
|
||||
:d "1"}))
|
||||
|
||||
(comment
|
||||
(url-decode!)
|
||||
(url-encode!)
|
||||
(form-decode!)
|
||||
(form-encode!))
|
||||
(form-encode!)
|
||||
(url-encode-coll!))
|
||||
|
|
|
|||
Loading…
Reference in a new issue