Skip to content

Commit

Permalink
feat: add support for keymatch5 function (#159)
Browse files Browse the repository at this point in the history
* feat: add KeyMatch5 matcher

Fixes #153

* test: add test for KeyMatch5
  • Loading branch information
mikyll authored Nov 22, 2024
1 parent eb6c211 commit 399e18b
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/model/FunctionMap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ local FunctionMap = {
["keyMatch4"] = BuiltInFunctions.keyMatch4Func,
["regexMatch"] = BuiltInFunctions.regexMatchFunc,
["IPMatch"] = BuiltInFunctions.IPMatchFunc,
["globMatch"] = BuiltInFunctions.globMatch
["globMatch"] = BuiltInFunctions.globMatch,
["keyMatch5"] = BuiltInFunctions.keyMatch4Func,
}

-- FunctionMap provides a set of built in functions
Expand Down
26 changes: 25 additions & 1 deletion src/util/BuiltInFunctions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ local BuiltInFunctions = {}

function BuiltInFunctions.validateVariadicArgs(expectedLen, args)
if #args ~= expectedLen then
return error("Expected"..expectedLen.." arguments, but got "..#args)
return error("Expected "..expectedLen.." arguments, but got "..#args)
end
for i=1,expectedLen do
if type(args[i])~="string" then
Expand Down Expand Up @@ -247,6 +247,30 @@ function BuiltInFunctions.globMatch(key1, key2)
end
end

-- Wrapper for keyMatch5
function BuiltInFunctions.keyMatch5Func(args)
BuiltInFunctions.validateVariadicArgs(2, args)
return BuiltInFunctions.keyMatch5(args[1], args[2])
end

-- KeyMatch5 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *
-- For example,
-- - "/foo/bar?status=1&type=2" matches "/foo/bar"
-- - "/parent/child1" and "/parent/child1" matches "/parent/*"
-- - "/parent/child1?status=1" matches "/parent/*"
function BuiltInFunctions.keyMatch5(key1, key2)
local i = string.find(key1, "?", 1, true)

if i then
key1 = string.sub(key1, 1, i - 1)
end

key2 = string.gsub(key2, "/%*", "/.*")
key2 = string.gsub(key2, "%{[^/]+%}", "[^/]+")

return string.match(key1, "^" .. key2 .. "$") ~= nil
end

-- GenerateGFunction is the factory method of the g(_, _) function.
function BuiltInFunctions.generateGFunction(rm)
local function f(args)
Expand Down
42 changes: 42 additions & 0 deletions tests/util/built_in_functions_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,46 @@ describe("BuiltInFunctions tests", function ()
assert.is.False(BuiltInFunctions.IPMatch("192.168.2.124", "192.168.2.123"))
assert.is.False(BuiltInFunctions.IPMatch("192.166.2.123", "192.168.2.123"))
end)

it("keyMatch5 tests", function ()
assert.has_error(function () BuiltInFunctions.keyMatch5Func({"/foo"}) end, "Expected 2 arguments, but got 1")
assert.has_error(function () BuiltInFunctions.keyMatch5Func({"/foo/create/123", "/foo/*", "/foo/update/123"}) end, "Expected 2 arguments, but got 3")
assert.has_error(function () BuiltInFunctions.keyMatch5Func({"/parent/123", true}) end, "Argument must be a string")

assert.is.True(BuiltInFunctions.keyMatch5("/parent/child?status=1&type=2", "/parent/child"))
assert.is.False(BuiltInFunctions.keyMatch5("/parent?status=1&type=2", "/parent/child"))

assert.is.True(BuiltInFunctions.keyMatch5("/parent/child/?status=1&type=2", "/parent/child/"))
assert.is.False(BuiltInFunctions.keyMatch5("/parent/child/?status=1&type=2", "/parent/child"))
assert.is.False(BuiltInFunctions.keyMatch5("/parent/child?status=1&type=2", "/parent/child/"))

assert.is.True(BuiltInFunctions.keyMatch5("/foo", "/foo"))
assert.is.True(BuiltInFunctions.keyMatch5("/foo", "/foo*"))
assert.is.False(BuiltInFunctions.keyMatch5("/foo", "/foo/*"))
assert.is.False(BuiltInFunctions.keyMatch5("/foo/bar", "/foo"))
assert.is.False(BuiltInFunctions.keyMatch5("/foo/bar", "/foo*"))
assert.is.True(BuiltInFunctions.keyMatch5("/foo/bar", "/foo/*"))
assert.is.False(BuiltInFunctions.keyMatch5("/foobar", "/foo"))
assert.is.False(BuiltInFunctions.keyMatch5("/foobar", "/foo*"))
assert.is.False(BuiltInFunctions.keyMatch5("/foobar", "/foo/*"))

assert.is.False(BuiltInFunctions.keyMatch5("/", "/{resource}"))
assert.is.True(BuiltInFunctions.keyMatch5("/resource1", "/{resource}"))
assert.is.False(BuiltInFunctions.keyMatch5("/myid", "/{id}/using/{resId}"))
assert.is.True(BuiltInFunctions.keyMatch5("/myid/using/myresid", "/{id}/using/{resId}"))

assert.is.False(BuiltInFunctions.keyMatch5("/proxy/myid", "/proxy/{id}/*"))
assert.is.True(BuiltInFunctions.keyMatch5("/proxy/myid/", "/proxy/{id}/*"))
assert.is.True(BuiltInFunctions.keyMatch5("/proxy/myid/res", "/proxy/{id}/*"))
assert.is.True(BuiltInFunctions.keyMatch5("/proxy/myid/res/res2", "/proxy/{id}/*"))
assert.is.True(BuiltInFunctions.keyMatch5("/proxy/myid/res/res2/res3", "/proxy/{id}/*"))
assert.is.False(BuiltInFunctions.keyMatch5("/proxy/", "/proxy/{id}/*"))

assert.is.False(BuiltInFunctions.keyMatch5("/proxy/myid?status=1&type=2", "/proxy/{id}/*"))
assert.is.True(BuiltInFunctions.keyMatch5("/proxy/myid/", "/proxy/{id}/*"))
assert.is.True(BuiltInFunctions.keyMatch5("/proxy/myid/res?status=1&type=2", "/proxy/{id}/*"))
assert.is.True(BuiltInFunctions.keyMatch5("/proxy/myid/res/res2?status=1&type=2", "/proxy/{id}/*"))
assert.is.True(BuiltInFunctions.keyMatch5("/proxy/myid/res/res2/res3?status=1&type=2", "/proxy/{id}/*"))
assert.is.False(BuiltInFunctions.keyMatch5("/proxy/", "/proxy/{id}/*"))
end)
end)

0 comments on commit 399e18b

Please sign in to comment.