Skip to content

Commit

Permalink
multiple values: all green
Browse files Browse the repository at this point in the history
  • Loading branch information
vm-001 committed Dec 18, 2023
1 parent 79e80ba commit 4bb8847
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 56 deletions.
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ build:
luarocks make

test: build
luajit spec/utils_spec.lua
@luajit spec/utils_spec.lua
@luajit spec/parser_spec.lua
@luajit spec/router_spec.lua

test2: build
TEST_NGINX_LOG_LEVEL=info prove -I../test-nginx/lib -I. -r -s t/
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,17 @@ TODO 处理路由冲突

- /user/:name/info
- /user/:id/info


## 推广工作

- v2ex
- QQ群
- 微信群
- hackernew
- Kong 博客
- 自己博客

- 找同事 star
- 提 issue
- 提 PR
1 change: 0 additions & 1 deletion lua-resty-router-tree-dev-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ build = {
["router-tree.route"] = "src/resty/route.lua",
["router-tree.parser"] = "src/resty/parser/parser.lua",
["router-tree.parser.style.default"] = "src/resty/parser/style/default.lua",
["router-tree.parser.style.ant"] = "src/resty/parser/style/ant.lua",
["router-tree.trie"] = "src/resty/trie.lua",
["router-tree.utils"] = "src/resty/utils.lua",
},
Expand Down
67 changes: 48 additions & 19 deletions spec/trie_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,53 @@ local cjson = require "cjson"
local inspect = require "inspect"

