diff --git a/dbal/cpp/src/entities/package/batch_create_packages.hpp b/dbal/cpp/src/entities/package/batch_create_packages.hpp new file mode 100644 index 000000000..dd74c751b --- /dev/null +++ b/dbal/cpp/src/entities/package/batch_create_packages.hpp @@ -0,0 +1,46 @@ +/** + * @file batch_create_packages.hpp + * @brief Batch create packages operation + */ + +#pragma once + +#include "dbal/types.hpp" +#include "dbal/errors.hpp" +#include "../store/in_memory_store.hpp" +#include "create_package.hpp" +#include "../validation/package_validation.hpp" + +namespace dbal { +namespace entities { + +/** + * @brief Batch create multiple packages + */ +inline Result batchCreatePackages(InMemoryStore& store, const std::vector& inputs) { + if (inputs.empty()) { + return Result(0); + } + + std::vector 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(static_cast(created_ids.size())); +} + +} // namespace entities +} // namespace dbal diff --git a/dbal/cpp/src/entities/package/batch_delete_packages.hpp b/dbal/cpp/src/entities/package/batch_delete_packages.hpp new file mode 100644 index 000000000..b8c7f3ae3 --- /dev/null +++ b/dbal/cpp/src/entities/package/batch_delete_packages.hpp @@ -0,0 +1,37 @@ +/** + * @file batch_delete_packages.hpp + * @brief Batch delete packages operation + */ + +#pragma once + +#include "dbal/types.hpp" +#include "dbal/errors.hpp" +#include "../store/in_memory_store.hpp" +#include "delete_package.hpp" + +namespace dbal { +namespace entities { + +/** + * @brief Batch delete multiple packages + */ +inline Result batchDeletePackages(InMemoryStore& store, const std::vector& ids) { + if (ids.empty()) { + return Result(0); + } + + int deleted = 0; + for (const auto& id : ids) { + auto result = deletePackage(store, id); + if (result.isError()) { + return result.error(); + } + deleted++; + } + + return Result(deleted); +} + +} // namespace entities +} // namespace dbal diff --git a/dbal/cpp/src/entities/package/batch_update_packages.hpp b/dbal/cpp/src/entities/package/batch_update_packages.hpp new file mode 100644 index 000000000..e935dab71 --- /dev/null +++ b/dbal/cpp/src/entities/package/batch_update_packages.hpp @@ -0,0 +1,37 @@ +/** + * @file batch_update_packages.hpp + * @brief Batch update packages operation + */ + +#pragma once + +#include "dbal/types.hpp" +#include "dbal/errors.hpp" +#include "../store/in_memory_store.hpp" +#include "update_package.hpp" + +namespace dbal { +namespace entities { + +/** + * @brief Batch update multiple packages + */ +inline Result batchUpdatePackages(InMemoryStore& store, const std::vector& updates) { + if (updates.empty()) { + return Result(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(updated); +} + +} // namespace entities +} // namespace dbal diff --git a/dbal/cpp/src/entities/package_ops.hpp b/dbal/cpp/src/entities/package_ops.hpp new file mode 100644 index 000000000..6aeb731f3 --- /dev/null +++ b/dbal/cpp/src/entities/package_ops.hpp @@ -0,0 +1,15 @@ +/** + * @file package_operations.hpp + * @brief Package operations - wrapper including all micro-functions + */ + +#pragma once + +#include "package/create_package.hpp" +#include "package/get_package.hpp" +#include "package/update_package.hpp" +#include "package/delete_package.hpp" +#include "package/list_packages.hpp" +#include "package/batch_create_packages.hpp" +#include "package/batch_update_packages.hpp" +#include "package/batch_delete_packages.hpp" diff --git a/dbal/ts/src/core/entities/package/update-package.ts b/dbal/ts/src/core/entities/package/update-package.ts index 97c99cdce..29f94bfd8 100644 --- a/dbal/ts/src/core/entities/package/update-package.ts +++ b/dbal/ts/src/core/entities/package/update-package.ts @@ -2,45 +2,76 @@ * @file update-package.ts * @description Update package operation */ -import type { Package, UpdatePackageInput, Result } from '../types'; -import type { InMemoryStore } from '../store/in-memory-store'; -import { validateVersion } from '../validation/package-validation'; +import type { Package, Result, UpdatePackageInput } from '../../types' +import type { InMemoryStore } from '../../store/in-memory-store' +import { validateId } from '../../validation/validate-id' +import { validatePackageUpdate } from '../../validation/validate-package-update' /** * Update an existing package */ -export async function updatePackage( +export const updatePackage = async ( store: InMemoryStore, id: string, input: UpdatePackageInput -): Promise> { - if (!id) { - return { success: false, error: { code: 'VALIDATION_ERROR', message: 'ID required' } }; +): Promise> => { + 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}` } } } - if (input.name !== undefined) { - if (!input.name || input.name.length > 100) { - return { success: false, error: { code: 'VALIDATION_ERROR', message: 'Invalid name' } }; + const validationErrors = validatePackageUpdate(input) + if (validationErrors.length > 0) { + return { success: false, error: { code: 'VALIDATION_ERROR', message: validationErrors[0] } } + } + + const nextName = input.name ?? pkg.name + const nextVersion = input.version ?? pkg.version + const currentKey = `${pkg.name}@${pkg.version}` + const nextKey = `${nextName}@${nextVersion}` + + if (nextKey !== currentKey) { + const existingId = store.packageKeys.get(nextKey) + if (existingId && existingId !== id) { + return { success: false, error: { code: 'CONFLICT', message: 'Package name+version already exists' } } } - pkg.name = input.name; + store.packageKeys.delete(currentKey) + store.packageKeys.set(nextKey, id) } - if (input.version !== undefined) { - if (!validateVersion(input.version)) { - return { success: false, error: { code: 'VALIDATION_ERROR', message: 'Invalid version' } }; - } - pkg.version = input.version; + pkg.name = nextName + pkg.version = nextVersion + + if (input.description !== undefined) { + pkg.description = input.description } - if (input.description !== undefined) pkg.description = input.description; - if (input.metadata !== undefined) pkg.metadata = input.metadata; - if (input.isActive !== undefined) pkg.isActive = input.isActive; + if (input.author !== undefined) { + pkg.author = input.author + } - pkg.updatedAt = new Date(); - return { success: true, data: pkg }; + if (input.manifest !== undefined) { + pkg.manifest = input.manifest + } + + if (input.isInstalled !== undefined) { + pkg.isInstalled = input.isInstalled + } + + if (input.installedAt !== undefined) { + pkg.installedAt = input.installedAt + } + + if (input.installedBy !== undefined) { + pkg.installedBy = input.installedBy + } + + pkg.updatedAt = new Date() + + return { success: true, data: pkg } }