This is an automated email from the ASF dual-hosted git repository.

hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-cpp.git


The following commit(s) were added to refs/heads/master by this push:
     new 8acc470  feat: add keyMatch5 built-in function
8acc470 is described below

commit 8acc4702857dbf28c2a8f54eb3079f859cbad2e5
Author: Yang Luo <[email protected]>
AuthorDate: Sat Oct 31 09:10:03 2026 +0800

    feat: add keyMatch5 built-in function
---
 casbin/model/evaluator.cpp               |  1 +
 casbin/util/built_in_functions.cpp       |  7 +++++
 include/casbin/model/exprtk_config.h     |  4 +++
 include/casbin/util/built_in_functions.h |  5 ++++
 tests/built_in_functions_test.cpp        | 47 ++++++++++++++++++++++++++++++++
 5 files changed, 64 insertions(+)

diff --git a/casbin/model/evaluator.cpp b/casbin/model/evaluator.cpp
index 2052ecd..69dbe2d 100644
--- a/casbin/model/evaluator.cpp
+++ b/casbin/model/evaluator.cpp
@@ -83,6 +83,7 @@ void ExprtkEvaluator::LoadFunctions() {
     AddFunction("keyMatch2", 
ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch2, 2));
     AddFunction("keyMatch3", 
ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch3, 2));
     AddFunction("keyMatch4", 
ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch4, 2));
+    AddFunction("keyMatch5", 
ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch5, 2));
     AddFunction("regexMatch", 
ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::RegexMatch, 2));
     AddFunction("ipMatch", 
ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::IpMatch, 2));
     AddFunction("keyGet", 
ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyGet, 2));
diff --git a/casbin/util/built_in_functions.cpp 
b/casbin/util/built_in_functions.cpp
index 6ca4cb6..c844b5d 100644
--- a/casbin/util/built_in_functions.cpp
+++ b/casbin/util/built_in_functions.cpp
@@ -204,6 +204,13 @@ bool KeyMatch4(const std::string& key1, const std::string& 
key2) {
     return true;
 }
 
+// KeyMatch5 determines whether key1 matches the pattern of key2 (similar to 
RESTful path), key2 can contain a *.
+// The query string in key1 is ignored.
+// For example, "/foo/bar?status=1&type=2" matches "/foo/bar", 
"/parent/child1" matches "/parent/*" and "/parent/{id}"
+bool KeyMatch5(const std::string& key1, const std::string& key2) {
+    return KeyMatch3(key1.substr(0, key1.find('?')), key2);
+}
+
 // RegexMatch determines whether key1 matches the pattern of key2 in regular 
