Skip to content

Commit d89b485

Browse files
authored
feat: refactor with lua-resty-expr (#77)
1 parent 99f4049 commit d89b485

File tree

4 files changed

+33
-118
lines changed

4 files changed

+33
-118
lines changed

README.md

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
- [Full path match](#full-path-match)
1010
- [Prefix match](#prefix-match)
1111
- [Parameters in path](#parameters-in-path)
12-
- [Operator List](#operator-list)
1312
- [match](#match)
1413
- [dispatch](#dispatch)
1514
- [Install](#install)
@@ -99,7 +98,7 @@ The attributes of each element may contain these:
9998
|hosts |option |A list of client request host, not only supports normal domain name, but also supports wildcard name.|{"foo.com", "*.bar.com"}|
10099
|remote_addrs|option |A list of client remote address(IPv4 and IPv6), and we can use CIDR format, eg `192.168.1.0/24`.|{"127.0.0.1", "192.0.0.0/8", "::1", "fe80::/32"}|
101100
|methods |option |A list of method name. Here is full valid method list: "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT" and "TRACE".|{"GET", "POST"}|
102-
|vars |option |A list of `{var, operator, val}`. For example: {{var, operator, val}, {var, operator, val}, ...}, `{"arg_name", "==", "json"}` means the value of argument `name` expect to `json`. Here is the full [Operator List](#operator-list).|{{"arg_name", "==", "json"}, {"arg_age", ">", 18}}|
101+
|vars |option |A DSL to evaluate with the given `opts.vars` or `ngx.var`. See https://github.com/api7/lua-resty-expr#new |{{"arg_name", "==", "json"}, {"arg_age", ">", 18}}|
103102
|filter_fun |option |User defined filter function, We can use it to achieve matching logic for special scenes. `radixtree` will pass `vars` and other arguments when matching route.|function(vars) return vars["arg_name"] == "json" end|
104103
|priority |option |Routing priority, default is 0.|priority = 100|
105104
|metadata |option |Will return this field if using `rx:match` to match route.||
@@ -162,20 +161,6 @@ local rx = radix.new({
162161
})
163162
```
164163

165-
#### Operator List
166-
167-
|operator|description|example|
168-
|--------|-----------|-------|
169-
|== |equal |{"arg_name", "==", "json"}|
170-
|~= |not equal |{"arg_name", "~=", "json"}|
171-
|> |greater than|{"arg_age", ">", 24}|
172-
|< |less than |{"arg_age", "<", 24}|
173-
|~~ |Regular match|{"arg_name", "~~", "[a-z]+"}|
174-
|in |find in array|{"arg_name", "in", {"1","2"}}|
175-
|has |left value array has value in the right |{"graphql_root_fields", "has", "repo"}|
176-
177-
[Back to TOC](#table-of-contents)
178-
179164
### match
180165

181166
`syntax: metadata = rx:match(path, opts)`

lib/resty/radixtree.lua

Lines changed: 27 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ local ipmatcher = require("resty.ipmatcher")
2222
local base = require("resty.core.base")
2323
local clone_tab = require("table.clone")
2424
local lrucache = require("resty.lrucache")
25+
local expr = require("resty.expr.v1")
2526
local bit = require("bit")
2627
local ngx = ngx
2728
local table = table
@@ -163,6 +164,7 @@ end
163164

164165
local ngx_log = ngx.log
165166
local ngx_INFO = ngx.INFO
167+
local ngx_ERR = ngx.ERR
166168
local function log_info(...)
167169
if cur_level and ngx_INFO > cur_level then
168170
return
@@ -171,6 +173,13 @@ local function log_info(...)
171173
return ngx_log(ngx_INFO, ...)
172174
end
173175

176+
local function log_err(...)
177+
if cur_level and ngx_ERR > cur_level then
178+
return
179+
end
180+
181+
return ngx_log(ngx_ERR, ...)
182+
end
174183

175184
local mt = { __index = _M, __gc = gc_free }
176185

@@ -256,12 +265,6 @@ function pre_insert_route(self, path, route)
256265
error("missing argument metadata or handler", 2)
257266
end
258267

259-
if route.vars then
260-
if type(route.vars) ~= "table" then
261-
error("invalid argument vars", 2)
262-
end
263-
end
264-
265268
local method = route.methods
266269
local bit_methods
267270
if type(method) ~= "table" then
@@ -276,6 +279,18 @@ function pre_insert_route(self, path, route)
276279

277280
clear_tab(route_opts)
278281

282+
if route.vars then
283+
if type(route.vars) ~= "table" then
284+
error("invalid argument vars", 2)
285+
end
286+
287+
local route_expr, err = expr.new(route.vars)
288+
if not route_expr then
289+
error("failed to handle expression: " .. err, 2)
290+
end
291+
route_opts.vars = route_expr
292+
end
293+
279294
local hosts = route.hosts
280295
if type(hosts) == "table" and #hosts > 0 then
281296
route_opts.hosts = {}
@@ -330,7 +345,6 @@ function pre_insert_route(self, path, route)
330345
route_opts.metadata = route.metadata
331346
route_opts.handler = route.handler
332347
route_opts.method = bit_methods
333-
route_opts.vars = route.vars
334348
route_opts.filter_fun = route.filter_fun
335349
route_opts.priority = route.priority or 0
336350

@@ -485,86 +499,6 @@ local function compare_param(req_path, route, opts)
485499
return true
486500
end
487501

488-
local function in_array(l_v, r_v)
489-
if type(r_v) == "table" then
490-
for _,v in ipairs(r_v) do
491-
if v == l_v then
492-
return true
493-
end
494-
end
495-
end
496-
return false
497-
end
498-
499-
local function has_element(l_v, r_v)
500-
if type(l_v) == "table" then
501-
for _, v in ipairs(l_v) do
502-
if v == r_v then
503-
return true
504-
end
505-
end
506-
507-
return false
508-
end
509-
510-
return false
511-
end
512-
513-
local compare_funcs = {
514-
["=="] = function (l_v, r_v)
515-
if type(r_v) == "number" then
516-
l_v = tonumber(l_v)
517-
if not l_v then
518-
return false
519-
end
520-
end
521-
return l_v == r_v
522-
end,
523-
["~="] = function (l_v, r_v)
524-
return l_v ~= r_v
525-
end,
526-
[">"] = function (l_v, r_v)
527-
l_v = tonumber(l_v)
528-
r_v = tonumber(r_v)
529-
if not l_v or not r_v then
530-
return false
531-
end
532-
return l_v > r_v
533-
end,
534-
["<"] = function (l_v, r_v)
535-
l_v = tonumber(l_v)
536-
r_v = tonumber(r_v)
537-
if not l_v or not r_v then
538-
return false
539-
end
540-
return l_v < r_v
541-
end,
542-
["~~"] = function (l_v, r_v)
543-
local from = re_find(l_v, r_v, "jo")
544-
if from then
545-
return true
546-
end
547-
return false
548-
end,
549-
["IN"] = in_array,
550-
["in"] = in_array,
551-
["has"] = has_element,
552-
}
553-
554-
555-
local function compare_val(l_v, op, r_v, opts)
556-
if r_v == ngx_null then
557-
r_v = nil
558-
end
559-
560-
local com_fun = compare_funcs[op or "=="]
561-
if not com_fun then
562-
return false
563-
end
564-
return com_fun(l_v, r_v, opts)
565-
end
566-
567-
568502
local function match_route_opts(route, opts, args)
569503
local method = opts.method
570504
local opts_matched_exists = (opts.matched ~= nil)
@@ -621,18 +555,13 @@ local function match_route_opts(route, opts, args)
621555
end
622556

623557
if route.vars then
624-
local vars = opts.vars or ngx_var
625-
if type(vars) ~= "table" then
626-
return false
627-
end
628-
629-
for _, route_var in ipairs(route.vars) do
630-
local l_v, op, r_v = route_var[1], route_var[2], route_var[3]
631-
l_v = vars[l_v]
632-
633-
if not compare_val(l_v, op, r_v, opts) then
634-
return false
558+
local ok, err = route.vars:eval(opts.vars, opts)
559+
if not ok then
560+
if ok == nil then
561+
log_err("failed to eval expression: ", err)
635562
end
563+
564+
return false
636565
end
637566
end
638567

rockspec/lua-resty-radixtree-master-0-0.rockspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ description = {
1414

1515
dependencies = {
1616
"lua-resty-ipmatcher",
17+
"lua-resty-expr = 1.0.0",
1718
}
1819

1920
build = {

t/vars.t

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ nil
319319
location /t {
320320
content_by_lua_block {
321321
local radix = require("resty.radixtree")
322-
local rx = radix.new({
322+
local ok, err = pcall(radix.new, {
323323
{
324324
paths = "/aa",
325325
metadata = "metadata /aa",
@@ -329,15 +329,15 @@ nil
329329
}
330330
})
331331

332-
ngx.say(rx:match("/aa", {vars = ngx.var}))
332+
ngx.say(ok, " ", err)
333333
}
334334
}
335335
--- request
336336
GET /t?k=9
337337
--- no_error_log
338338
[error]
339-
--- response_body
340-
nil
339+
--- response_body_like eval
340+
qr/failed to handle expression: invalid operator 'invalid'/
341341

342342

343343

0 commit comments

Comments
 (0)