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-sqlpp11-adapter.git
The following commit(s) were added to refs/heads/master by this push:
new b4f134c fix: make the adapter build against casbin-cpp and sqlpp11's
MySQL connector
b4f134c is described below
commit b4f134cb166817d6b89b6892d63027f62515aba5
Author: Yang Luo <[email protected]>
AuthorDate: Wed Oct 7 10:37:59 2026 +0800
fix: make the adapter build against casbin-cpp and sqlpp11's MySQL connector
---
.github/workflows/ci.yml | 12 ++--
CMakeLists.txt | 7 +-
include/sqlpp11_adapter.h | 22 ++++---
sqlpp11_adapter.cpp | 160 +++++++++++++++++++++++++++-------------------
test.cpp | 30 ++++-----
5 files changed, 131 insertions(+), 100 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6b9e080..817da52 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -66,16 +66,16 @@ jobs:
git clone https://github.com/nlohmann/json.git
cd json
mkdir build && cd build
- cmake .. -DCMAKE_BUILD_TYPE=Release
+ cmake .. -DCMAKE_BUILD_TYPE=Release -DJSON_BuildTests=OFF
sudo cmake --build . --target install
cd ../..
- name: Install Casbin-CPP
run: |
- git clone https://github.com/casbin/casbin-cpp.git
+ git clone https://github.com/apache/casbin-cpp.git
cd casbin-cpp
mkdir build && cd build
- cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/usr/local
+ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/usr/local
-DCASBIN_BUILD_TEST=OFF -DCASBIN_BUILD_BENCHMARK=OFF
-DCASBIN_BUILD_PYTHON_BINDINGS=OFF
sudo cmake --build . --target install
cd ../..
@@ -84,7 +84,7 @@ jobs:
git clone https://github.com/rbock/sqlpp11.git
cd sqlpp11
mkdir build && cd build
- cmake .. -DCMAKE_BUILD_TYPE=Release
+ cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_MYSQL_CONNECTOR=ON
-DBUILD_TESTING=OFF
sudo cmake --build . --target install
cd ../..
@@ -106,6 +106,4 @@ jobs:
- name: Run tests
env:
MYSQL_HOST: 127.0.0.1
- run: |
- cd build
- ./test || echo "Tests require MySQL connection"
+ run: ./build/test
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e0f6245..712cf28 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,6 +23,7 @@ set(CMAKE_CXX_EXTENSIONS OFF)
# Find required packages
find_package(casbin REQUIRED)
+find_package(Sqlpp11 REQUIRED COMPONENTS MySQL)
# Add library target
add_library(sqlpp11_adapter STATIC
@@ -36,7 +37,8 @@ target_include_directories(sqlpp11_adapter
target_link_libraries(sqlpp11_adapter
PUBLIC
- casbin
+ casbin::casbin
+ sqlpp11::mysql
)
# Add test executable
@@ -52,7 +54,8 @@ target_include_directories(test
target_link_libraries(test
PRIVATE
- casbin
+ casbin::casbin
+ sqlpp11::mysql
)
# Installation rules
diff --git a/include/sqlpp11_adapter.h b/include/sqlpp11_adapter.h
index 8e085e4..b160b00 100644
--- a/include/sqlpp11_adapter.h
+++ b/include/sqlpp11_adapter.h
@@ -20,34 +20,36 @@
#include <vector>
#include "casbin/persist/adapter.h"
-#include "casbin/util/util.h"
#include "sqlpp11/mysql/mysql.h"
#include "sqlpp11/sqlpp11.h"
#include "CasbinRule.h"
namespace casbin {
-class Model;
-
class Sqlpp11Adapter : public Adapter {
public:
Sqlpp11Adapter(const std::string& host, const std::string& user,
const std::string& password, const std::string& database,
unsigned int port = 3306);
-
+
void LoadPolicy(const std::shared_ptr<Model>& model) override;
- void SavePolicy(Model& model) override;
-
+ void SavePolicy(const std::shared_ptr<Model>& model) override;
+ void AddPolicy(std::string sec, std::string p_type,
std::vector<std::string> rule) override;
+ void RemovePolicy(std::string sec, std::string p_type,
std::vector<std::string> rule) override;
+ void RemoveFilteredPolicy(std::string sec, std::string p_type, int
field_index, std::vector<std::string> field_values) override;
+ bool IsFiltered() override;
+ bool IsValid() override;
+
void CreateTable();
void DropTable();
private:
- sqlpp::mysql::connection_config config_;
+ std::shared_ptr<sqlpp::mysql::connection_config> config_;
std::shared_ptr<sqlpp::mysql::connection> db_;
std::string table_name_;
-
- template<typename Row>
- void LoadPolicyLine(const Row& row, const std::shared_ptr<Model>& model);
+
+ void InsertRule(const std::string& p_type, const std::vector<std::string>&
rule);
+ void RemoveRules(const std::string& p_type, int field_index, const
std::vector<std::string>& field_values);
};
} // namespace casbin
diff --git a/sqlpp11_adapter.cpp b/sqlpp11_adapter.cpp
index 2a3c0eb..d65b50b 100644
--- a/sqlpp11_adapter.cpp
+++ b/sqlpp11_adapter.cpp
@@ -26,13 +26,16 @@ Sqlpp11Adapter::Sqlpp11Adapter(const std::string& host,
const std::string& user,
const std::string& password, const std::string&
database,
unsigned int port)
: table_name_(kDefaultTableName) {
- config_.host = host;
- config_.user = user;
- config_.password = password;
- config_.database = database;
- config_.port = port;
- config_.debug = false;
-
+ filtered = false;
+
+ config_ = std::make_shared<sqlpp::mysql::connection_config>();
+ config_->host = host;
+ config_->user = user;
+ config_->password = password;
+ config_->database = database;
+ config_->port = port;
+ config_->debug = false;
+
db_ = std::make_shared<sqlpp::mysql::connection>(config_);
}
@@ -40,9 +43,23 @@ void Sqlpp11Adapter::LoadPolicy(const
std::shared_ptr<Model>& model) {
CasbinRuleTable casbin_rule;
try {
- auto result =
(*db_)(sqlpp::select(all_of(casbin_rule)).from(casbin_rule).unconditionally());
- for (const auto& row : result) {
- LoadPolicyLine(row, model);
+ for (const auto& row :
(*db_)(sqlpp::select(all_of(casbin_rule)).from(casbin_rule).unconditionally()))
{
+ std::string line = row.ptype.value();
+ bool done = false;
+ auto append = [&line, &done](const auto& field) {
+ if (done || field.is_null()) {
+ done = true;
+ return;
+ }
+ line += ", " + field.value();
+ };
+ append(row.v0);
+ append(row.v1);
+ append(row.v2);
+ append(row.v3);
+ append(row.v4);
+ append(row.v5);
+ LoadPolicyLine(line, model);
}
} catch (const sqlpp::exception& e) {
std::cerr << "Error loading policy: " << e.what() << std::endl;
@@ -50,66 +67,19 @@ void Sqlpp11Adapter::LoadPolicy(const
std::shared_ptr<Model>& model) {
}
}
-template<typename Row>
-void Sqlpp11Adapter::LoadPolicyLine(const Row& row,
- const std::shared_ptr<Model>& model) {
- std::vector<std::string> tokens;
- tokens.push_back(row.ptype);
-
- if (!row.v0.is_null()) tokens.push_back(row.v0.value());
- if (!row.v1.is_null()) tokens.push_back(row.v1.value());
- if (!row.v2.is_null()) tokens.push_back(row.v2.value());
- if (!row.v3.is_null()) tokens.push_back(row.v3.value());
- if (!row.v4.is_null()) tokens.push_back(row.v4.value());
- if (!row.v5.is_null()) tokens.push_back(row.v5.value());
-
- if (tokens.size() < 2) {
- return; // Need at least ptype and one value
- }
-
- std::string key = tokens[0];
- std::vector<std::string> sec_tokens(tokens.begin() + 1, tokens.end());
-
- if (model->HasSection("p") && model->HasAssertion("p", key)) {
- model->AddPolicy("p", key, sec_tokens);
- } else if (model->HasSection("g") && model->HasAssertion("g", key)) {
- model->AddPolicy("g", key, sec_tokens);
- }
-}
-
-void Sqlpp11Adapter::SavePolicy(Model& model) {
+void Sqlpp11Adapter::SavePolicy(const std::shared_ptr<Model>& model) {
try {
DropTable();
CreateTable();
- CasbinRuleTable casbin_rule;
-
- // Helper lambda to insert a single policy rule
- auto insertRule = [this, &casbin_rule](const std::string& ptype,
- const
std::vector<std::string>& rule) {
- auto insert = sqlpp::insert_into(casbin_rule).set(
- casbin_rule.ptype = ptype,
- casbin_rule.v0 = rule.size() > 0 ? sqlpp::value(rule[0]) :
sqlpp::null,
- casbin_rule.v1 = rule.size() > 1 ? sqlpp::value(rule[1]) :
sqlpp::null,
- casbin_rule.v2 = rule.size() > 2 ? sqlpp::value(rule[2]) :
sqlpp::null,
- casbin_rule.v3 = rule.size() > 3 ? sqlpp::value(rule[3]) :
sqlpp::null,
- casbin_rule.v4 = rule.size() > 4 ? sqlpp::value(rule[4]) :
sqlpp::null,
- casbin_rule.v5 = rule.size() > 5 ? sqlpp::value(rule[5]) :
sqlpp::null
- );
- (*db_)(insert);
- };
-
- // Save policy rules
- for (const auto& [ptype, ast] : model.m["p"].assertion_map) {
- for (const auto& rule : ast->policy) {
- insertRule(ptype, rule);
+ for (const std::string sec : {"p", "g"}) {
+ if (model->m.find(sec) == model->m.end()) {
+ continue;
}
- }
-
- // Save grouping rules
- for (const auto& [ptype, ast] : model.m["g"].assertion_map) {
- for (const auto& rule : ast->policy) {
- insertRule(ptype, rule);
+ for (const auto& [p_type, ast] : model->m[sec].assertion_map) {
+ for (const auto& rule : ast->policy) {
+ InsertRule(p_type, rule);
+ }
}
}
} catch (const sqlpp::exception& e) {
@@ -118,6 +88,64 @@ void Sqlpp11Adapter::SavePolicy(Model& model) {
}
}
+void Sqlpp11Adapter::AddPolicy(std::string sec, std::string p_type,
std::vector<std::string> rule) {
+ InsertRule(p_type, rule);
+}
+
+void Sqlpp11Adapter::RemovePolicy(std::string sec, std::string p_type,
std::vector<std::string> rule) {
+ RemoveRules(p_type, 0, rule);
+}
+
+void Sqlpp11Adapter::RemoveFilteredPolicy(std::string sec, std::string p_type,
int field_index, std::vector<std::string> field_values) {
+ RemoveRules(p_type, field_index, field_values);
+}
+
+bool Sqlpp11Adapter::IsFiltered() {
+ return filtered;
+}
+
+bool Sqlpp11Adapter::IsValid() {
+ return db_ != nullptr;
+}
+
+void Sqlpp11Adapter::InsertRule(const std::string& p_type, const
std::vector<std::string>& rule) {
+ CasbinRuleTable casbin_rule;
+
+ auto field = [&rule](size_t i) {
+ return i < rule.size() ? sqlpp::value_or_null(rule[i]) :
sqlpp::value_or_null<sqlpp::text>(sqlpp::null);
+ };
+
+ (*db_)(sqlpp::insert_into(casbin_rule).set(
+ casbin_rule.ptype = p_type,
+ casbin_rule.v0 = field(0),
+ casbin_rule.v1 = field(1),
+ casbin_rule.v2 = field(2),
+ casbin_rule.v3 = field(3),
+ casbin_rule.v4 = field(4),
+ casbin_rule.v5 = field(5)));
+}
+
+void Sqlpp11Adapter::RemoveRules(const std::string& p_type, int field_index,
const std::vector<std::string>& field_values) {
+ CasbinRuleTable casbin_rule;
+
+ auto remove = sqlpp::dynamic_remove_from(*db_,
casbin_rule).dynamic_where(casbin_rule.ptype == p_type);
+ for (size_t i = 0; i < field_values.size(); i++) {
+ const std::string& value = field_values[i];
+ if (value.empty()) {
+ continue;
+ }
+ switch (field_index + i) {
+ case 0: remove.where.add(casbin_rule.v0 == value); break;
+ case 1: remove.where.add(casbin_rule.v1 == value); break;
+ case 2: remove.where.add(casbin_rule.v2 == value); break;
+ case 3: remove.where.add(casbin_rule.v3 == value); break;
+ case 4: remove.where.add(casbin_rule.v4 == value); break;
+ case 5: remove.where.add(casbin_rule.v5 == value); break;
+ }
+ }
+ (*db_)(remove);
+}
+
void Sqlpp11Adapter::CreateTable() {
try {
db_->execute("CREATE TABLE IF NOT EXISTS " + table_name_ +
@@ -144,4 +172,4 @@ void Sqlpp11Adapter::DropTable() {
}
}
-} // namespace casbin
\ No newline at end of file
+} // namespace casbin
diff --git a/test.cpp b/test.cpp
index 7990a2f..2f7218b 100644
--- a/test.cpp
+++ b/test.cpp
@@ -20,7 +20,7 @@
using namespace casbin;
-void TestBasicOperations() {
+bool TestBasicOperations() {
std::cout << "Testing basic adapter operations..." << std::endl;
try {
@@ -43,13 +43,13 @@ void TestBasicOperations() {
auto enforcer = std::make_shared<Enforcer>("examples/rbac_model.conf",
adapter);
// Add policies
- enforcer->AddPolicy("alice", "data1", "read");
- enforcer->AddPolicy("bob", "data2", "write");
- enforcer->AddPolicy("data2_admin", "data2", "read");
- enforcer->AddPolicy("data2_admin", "data2", "write");
+ enforcer->AddPolicy({"alice", "data1", "read"});
+ enforcer->AddPolicy({"bob", "data2", "write"});
+ enforcer->AddPolicy({"data2_admin", "data2", "read"});
+ enforcer->AddPolicy({"data2_admin", "data2", "write"});
// Add roles
- enforcer->AddGroupingPolicy("alice", "data2_admin");
+ enforcer->AddGroupingPolicy({"alice", "data2_admin"});
// Save policy to database
enforcer->SavePolicy();
@@ -61,11 +61,11 @@ void TestBasicOperations() {
std::cout << "Policy loaded successfully" << std::endl;
// Test enforcement
- bool result1 = enforcer->Enforce("alice", "data1", "read");
- bool result2 = enforcer->Enforce("alice", "data1", "write");
- bool result3 = enforcer->Enforce("alice", "data2", "read");
- bool result4 = enforcer->Enforce("alice", "data2", "write");
- bool result5 = enforcer->Enforce("bob", "data2", "write");
+ bool result1 = enforcer->Enforce({"alice", "data1", "read"});
+ bool result2 = enforcer->Enforce({"alice", "data1", "write"});
+ bool result3 = enforcer->Enforce({"alice", "data2", "read"});
+ bool result4 = enforcer->Enforce({"alice", "data2", "write"});
+ bool result5 = enforcer->Enforce({"bob", "data2", "write"});
std::cout << "Enforcement results:" << std::endl;
std::cout << " alice, data1, read: " << (result1 ? "PASS" : "FAIL")
<< std::endl;
@@ -76,16 +76,16 @@ void TestBasicOperations() {
if (result1 && !result2 && result3 && result4 && result5) {
std::cout << "All tests PASSED!" << std::endl;
- } else {
- std::cerr << "Some tests FAILED!" << std::endl;
+ return true;
}
+ std::cerr << "Some tests FAILED!" << std::endl;
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
+ return false;
}
int main(int argc, char** argv) {
- TestBasicOperations();
- return 0;
+ return TestBasicOperations() ? 0 : 1;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]