describe("Trie", function()
it("", function()
local root = Trie.new()
root:add("key", "value")
assert.equal("key", root.path)
assert.equal("value", root.value)
end)

it("", function()
local root = Trie.new()
root:add("cat", "cat")
root:add("dog", "dog")
--print(inspect(root))
--print(cjson.encode(root))
describe("add", function()
it("", function()
local root = Trie.new()
root:add("key", "value")
assert.equal("key", root.path)
assert.equal("value", root.value)
end)

it("", function()
local root = Trie.new()
root:add("cat", "cat")
root:add("dog", "dog")
--print(inspect(root))
--print(cjson.encode(root))
end)

it("", function()
local root = Trie.new()
root:add("/:name/foo", "1")
root:add("/:name/foo*", "2")
end)
end)

it("需要修复", function()
local root = Trie.new()
root:add("/:name/foo", "1")
root:add("/:name/foo*", "2")
describe("and + traverse", function()
it("sanity", function()

end)

-- 重复节点
it("overrides node.value", function()
local root = Trie.new()
root:add("/:a/cc", "1")
root:add("/:b/cc", "2")
local values = root:traverse("/a/cc")
assert.same("2", values)
end)

it("invokes function in case conflict", function()
local root = Trie.new()
root:add("/:a/cc", "1")
root:add("/:a/cc", "2", function(node)
node.value = { node.value, "2" }
end)
local values = root:traverse("/a/cc")
assert.same({"1", "2"}, values)
end)
end)

it("sanity", function()
Expand Down Expand Up @@ -71,9 +99,10 @@ local function test1()
local mobdebug = require "mobdebug"
mobdebug.start("localhost", 28172)
local root = Trie.new()
root:add("/:name/foo", "1")
root:add("/:name/foo*", "2")
print("doge")
root:add("/:a/cc", "1")
root:add("/:b/cc", "2")
local values = root:traverse("/a/cc")
print(values)
end

test1()
48 changes: 32 additions & 16 deletions src/resty/router.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ local function add_route(self, path, route)
local wildcard = has_wildcard(path)
if wildcard then
-- wildcard
self.trie:add(path, route)
self.trie:add(path, { route }, function(node)
-- on duplicated
table.insert(node.value, route)
table.sort(node.value, sort_route)
end)
else
-- static
if not self.static[path] then
Expand Down Expand Up @@ -110,11 +114,16 @@ function Router:match(path, ctx)
-- route2 { paths = { "/aa/bb*" }, methods = { "POST" } }
-- :match("/aa/bb", { methond = "GET" } )
-- 从前缀树的查找过程中,最终进入到 "/aa/bb*", 但其实 method 不匹配到
local route, ok = self.trie:traverse(path, ctx)
local values, ok, count = self.trie:traverse(path, ctx)
if ok then
-- 多个节点
routes = ReverseTable(route) -- TODO 优化
route = find_route(routes, ctx)
local route
for n = count, 1, -1 do -- #values 可以从traverse里面得到
route = find_route(values[n], ctx)
if route then
break
end
end
if route then
if ctx.matched then
local _path = ctx.matched._path
Expand All @@ -128,21 +137,28 @@ function Router:match(path, ctx)
end
return route.handler
end
end

if route and route:is_match(ctx) then
if ctx.matched then
local _path = ctx.matched._path
local params = route.path_params[_path]
for i, param in ipairs(params) do
ctx.matched[param] = ctx.matched[i]
end
for i, _ in ipairs(ctx.matched) do
ctx.matched[i] = nil
else
if values then
local route = find_route(values, ctx)
if route then
if ctx.matched then
local _path = ctx.matched._path
local params = route.path_params[_path]
for i, param in ipairs(params) do
ctx.matched[param] = ctx.matched[i]
end
for i, _ in ipairs(ctx.matched) do
ctx.matched[i] = nil
end
end
return route.handler
end
end
return route.handler
end




if ctx and ctx.matched then -- ??? remove?
clear_table(ctx.matched)
end
Expand Down
26 changes: 25 additions & 1 deletion src/resty/sample.lua
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,37 @@ local function test5()
ngx.say(rx:match("/aa"))
end


local function test6()
local mobdebug = require "mobdebug"
mobdebug.start("localhost", 28172)
local radix = require("router-tree")
local rx = radix.new({
{
paths = {"/name/:name/foo"},
metadata = "metadata /name",
},
})

local opts = {matched = {}}
local meta = rx:match("/name/json/foo", opts)
ngx.say("match meta: ", meta)
ngx.say("matched: ", json.encode(opts.matched))

meta = rx:match("/name/json", opts)
ngx.say("match meta: ", meta)
ngx.say("matched: ", json.encode(opts.matched))
end

--test1()
--test2()

--test3()

--test4()

test5()
--test5()

test6()

--test_example()
39 changes: 21 additions & 18 deletions src/resty/trie.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-- Trie
--- Trie

local utils = require "router-tree.utils"
local Parser = require "router-tree.parser"
Expand All @@ -19,8 +19,7 @@ local BYTE_ASTERISK = byte("*")


local TrieNode = {}

local _mt = { __index = TrieNode }
local mt = { __index = TrieNode }

local TYPES = {
STATIC = 0,
Expand All @@ -40,25 +39,29 @@ function TrieNode.new(o)
type = o.type,
value = o.value, -- 有没有可能这个 Trie 不做 value 的插入,只是返回最后的节点,但是 node.value 的设置交给外部,这样就可以根据 priority 做 value 优先级循序
indexs = o.indexs or {},
full_path = o.full_path,
full_path = o.full_path, -- 如果叶子节点可以有多个 values,那么这里的 full_path 不能代表完成的路径
}

self.path_n = self.path and #self.path or 0

return setmetatable(self, _mt)
return setmetatable(self, mt)
end

--function TrieNode:tostring()
-- -- todo 如何在测试用可以 assert node 具有的结构
--end

function TrieNode:set(fn)
self.value = fn(self.value)
function TrieNode:set(value, fn)
if self.value and type(fn) =="function" then
fn(self, value)
return
end
self.value = value
end


local function insert_child(node, path, full_path, value)
local parser = Parser.new(path, "default")
local function insert_child(node, path, full_path, value, fn)
local parser = Parser.new(path, "default") -- 外部 :add 应该传一个 parser 进来?
local token = parser:next()
while token do
if byte(token) == BYTE_COLON then
Expand Down Expand Up @@ -87,7 +90,7 @@ local function insert_child(node, path, full_path, value)
end
end

node.value = value -- todo multiple values support
node:set(value, fn)
node.full_path = full_path
end

Expand All @@ -111,12 +114,12 @@ local function split(node, path, prefix_n)
node.indexs = { [str_sub(child.path, 1, 1)] = 1 }
end

function TrieNode:add(path, value)
function TrieNode:add(path, value, fn)
local full_path = path

if self.path == "" and not self.type then
-- current node is empty
insert_child(self, path, full_path, value)
insert_child(self, path, full_path, value, fn)
return
end

Expand Down Expand Up @@ -173,16 +176,16 @@ function TrieNode:add(path, value)
local child = TrieNode.new()
self.children = self.children or {}
table.insert(self.children, child)
insert_child(child, path, full_path, value)
insert_child(child, path, full_path, value, fn)
self.indexs[first_char] = #self.children
return
end

self.value = value
self:set(value, fn)
return
end

self.value = value
self:set(value, fn)
end

--local paths_i = 1 -- 没有特别明显的变化
Expand Down Expand Up @@ -248,7 +251,7 @@ function TrieNode:traverse(path, ctx)

-- 通配符

node = node.children[1]
node = node.children[1] -- 为什么要选 [1] ?
if node.type == TYPES.PARAM then
-- 找到第一个 /
local idx = find(path, "/", 1, true)
Expand Down Expand Up @@ -326,15 +329,15 @@ function TrieNode:traverse(path, ctx)
end

if matched_n > 0 then
return matched_values, true
return matched_values, true, matched_n
end

return nil
end

if matched_n > 0 then
-- { { route1, route2 }, { route1, route2 }, }
return matched_values, true
return matched_values, true, matched_n
end
return nil
end
Expand Down

0 comments on commit 4bb8847

Please sign in to comment.