mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-25 06:14:59 +00:00
code: dbal,operations,hpp (4 files)
This commit is contained in:
@@ -1,288 +0,0 @@
|
||||
/**
|
||||
* @file package_operations.hpp
|
||||
* @brief Package entity CRUD operations
|
||||
*
|
||||
* Single-responsibility module for Package entity operations.
|
||||
*/
|
||||
#ifndef DBAL_PACKAGE_OPERATIONS_HPP
|
||||
#define DBAL_PACKAGE_OPERATIONS_HPP
|
||||
|
||||
#include "dbal/types.hpp"
|
||||
#include "dbal/errors.hpp"
|
||||
#include "../store/in_memory_store.hpp"
|
||||
#include "../validation/package_validation.hpp"
|
||||
|
||||
namespace dbal {
|
||||
namespace entities {
|
||||
|
||||
/**
|
||||
* Create a new package in the store
|
||||
*/
|
||||
inline Result<Package> createPackage(InMemoryStore& store, const CreatePackageInput& input) {
|
||||
if (!validation::isValidPackageName(input.name)) {
|
||||
return Error::validationError("Package name must be 1-255 characters");
|
||||
}
|
||||
if (!validation::isValidSemver(input.version)) {
|
||||
return Error::validationError("Version must be valid semver");
|
||||
}
|
||||
if (input.author.empty()) {
|
||||
return Error::validationError("author is required");
|
||||
}
|
||||
|
||||
std::string key = validation::packageKey(input.name, input.version);
|
||||
if (store.package_keys.find(key) != store.package_keys.end()) {
|
||||
return Error::conflict("Package name+version already exists: " + key);
|
||||
}
|
||||
|
||||
Package package;
|
||||
package.id = store.generateId("package", ++store.package_counter);
|
||||
package.name = input.name;
|
||||
package.version = input.version;
|
||||
package.description = input.description;
|
||||
package.author = input.author;
|
||||
package.manifest = input.manifest;
|
||||
package.is_installed = input.is_installed;
|
||||
package.installed_at = input.installed_at;
|
||||
package.installed_by = input.installed_by;
|
||||
package.created_at = std::chrono::system_clock::now();
|
||||
package.updated_at = package.created_at;
|
||||
|
||||
store.packages[package.id] = package;
|
||||
store.package_keys[key] = package.id;
|
||||
|
||||
return Result<Package>(package);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a package by ID
|
||||
*/
|
||||
inline Result<Package> getPackage(InMemoryStore& store, const std::string& id) {
|
||||
if (id.empty()) {
|
||||
return Error::validationError("Package ID cannot be empty");
|
||||
}
|
||||
|
||||
auto it = store.packages.find(id);
|
||||
if (it == store.packages.end()) {
|
||||
return Error::notFound("Package not found: " + id);
|
||||
}
|
||||
|
||||
return Result<Package>(it->second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing package
|
||||
*/
|
||||
inline Result<Package> updatePackage(InMemoryStore& store, const std::string& id, const UpdatePackageInput& input) {
|
||||
if (id.empty()) {
|
||||
return Error::validationError("Package ID cannot be empty");
|
||||
}
|
||||
|
||||
auto it = store.packages.find(id);
|
||||
if (it == store.packages.end()) {
|
||||
return Error::notFound("Package not found: " + id);
|
||||
}
|
||||
|
||||
Package& package = it->second;
|
||||
|
||||
std::string next_name = input.name.value_or(package.name);
|
||||
std::string next_version = input.version.value_or(package.version);
|
||||
|
||||
if (!validation::isValidPackageName(next_name)) {
|
||||
return Error::validationError("Package name must be 1-255 characters");
|
||||
}
|
||||
if (!validation::isValidSemver(next_version)) {
|
||||
return Error::validationError("Version must be valid semver");
|
||||
}
|
||||
|
||||
std::string current_key = validation::packageKey(package.name, package.version);
|
||||
std::string next_key = validation::packageKey(next_name, next_version);
|
||||
|
||||
if (next_key != current_key) {
|
||||
auto key_it = store.package_keys.find(next_key);
|
||||
if (key_it != store.package_keys.end() && key_it->second != id) {
|
||||
return Error::conflict("Package name+version already exists: " + next_key);
|
||||
}
|
||||
store.package_keys.erase(current_key);
|
||||
store.package_keys[next_key] = id;
|
||||
}
|
||||
|
||||
package.name = next_name;
|
||||
package.version = next_version;
|
||||
|
||||
if (input.description.has_value()) {
|
||||
package.description = input.description.value();
|
||||
}
|
||||
|
||||
if (input.author.has_value()) {
|
||||
if (input.author.value().empty()) {
|
||||
return Error::validationError("author is required");
|
||||
}
|
||||
package.author = input.author.value();
|
||||
}
|
||||
|
||||
if (input.manifest.has_value()) {
|
||||
package.manifest = input.manifest.value();
|
||||
}
|
||||
|
||||
if (input.is_installed.has_value()) {
|
||||
package.is_installed = input.is_installed.value();
|
||||
}
|
||||
|
||||
if (input.installed_at.has_value()) {
|
||||
package.installed_at = input.installed_at.value();
|
||||
}
|
||||
|
||||
if (input.installed_by.has_value()) {
|
||||
if (input.installed_by.value().empty()) {
|
||||
return Error::validationError("installed_by is required");
|
||||
}
|
||||
package.installed_by = input.installed_by.value();
|
||||
}
|
||||
|
||||
package.updated_at = std::chrono::system_clock::now();
|
||||
|
||||
return Result<Package>(package);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a package by ID
|
||||
*/
|
||||
inline Result<bool> deletePackage(InMemoryStore& store, const std::string& id) {
|
||||
if (id.empty()) {
|
||||
return Error::validationError("Package ID cannot be empty");
|
||||
}
|
||||
|
||||
auto it = store.packages.find(id);
|
||||
if (it == store.packages.end()) {
|
||||
return Error::notFound("Package not found: " + id);
|
||||
}
|
||||
|
||||
store.package_keys.erase(validation::packageKey(it->second.name, it->second.version));
|
||||
store.packages.erase(it);
|
||||
|
||||
return Result<bool>(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* List packages with filtering and pagination
|
||||
*/
|
||||
inline Result<std::vector<Package>> listPackages(InMemoryStore& store, const ListOptions& options) {
|
||||
std::vector<Package> packages;
|
||||
|
||||
for (const auto& [id, package] : store.packages) {
|
||||
bool matches = true;
|
||||
|
||||
if (options.filter.find("name") != options.filter.end()) {
|
||||
if (package.name != options.filter.at("name")) matches = false;
|
||||
}
|
||||
|
||||
if (options.filter.find("version") != options.filter.end()) {
|
||||
if (package.version != options.filter.at("version")) matches = false;
|
||||
}
|
||||
|
||||
if (options.filter.find("author") != options.filter.end()) {
|
||||
if (package.author != options.filter.at("author")) matches = false;
|
||||
}
|
||||
|
||||
if (options.filter.find("is_installed") != options.filter.end()) {
|
||||
bool filter_installed = options.filter.at("is_installed") == "true";
|
||||
if (package.is_installed != filter_installed) matches = false;
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
packages.push_back(package);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.sort.find("name") != options.sort.end()) {
|
||||
std::sort(packages.begin(), packages.end(), [](const Package& a, const Package& b) {
|
||||
return a.name < b.name;
|
||||
});
|
||||
} else if (options.sort.find("created_at") != options.sort.end()) {
|
||||
std::sort(packages.begin(), packages.end(), [](const Package& a, const Package& b) {
|
||||
return a.created_at < b.created_at;
|
||||
});
|
||||
}
|
||||
|
||||
int start = (options.page - 1) * options.limit;
|
||||
int end = std::min(start + options.limit, static_cast<int>(packages.size()));
|
||||
|
||||
if (start < static_cast<int>(packages.size())) {
|
||||
return Result<std::vector<Package>>(std::vector<Package>(packages.begin() + start, packages.begin() + end));
|
||||
}
|
||||
|
||||
return Result<std::vector<Package>>(std::vector<Package>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch create multiple packages
|
||||
*/
|
||||
inline Result<int> batchCreatePackages(InMemoryStore& store, const std::vector<CreatePackageInput>& inputs) {
|
||||
if (inputs.empty()) {
|
||||
return Result<int>(0);
|
||||
}
|
||||
|
||||
std::vector<std::string> created_ids;
|
||||
for (const auto& input : inputs) {
|
||||
auto result = createPackage(store, input);
|
||||
if (result.isError()) {
|
||||
// Rollback on error
|
||||
for (const auto& id : created_ids) {
|
||||
auto it = store.packages.find(id);
|
||||
if (it != store.packages.end()) {
|
||||
store.package_keys.erase(validation::packageKey(it->second.name, it->second.version));
|
||||
store.packages.erase(it);
|
||||
}
|
||||
}
|
||||
return result.error();
|
||||
}
|
||||
created_ids.push_back(result.value().id);
|
||||
}
|
||||
|
||||
return Result<int>(static_cast<int>(created_ids.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch update multiple packages
|
||||
*/
|
||||
inline Result<int> batchUpdatePackages(InMemoryStore& store, const std::vector<UpdatePackageBatchItem>& updates) {
|
||||
if (updates.empty()) {
|
||||
return Result<int>(0);
|
||||
}
|
||||
|
||||
int updated = 0;
|
||||
for (const auto& item : updates) {
|
||||
auto result = updatePackage(store, item.id, item.data);
|
||||
if (result.isError()) {
|
||||
return result.error();
|
||||
}
|
||||
updated++;
|
||||
}
|
||||
|
||||
return Result<int>(updated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch delete multiple packages
|
||||
*/
|
||||
inline Result<int> batchDeletePackages(InMemoryStore& store, const std::vector<std::string>& ids) {
|
||||
if (ids.empty()) {
|
||||
return Result<int>(0);
|
||||
}
|
||||
|
||||
int deleted = 0;
|
||||
for (const auto& id : ids) {
|
||||
auto result = deletePackage(store, id);
|
||||
if (result.isError()) {
|
||||
return result.error();
|
||||
}
|
||||
deleted++;
|
||||
}
|
||||
|
||||
return Result<int>(deleted);
|
||||
}
|
||||
|
||||
} // namespace entities
|
||||
} // namespace dbal
|
||||
|
||||
#endif
|
||||
@@ -1,221 +0,0 @@
|
||||
/**
|
||||
* @file page_operations.hpp
|
||||
* @brief PageView entity CRUD operations
|
||||
*
|
||||
* Single-responsibility module for PageView entity operations.
|
||||
*/
|
||||
#ifndef DBAL_PAGE_OPERATIONS_HPP
|
||||
#define DBAL_PAGE_OPERATIONS_HPP
|
||||
|
||||
#include "dbal/types.hpp"
|
||||
#include "dbal/errors.hpp"
|
||||
#include "../store/in_memory_store.hpp"
|
||||
#include "../validation/page_validation.hpp"
|
||||
|
||||
namespace dbal {
|
||||
namespace entities {
|
||||
|
||||
/**
|
||||
* Create a new page in the store
|
||||
*/
|
||||
inline Result<PageView> createPage(InMemoryStore& store, const CreatePageInput& input) {
|
||||
// Validation
|
||||
if (!validation::isValidSlug(input.slug)) {
|
||||
return Error::validationError("Invalid slug format (lowercase, alphanumeric, hyphens only)");
|
||||
}
|
||||
if (input.title.empty() || input.title.length() > 200) {
|
||||
return Error::validationError("Title must be between 1 and 200 characters");
|
||||
}
|
||||
if (input.level < 0 || input.level > 5) {
|
||||
return Error::validationError("Level must be between 0 and 5");
|
||||
}
|
||||
|
||||
// Check for duplicate slug
|
||||
if (store.page_slugs.find(input.slug) != store.page_slugs.end()) {
|
||||
return Error::conflict("Page with slug already exists: " + input.slug);
|
||||
}
|
||||
|
||||
// Create page
|
||||
PageView page;
|
||||
page.id = store.generateId("page", ++store.page_counter);
|
||||
page.slug = input.slug;
|
||||
page.title = input.title;
|
||||
page.description = input.description;
|
||||
page.level = input.level;
|
||||
page.layout = input.layout;
|
||||
page.is_active = input.is_active;
|
||||
page.created_at = std::chrono::system_clock::now();
|
||||
page.updated_at = page.created_at;
|
||||
|
||||
store.pages[page.id] = page;
|
||||
store.page_slugs[page.slug] = page.id;
|
||||
|
||||
return Result<PageView>(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a page by ID
|
||||
*/
|
||||
inline Result<PageView> getPage(InMemoryStore& store, const std::string& id) {
|
||||
if (id.empty()) {
|
||||
return Error::validationError("Page ID cannot be empty");
|
||||
}
|
||||
|
||||
auto it = store.pages.find(id);
|
||||
if (it == store.pages.end()) {
|
||||
return Error::notFound("Page not found: " + id);
|
||||
}
|
||||
|
||||
return Result<PageView>(it->second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a page by slug
|
||||
*/
|
||||
inline Result<PageView> getPageBySlug(InMemoryStore& store, const std::string& slug) {
|
||||
if (slug.empty()) {
|
||||
return Error::validationError("Slug cannot be empty");
|
||||
}
|
||||
|
||||
auto it = store.page_slugs.find(slug);
|
||||
if (it == store.page_slugs.end()) {
|
||||
return Error::notFound("Page not found with slug: " + slug);
|
||||
}
|
||||
|
||||
return getPage(store, it->second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing page
|
||||
*/
|
||||
inline Result<PageView> updatePage(InMemoryStore& store, const std::string& id, const UpdatePageInput& input) {
|
||||
if (id.empty()) {
|
||||
return Error::validationError("Page ID cannot be empty");
|
||||
}
|
||||
|
||||
auto it = store.pages.find(id);
|
||||
if (it == store.pages.end()) {
|
||||
return Error::notFound("Page not found: " + id);
|
||||
}
|
||||
|
||||
PageView& page = it->second;
|
||||
std::string old_slug = page.slug;
|
||||
|
||||
// Validate and update fields
|
||||
if (input.slug.has_value()) {
|
||||
if (!validation::isValidSlug(input.slug.value())) {
|
||||
return Error::validationError("Invalid slug format");
|
||||
}
|
||||
// Check for slug conflict
|
||||
auto slug_it = store.page_slugs.find(input.slug.value());
|
||||
if (slug_it != store.page_slugs.end() && slug_it->second != id) {
|
||||
return Error::conflict("Slug already exists: " + input.slug.value());
|
||||
}
|
||||
// Update slug mapping
|
||||
store.page_slugs.erase(old_slug);
|
||||
store.page_slugs[input.slug.value()] = id;
|
||||
page.slug = input.slug.value();
|
||||
}
|
||||
|
||||
if (input.title.has_value()) {
|
||||
if (input.title.value().empty() || input.title.value().length() > 200) {
|
||||
return Error::validationError("Title must be between 1 and 200 characters");
|
||||
}
|
||||
page.title = input.title.value();
|
||||
}
|
||||
|
||||
if (input.description.has_value()) {
|
||||
page.description = input.description.value();
|
||||
}
|
||||
|
||||
if (input.level.has_value()) {
|
||||
if (input.level.value() < 0 || input.level.value() > 5) {
|
||||
return Error::validationError("Level must be between 0 and 5");
|
||||
}
|
||||
page.level = input.level.value();
|
||||
}
|
||||
|
||||
if (input.layout.has_value()) {
|
||||
page.layout = input.layout.value();
|
||||
}
|
||||
|
||||
if (input.is_active.has_value()) {
|
||||
page.is_active = input.is_active.value();
|
||||
}
|
||||
|
||||
page.updated_at = std::chrono::system_clock::now();
|
||||
|
||||
return Result<PageView>(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a page by ID
|
||||
*/
|
||||
inline Result<bool> deletePage(InMemoryStore& store, const std::string& id) {
|
||||
if (id.empty()) {
|
||||
return Error::validationError("Page ID cannot be empty");
|
||||
}
|
||||
|
||||
auto it = store.pages.find(id);
|
||||
if (it == store.pages.end()) {
|
||||
return Error::notFound("Page not found: " + id);
|
||||
}
|
||||
|
||||
// Remove slug mapping
|
||||
store.page_slugs.erase(it->second.slug);
|
||||
store.pages.erase(it);
|
||||
|
||||
return Result<bool>(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* List pages with filtering and pagination
|
||||
*/
|
||||
inline Result<std::vector<PageView>> listPages(InMemoryStore& store, const ListOptions& options) {
|
||||
std::vector<PageView> pages;
|
||||
|
||||
for (const auto& [id, page] : store.pages) {
|
||||
// Apply filters
|
||||
bool matches = true;
|
||||
|
||||
if (options.filter.find("is_active") != options.filter.end()) {
|
||||
bool filter_active = options.filter.at("is_active") == "true";
|
||||
if (page.is_active != filter_active) matches = false;
|
||||
}
|
||||
|
||||
if (options.filter.find("level") != options.filter.end()) {
|
||||
int filter_level = std::stoi(options.filter.at("level"));
|
||||
if (page.level != filter_level) matches = false;
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
pages.push_back(page);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply sorting
|
||||
if (options.sort.find("title") != options.sort.end()) {
|
||||
std::sort(pages.begin(), pages.end(), [](const PageView& a, const PageView& b) {
|
||||
return a.title < b.title;
|
||||
});
|
||||
} else if (options.sort.find("created_at") != options.sort.end()) {
|
||||
std::sort(pages.begin(), pages.end(), [](const PageView& a, const PageView& b) {
|
||||
return a.created_at < b.created_at;
|
||||
});
|
||||
}
|
||||
|
||||
// Apply pagination
|
||||
int start = (options.page - 1) * options.limit;
|
||||
int end = std::min(start + options.limit, static_cast<int>(pages.size()));
|
||||
|
||||
if (start < static_cast<int>(pages.size())) {
|
||||
return Result<std::vector<PageView>>(std::vector<PageView>(pages.begin() + start, pages.begin() + end));
|
||||
}
|
||||
|
||||
return Result<std::vector<PageView>>(std::vector<PageView>());
|
||||
}
|
||||
|
||||
} // namespace entities
|
||||
} // namespace dbal
|
||||
|
||||
#endif
|
||||
@@ -1,245 +0,0 @@
|
||||
/**
|
||||
* @file user_operations.hpp
|
||||
* @brief User entity CRUD operations
|
||||
*
|
||||
* Single-responsibility module for User entity operations.
|
||||
* Follows the small-function-file pattern from the Next.js frontend.
|
||||
*/
|
||||
#ifndef DBAL_USER_OPERATIONS_HPP
|
||||
#define DBAL_USER_OPERATIONS_HPP
|
||||
|
||||
#include "dbal/types.hpp"
|
||||
#include "dbal/errors.hpp"
|
||||
#include "../store/in_memory_store.hpp"
|
||||
#include "../validation/user_validation.hpp"
|
||||
|
||||
namespace dbal {
|
||||
namespace entities {
|
||||
|
||||
/**
|
||||
* Create a new user in the store
|
||||
*/
|
||||
inline Result<User> createUser(InMemoryStore& store, const CreateUserInput& input) {
|
||||
// Validation
|
||||
if (!validation::isValidUsername(input.username)) {
|
||||
return Error::validationError("Invalid username format (alphanumeric, underscore, hyphen only)");
|
||||
}
|
||||
if (!validation::isValidEmail(input.email)) {
|
||||
return Error::validationError("Invalid email format");
|
||||
}
|
||||
|
||||
// Check for duplicate username
|
||||
for (const auto& [id, user] : store.users) {
|
||||
if (user.username == input.username) {
|
||||
return Error::conflict("Username already exists: " + input.username);
|
||||
}
|
||||
if (user.email == input.email) {
|
||||
return Error::conflict("Email already exists: " + input.email);
|
||||
}
|
||||
}
|
||||
|
||||
// Create user
|
||||
User user;
|
||||
user.id = store.generateId("user", ++store.user_counter);
|
||||
user.username = input.username;
|
||||
user.email = input.email;
|
||||
user.role = input.role;
|
||||
user.created_at = std::chrono::system_clock::now();
|
||||
user.updated_at = user.created_at;
|
||||
|
||||
store.users[user.id] = user;
|
||||
|
||||
return Result<User>(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user by ID
|
||||
*/
|
||||
inline Result<User> getUser(InMemoryStore& store, const std::string& id) {
|
||||
if (id.empty()) {
|
||||
return Error::validationError("User ID cannot be empty");
|
||||
}
|
||||
|
||||
auto it = store.users.find(id);
|
||||
if (it == store.users.end()) {
|
||||
return Error::notFound("User not found: " + id);
|
||||
}
|
||||
|
||||
return Result<User>(it->second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing user
|
||||
*/
|
||||
inline Result<User> updateUser(InMemoryStore& store, const std::string& id, const UpdateUserInput& input) {
|
||||
if (id.empty()) {
|
||||
return Error::validationError("User ID cannot be empty");
|
||||
}
|
||||
|
||||
auto it = store.users.find(id);
|
||||
if (it == store.users.end()) {
|
||||
return Error::notFound("User not found: " + id);
|
||||
}
|
||||
|
||||
User& user = it->second;
|
||||
|
||||
// Validate and check conflicts
|
||||
if (input.username.has_value()) {
|
||||
if (!validation::isValidUsername(input.username.value())) {
|
||||
return Error::validationError("Invalid username format");
|
||||
}
|
||||
// Check for username conflict
|
||||
for (const auto& [uid, u] : store.users) {
|
||||
if (uid != id && u.username == input.username.value()) {
|
||||
return Error::conflict("Username already exists: " + input.username.value());
|
||||
}
|
||||
}
|
||||
user.username = input.username.value();
|
||||
}
|
||||
|
||||
if (input.email.has_value()) {
|
||||
if (!validation::isValidEmail(input.email.value())) {
|
||||
return Error::validationError("Invalid email format");
|
||||
}
|
||||
// Check for email conflict
|
||||
for (const auto& [uid, u] : store.users) {
|
||||
if (uid != id && u.email == input.email.value()) {
|
||||
return Error::conflict("Email already exists: " + input.email.value());
|
||||
}
|
||||
}
|
||||
user.email = input.email.value();
|
||||
}
|
||||
|
||||
if (input.role.has_value()) {
|
||||
user.role = input.role.value();
|
||||
}
|
||||
|
||||
user.updated_at = std::chrono::system_clock::now();
|
||||
|
||||
return Result<User>(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a user by ID
|
||||
*/
|
||||
inline Result<bool> deleteUser(InMemoryStore& store, const std::string& id) {
|
||||
if (id.empty()) {
|
||||
return Error::validationError("User ID cannot be empty");
|
||||
}
|
||||
|
||||
auto it = store.users.find(id);
|
||||
if (it == store.users.end()) {
|
||||
return Error::notFound("User not found: " + id);
|
||||
}
|
||||
|
||||
store.users.erase(it);
|
||||
return Result<bool>(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* List users with filtering and pagination
|
||||
*/
|
||||
inline Result<std::vector<User>> listUsers(InMemoryStore& store, const ListOptions& options) {
|
||||
std::vector<User> users;
|
||||
|
||||
for (const auto& [id, user] : store.users) {
|
||||
// Apply filters if provided
|
||||
bool matches = true;
|
||||
|
||||
if (options.filter.find("role") != options.filter.end()) {
|
||||
std::string role_str = options.filter.at("role");
|
||||
if (role_str == "admin" && user.role != UserRole::Admin) matches = false;
|
||||
if (role_str == "user" && user.role != UserRole::User) matches = false;
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
users.push_back(user);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply sorting
|
||||
if (options.sort.find("username") != options.sort.end()) {
|
||||
std::sort(users.begin(), users.end(), [](const User& a, const User& b) {
|
||||
return a.username < b.username;
|
||||
});
|
||||
}
|
||||
|
||||
// Apply pagination
|
||||
int start = (options.page - 1) * options.limit;
|
||||
int end = std::min(start + options.limit, static_cast<int>(users.size()));
|
||||
|
||||
if (start < static_cast<int>(users.size())) {
|
||||
return Result<std::vector<User>>(std::vector<User>(users.begin() + start, users.begin() + end));
|
||||
}
|
||||
|
||||
return Result<std::vector<User>>(std::vector<User>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch create multiple users
|
||||
*/
|
||||
inline Result<int> batchCreateUsers(InMemoryStore& store, const std::vector<CreateUserInput>& inputs) {
|
||||
if (inputs.empty()) {
|
||||
return Result<int>(0);
|
||||
}
|
||||
|
||||
std::vector<std::string> created_ids;
|
||||
for (const auto& input : inputs) {
|
||||
auto result = createUser(store, input);
|
||||
if (result.isError()) {
|
||||
// Rollback on error
|
||||
for (const auto& id : created_ids) {
|
||||
store.users.erase(id);
|
||||
}
|
||||
return result.error();
|
||||
}
|
||||
created_ids.push_back(result.value().id);
|
||||
}
|
||||
|
||||
return Result<int>(static_cast<int>(created_ids.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch update multiple users
|
||||
*/
|
||||
inline Result<int> batchUpdateUsers(InMemoryStore& store, const std::vector<UpdateUserBatchItem>& updates) {
|
||||
if (updates.empty()) {
|
||||
return Result<int>(0);
|
||||
}
|
||||
|
||||
int updated = 0;
|
||||
for (const auto& item : updates) {
|
||||
auto result = updateUser(store, item.id, item.data);
|
||||
if (result.isError()) {
|
||||
return result.error();
|
||||
}
|
||||
updated++;
|
||||
}
|
||||
|
||||
return Result<int>(updated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch delete multiple users
|
||||
*/
|
||||
inline Result<int> batchDeleteUsers(InMemoryStore& store, const std::vector<std::string>& ids) {
|
||||
if (ids.empty()) {
|
||||
return Result<int>(0);
|
||||
}
|
||||
|
||||
int deleted = 0;
|
||||
for (const auto& id : ids) {
|
||||
auto result = deleteUser(store, id);
|
||||
if (result.isError()) {
|
||||
return result.error();
|
||||
}
|
||||
deleted++;
|
||||
}
|
||||
|
||||
return Result<int>(deleted);
|
||||
}
|
||||
|
||||
} // namespace entities
|
||||
} // namespace dbal
|
||||
|
||||
#endif
|
||||
@@ -2,24 +2,26 @@
|
||||
* @file delete-package.ts
|
||||
* @description Delete package operation
|
||||
*/
|
||||
import type { Result } from '../types';
|
||||
import type { InMemoryStore } from '../store/in-memory-store';
|
||||
import type { Result } from '../../types'
|
||||
import type { InMemoryStore } from '../../store/in-memory-store'
|
||||
import { validateId } from '../../validation/validate-id'
|
||||
|
||||
/**
|
||||
* Delete a package by ID
|
||||
*/
|
||||
export async function deletePackage(store: InMemoryStore, id: string): Promise<Result<boolean>> {
|
||||
if (!id) {
|
||||
return { success: false, error: { code: 'VALIDATION_ERROR', message: 'ID required' } };
|
||||
export const deletePackage = async (store: InMemoryStore, id: string): Promise<Result<boolean>> => {
|
||||
const idErrors = validateId(id)
|
||||
if (idErrors.length > 0) {
|
||||
return { success: false, error: { code: 'VALIDATION_ERROR', message: idErrors[0] } }
|
||||
}
|
||||
|
||||
const pkg = store.packages.get(id);
|
||||
const pkg = store.packages.get(id)
|
||||
if (!pkg) {
|
||||
return { success: false, error: { code: 'NOT_FOUND', message: `Package not found: ${id}` } };
|
||||
return { success: false, error: { code: 'NOT_FOUND', message: `Package not found: ${id}` } }
|
||||
}
|
||||
|
||||
store.packageIds.delete(pkg.packageId);
|
||||
store.packages.delete(id);
|
||||
store.packages.delete(id)
|
||||
store.packageKeys.delete(`${pkg.name}@${pkg.version}`)
|
||||
|
||||
return { success: true, data: true };
|
||||
return { success: true, data: true }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user