expression.
 bool RegexMatch(const std::string& key1, const std::string& key2) {
     std::regex regex_s(key2);
diff --git a/include/casbin/model/exprtk_config.h 
b/include/casbin/model/exprtk_config.h
index 9ce6a96..e585049 100644
--- a/include/casbin/model/exprtk_config.h
+++ b/include/casbin/model/exprtk_config.h
@@ -234,6 +234,7 @@ enum class ExprtkFunctionType {
     KeyMatch2,
     KeyMatch3,
     KeyMatch4,
+    KeyMatch5,
     RegexMatch,
     IpMatch,
     KeyGet,
@@ -276,6 +277,9 @@ public:
             case ExprtkFunctionType::KeyMatch4:
                 func = std::make_shared<ExprtkMatchFunction>(idenfier, 
KeyMatch4);
                 break;
+            case ExprtkFunctionType::KeyMatch5:
+                func = std::make_shared<ExprtkMatchFunction>(idenfier, 
KeyMatch5);
+                break;
             case ExprtkFunctionType::IpMatch:
                 func = std::make_shared<ExprtkMatchFunction>(idenfier, 
IPMatch);
                 break;
diff --git a/include/casbin/util/built_in_functions.h 
b/include/casbin/util/built_in_functions.h
index abb2d1d..12f53af 100644
--- a/include/casbin/util/built_in_functions.h
+++ b/include/casbin/util/built_in_functions.h
@@ -53,6 +53,11 @@ std::string KeyGet3(const std::string& key1, const 
std::string& key2, const std:
 // But KeyMatch3 will match both.
 bool KeyMatch4(const std::string& key1, const std::string& key2);
 
+// KeyMatch5 determines whether key1 matches the pattern of key2 (similar to 
RESTful path), key2 can contain a *.
+// The query string in key1 is ignored.
+// For example, "/foo/bar?status=1&type=2" matches "/foo/bar", 
"/parent/child1" matches "/parent/*" and "/parent/{id}"
+bool KeyMatch5(const std::string& key1, const std::string& key2);
+
 // RegexMatch determines whether key1 matches the pattern of key2 in regular 
expression.
 bool RegexMatch(const std::string& key1, const std::string& key2);
 
diff --git a/tests/built_in_functions_test.cpp 
b/tests/built_in_functions_test.cpp
index 72bc6d2..b536f2a 100644
--- a/tests/built_in_functions_test.cpp
+++ b/tests/built_in_functions_test.cpp
@@ -282,6 +282,53 @@ TEST(TestBuiltInFunctions, TestKeyMatch4) {
     TestKeyMatch4Fn("/parent/123/child/123", "/parent/{i/d}/child/{i/d}", 
false);
 }
 
+void TestKeyMatch5Fn(std::string key1, std::string key2, bool res) {
+    auto evaluator = casbin::ExprtkEvaluator();
+    auto func = 
casbin::ExprtkFunctionFactory::GetExprtkFunction(casbin::ExprtkFunctionType::KeyMatch5,
 2);
+    evaluator.AddFunction("keyMatch5", func);
+    evaluator.AddIdentifier("key1", key1);
+    evaluator.AddIdentifier("key2", key2);
+    evaluator.Eval("keyMatch5(key1, key2)");
+    bool my_res = evaluator.GetBoolean();
+    EXPECT_EQ(res, my_res);
+}
+
+TEST(TestBuiltInFunctions, TestKeyMatch5) {
+    TestKeyMatch5Fn("/parent/child?status=1&type=2", "/parent/child", true);
+    TestKeyMatch5Fn("/parent?status=1&type=2", "/parent/child", false);
+
+    TestKeyMatch5Fn("/parent/child/?status=1&type=2", "/parent/child/", true);
+    TestKeyMatch5Fn("/parent/child/?status=1&type=2", "/parent/child", false);
+    TestKeyMatch5Fn("/parent/child?status=1&type=2", "/parent/child/", false);
+
+    TestKeyMatch5Fn("/foo", "/foo", true);
+    TestKeyMatch5Fn("/foo", "/foo*", true);
+    TestKeyMatch5Fn("/foo", "/foo/*", false);
+    TestKeyMatch5Fn("/foo/bar", "/foo", false);
+    TestKeyMatch5Fn("/foo/bar", "/foo*", false);
+    TestKeyMatch5Fn("/foo/bar", "/foo/*", true);
+    TestKeyMatch5Fn("/foobar", "/foo", false);
+    TestKeyMatch5Fn("/foobar", "/foo*", false);
+    TestKeyMatch5Fn("/foobar", "/foo/*", false);
+
+    TestKeyMatch5Fn("/", "/{resource}", false);
+    TestKeyMatch5Fn("/resource1", "/{resource}", true);
+    TestKeyMatch5Fn("/myid", "/{id}/using/{resId}", false);
+    TestKeyMatch5Fn("/myid/using/myresid", "/{id}/using/{resId}", true);
+
+    TestKeyMatch5Fn("/proxy/myid", "/proxy/{id}/*", false);
+    TestKeyMatch5Fn("/proxy/myid/", "/proxy/{id}/*", true);
+    TestKeyMatch5Fn("/proxy/myid/res", "/proxy/{id}/*", true);
+    TestKeyMatch5Fn("/proxy/myid/res/res2", "/proxy/{id}/*", true);
+    TestKeyMatch5Fn("/proxy/myid/res/res2/res3", "/proxy/{id}/*", true);
+    TestKeyMatch5Fn("/proxy/", "/proxy/{id}/*", false);
+
+    TestKeyMatch5Fn("/proxy/myid?status=1&type=2", "/proxy/{id}/*", false);
+    TestKeyMatch5Fn("/proxy/myid/res?status=1&type=2", "/proxy/{id}/*", true);
+    TestKeyMatch5Fn("/proxy/myid/res/res2?status=1&type=2", "/proxy/{id}/*", 
true);
+    TestKeyMatch5Fn("/proxy/myid/res/res2/res3?status=1&type=2", 
"/proxy/{id}/*", true);
+}
+
 void TestRegexMatchFn(std::string key1, std::string key2, bool res) {
     auto evaluator = casbin::ExprtkEvaluator();
     auto func = 
casbin::ExprtkFunctionFactory::GetExprtkFunction(casbin::ExprtkFunctionType::RegexMatch,
 2);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to