Files
metabuilder/dbal/production/CLEAN_ARCHITECTURE.md
2026-03-09 22:30:41 +00:00

6.4 KiB

DBAL Client Clean Architecture

Refactored: 2026-02-07 Pattern: Clean Architecture with Single Responsibility Principle

Architecture Overview

Client (client.cpp)
    ├── ClientConfigManager    - Configuration validation
    ├── AdapterFactory         - Adapter instantiation
    ├── ConnectionValidator    - URL validation
    ├── OperationExecutor      - CRUD operations (future)
    └── MetadataCache          - Entity metadata caching (future)

Helper Classes

1. AdapterFactory

Location: include/dbal/core/adapter_factory.hpp, src/core/adapter_factory.cpp Size: 81 lines (header) + 101 lines (impl) = 182 lines Purpose: Create adapter instances from database URLs

Supported Backends (13 total):

  • SQLite, PostgreSQL, MySQL, MongoDB, Prisma, Supabase
  • Redis, Cassandra, Elasticsearch, SurrealDB
  • DynamoDB, CockroachDB, TiDB

Methods:

  • createFromUrl(database_url) - Main factory method
  • createFromType(adapter_type, connection_string) - Type-based creation
  • extractAdapterType(database_url) - Parse protocol
  • isSupported(adapter_type) - Check if backend supported

2. ConnectionValidator

Location: include/dbal/core/connection_validator.hpp, src/core/connection_validator.cpp Size: 115 lines (header) + 140 lines (impl) = 255 lines Purpose: Validate connection strings for all backends

Features:

  • URL format validation
  • Protocol-specific validation (SQLite, PostgreSQL, MySQL)
  • Regex pattern matching
  • Detailed error messages

Methods:

  • validate(database_url) - Main validation
  • validateSQLite(url) - SQLite-specific
  • validatePostgreSQL(url) - PostgreSQL-specific
  • validateMySQL(url) - MySQL-specific
  • hasValidFormat(url) - Basic format check
  • extractProtocol(url) - Parse protocol

Return Type: ValidationResult with status, error message, adapter type, normalized URL

3. ClientConfigManager

Location: include/dbal/core/client_config.hpp, src/core/client_config.cpp Size: 118 lines (header) + 99 lines (impl) = 217 lines Purpose: Parse and validate client configuration

Configuration Fields:

  • mode - Operation mode (development/production/test)
  • adapter - Adapter type
  • endpoint - Optional endpoint URL
  • database_url - Connection string
  • sandbox_enabled - Sandbox mode flag
  • parameters - Additional connection parameters

Methods:

  • getMode(), getAdapter(), getEndpoint(), getDatabaseUrl()
  • isSandboxEnabled()
  • setParameter(key, value), getParameter(key), hasParameter(key)
  • validate() - Validate entire configuration

4. OperationExecutor

Location: include/dbal/core/operation_executor.hpp, src/core/operation_executor.cpp Size: 94 lines (header) + 15 lines (impl) = 109 lines Purpose: Execute CRUD operations via adapters (future use)

Status: Placeholder implementation Future Work: Implement template specializations for adapter-based CRUD

Template Methods (planned):

  • executeCreate<EntityType, InputType>(entity_name, input)
  • executeRead<EntityType>(entity_name, id)
  • executeUpdate<EntityType, InputType>(entity_name, id, input)
  • executeDelete(entity_name, id)
  • executeList<EntityType>(entity_name, options)

5. MetadataCache

Location: include/dbal/core/metadata_cache.hpp, src/core/metadata_cache.cpp Size: 131 lines (header) + 105 lines (impl) = 236 lines Purpose: Cache entity metadata with TTL support (future use)

Features:

  • Thread-safe read/write operations
  • TTL-based expiration (default: 5 minutes)
  • Statistics tracking (hits/misses)
  • Manual invalidation support

Methods:

  • cacheAvailableEntities(entities), getAvailableEntities()
  • cacheEntitySchema(entity_name, schema), getEntitySchema(entity_name)
  • hasAvailableEntities(), hasEntitySchema(entity_name)
  • invalidateAll(), invalidateSchema(entity_name)
  • getStatistics() - JSON stats with hit rate

Client.cpp Structure

Size: 262 lines (was 247 before refactoring)

Constructor:

Client::Client(const ClientConfig& config) : config_(config) {
    // Validate configuration
    core::ClientConfigManager config_manager(...);
    
    // Create adapter via factory
    adapter_ = core::AdapterFactory::createFromUrl(config.database_url);
}

Entity Operations: All unchanged, still delegate to entities::* functions using getStore()

Build System

CMakeLists.txt updated with 5 new source files in dbal_core library:

  • ${DBAL_SRC_DIR}/core/adapter_factory.cpp
  • ${DBAL_SRC_DIR}/core/connection_validator.cpp
  • ${DBAL_SRC_DIR}/core/client_config.cpp
  • ${DBAL_SRC_DIR}/core/operation_executor.cpp
  • ${DBAL_SRC_DIR}/core/metadata_cache.cpp

Code Metrics

Component Lines Status
AdapterFactory 182 Complete
ConnectionValidator 255 Complete
ClientConfigManager 217 Complete
OperationExecutor 109 🚧 Placeholder
MetadataCache 236 🚧 Placeholder
Total Helpers 999 -
Client.cpp 262 Refactored

All files <150 LOC per implementation

Benefits

  1. Separation of Concerns: Each helper has single responsibility
  2. Extensibility: Easy to add new adapters via factory
  3. Validation: Comprehensive URL and config validation
  4. Caching: Metadata caching for performance (future)
  5. Testability: Each helper can be tested independently
  6. Maintainability: Small files, clear interfaces

Future Work

  1. Implement OperationExecutor template specializations
  2. Integrate MetadataCache with entity schema operations
  3. Migrate entity operations from InMemoryStore to adapter-based
  4. Add connection pooling to adapters
  5. Add performance metrics collection

Usage Example

// Create client with validated config
ClientConfig config;
config.mode = "production";
config.adapter = "postgres";
config.database_url = "postgresql://user:pass@localhost:5432/mydb";
config.sandbox_enabled = false;

// Client constructor now:
// 1. Validates config via ClientConfigManager
// 2. Validates URL via ConnectionValidator
// 3. Creates adapter via AdapterFactory
Client client(config);

// Use client as before
auto user = client.getUser("user_12345678");

Testing

Run tests (requires Conan dependencies):

cd dbal/production/build-config
cmake -S . -B _build -DCMAKE_BUILD_TYPE=Debug
cmake --build _build

Note: Build requires Conan packages (nlohmann_json, yaml-cpp, etc.)