mirror of
https://github.com/metosin/reitit.git
synced 2025-12-16 16:01:11 +00:00
Implement catch-all from trie
This commit is contained in:
parent
fe0ea19e31
commit
eaee4ca38d
4 changed files with 59 additions and 9 deletions
|
|
@ -13,8 +13,8 @@ import java.util.*;
|
|||
|
||||
public class Trie {
|
||||
|
||||
private static String decode(char[] chars, int i, int j, boolean hasPercent, boolean hasPlus) {
|
||||
final String s = new String(chars, i, j);
|
||||
private static String decode(char[] chars, int offset, int count, boolean hasPercent, boolean hasPlus) {
|
||||
final String s = new String(chars, offset, count);
|
||||
try {
|
||||
if (hasPercent) {
|
||||
return URLDecoder.decode(hasPlus ? s.replace("+", "%2B") : s, "UTF-8");
|
||||
|
|
@ -24,6 +24,20 @@ public class Trie {
|
|||
return s;
|
||||
}
|
||||
|
||||
private static String decode(char[] chars, int offset, int count) {
|
||||
boolean hasPercent = false;
|
||||
boolean hasPlus = false;
|
||||
for (int j = offset; j < offset + count; j++) {
|
||||
if (chars[j] == '%') {
|
||||
hasPercent = true;
|
||||
} else if (chars[j] == '+') {
|
||||
hasPlus = true;
|
||||
}
|
||||
}
|
||||
System.err.println();
|
||||
return decode(chars, offset, count, hasPercent, hasPlus);
|
||||
}
|
||||
|
||||
public static class Match {
|
||||
final ITransientMap params = PersistentArrayMap.EMPTY.asTransient();
|
||||
public Object data;
|
||||
|
|
@ -36,7 +50,7 @@ public class Trie {
|
|||
public String toString() {
|
||||
Map<Object, Object> m = new HashMap<>();
|
||||
m.put(Keyword.intern("data"), data);
|
||||
m.put(Keyword.intern("params"), params.persistent());
|
||||
m.put(Keyword.intern("params"), parameters());
|
||||
return m.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -163,6 +177,35 @@ public class Trie {
|
|||
}
|
||||
}
|
||||
|
||||
public static CatchAllMatcher catchAllMatcher(Keyword parameter, Object data) {
|
||||
return new CatchAllMatcher(parameter, data);
|
||||
}
|
||||
|
||||
static final class CatchAllMatcher implements Matcher {
|
||||
private final Keyword parameter;
|
||||
private final Object data;
|
||||
|
||||
CatchAllMatcher(Keyword parameter, Object data) {
|
||||
this.parameter = parameter;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Match match(int i, Path path, Match match) {
|
||||
if (i < path.value.length) {
|
||||
match.params.assoc(parameter, decode(path.value, i, path.size - i));
|
||||
match.data = data;
|
||||
return match;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + parameter + " " + new DataMatcher(data) + "]";
|
||||
}
|
||||
}
|
||||
|
||||
public static LinearMatcher linearMatcher(List<Matcher> childs) {
|
||||
return new LinearMatcher(childs);
|
||||
}
|
||||
|
|
@ -198,6 +241,10 @@ public class Trie {
|
|||
return matcher.match(0, new Path(path), new Match());
|
||||
}
|
||||
|
||||
public static Matcher scanner(List<Matcher> matchers) {
|
||||
return new LinearMatcher(matchers);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
//Matcher matcher = new StaticMatcher("/kikka", new StaticMatcher("/kukka", new DataMatcher(1)));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
(ns reitit.core
|
||||
(:require [meta-merge.core :refer [meta-merge]]
|
||||
[clojure.string :as str]
|
||||
[reitit.segment :as segment]
|
||||
[reitit.trie :as trie]
|
||||
[reitit.impl :as impl #?@(:cljs [:refer [Route]])])
|
||||
#?(:clj
|
||||
|
|
@ -176,12 +175,12 @@
|
|||
f #(if-let [path (impl/path-for route %)]
|
||||
(->Match p data result (impl/url-decode-coll %) path)
|
||||
(->PartialMatch p data result % path-params))]
|
||||
[(conj pl (-> (segment/insert nil p (->Match p data result nil nil)) (segment/compile)))
|
||||
[(conj pl (-> (trie/insert nil p (->Match p data result nil nil)) (trie/compile)))
|
||||
(if name (assoc nl name f) nl)]))
|
||||
[[] {}]
|
||||
compiled-routes)
|
||||
lookup (impl/fast-map nl)
|
||||
scanner (segment/scanner pl)
|
||||
scanner (trie/scanner pl)
|
||||
routes (uncompile-routes compiled-routes)]
|
||||
^{:type ::router}
|
||||
(reify
|
||||
|
|
@ -197,7 +196,7 @@
|
|||
(route-names [_]
|
||||
names)
|
||||
(match-by-path [_ path]
|
||||
(if-let [match (segment/lookup scanner path)]
|
||||
(if-let [match (trie/lookup scanner path)]
|
||||
(-> (:data match)
|
||||
(assoc :path-params (:path-params match))
|
||||
(assoc :path path))))
|
||||
|
|
|
|||
|
|
@ -94,7 +94,8 @@
|
|||
(let [matchers (cond-> []
|
||||
data (conj (Trie/dataMatcher data))
|
||||
children (into (for [[p c] children] (Trie/staticMatcher p (compile c))))
|
||||
wilds (into (for [[p c] wilds] (Trie/wildMatcher p (compile c)))))]
|
||||
wilds (into (for [[p c] wilds] (Trie/wildMatcher p (compile c))))
|
||||
catch-all (into (for [[p c] catch-all] (Trie/catchAllMatcher (first p) (:data c)))))]
|
||||
(if (rest matchers)
|
||||
(Trie/linearMatcher matchers)
|
||||
(first matchers))))
|
||||
|
|
@ -108,6 +109,9 @@
|
|||
(if-let [match ^Trie$Match (Trie/lookup matcher ^String path)]
|
||||
(->Match (.data match) (.parameters match))))
|
||||
|
||||
(defn scanner [compiled-tries]
|
||||
(Trie/scanner compiled-tries))
|
||||
|
||||
;;
|
||||
;; matcher
|
||||
;;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
"modules/reitit-sieppari/src"
|
||||
"modules/reitit-pedestal/src"]
|
||||
|
||||
;:java-source-paths ["modules/reitit-core/java-src"]
|
||||
:java-source-paths ["modules/reitit-core/java-src"]
|
||||
|
||||
:dependencies [[org.clojure/clojure "1.10.0"]
|
||||
[org.clojure/clojurescript "1.10.439"]
|
||||
|
|
|
|||
Loading…
Reference in a new issue