# Database Module New Features This document provides an overview of the new features added to the Database module. ## Table of Contents - [Stored Procedures and Functions](#stored-procedures-and-functions) - [Extended Index Management](#extended-index-management) - [Enhanced Schema Versioning](#enhanced-schema-versioning) - [Usage Examples](#usage-examples) ## Stored Procedures and Functions The Database module now supports defining, executing, and managing stored procedures and functions across different database systems. ### StoredProcedureDefinition The `StoredProcedureDefinition` class provides a fluent interface for defining stored procedures: ```php use App\Framework\Database\StoredProcedure\StoredProcedureDefinition; $procedure = StoredProcedureDefinition::create('get_user_by_id') ->withParameter('user_id', 'INT') ->withBody('SELECT * FROM users WHERE id = user_id') ->returnsType('TABLE'); ``` The definition can then be converted to SQL for different database systems: ```php // Generate MySQL-specific SQL $mysqlSql = $procedure->toSql('mysql'); // Generate PostgreSQL-specific SQL $pgsqlSql = $procedure->toSql('pgsql'); ``` ### StoredProcedureManager The `StoredProcedureManager` class provides methods for managing stored procedures: ```php use App\Framework\Database\StoredProcedure\StoredProcedureManager; // Create a new manager with a database connection $manager = new StoredProcedureManager($connection); // Create a stored procedure $manager->createProcedure($procedure); // Check if a procedure exists if ($manager->procedureExists('get_user_by_id')) { // Execute the procedure with parameters $result = $manager->executeProcedure('get_user_by_id', [42]); // Process the results foreach ($result->fetchAll() as $row) { // ... } } // Execute a stored function $value = $manager->executeFunction('calculate_order_total', [123, true]); // Drop a procedure $manager->dropProcedure('get_user_by_id'); // List all procedures $procedures = $manager->listProcedures(); ``` ## Extended Index Management The Database module now supports advanced index types and features across different database systems. ### AdvancedIndexDefinition The `AdvancedIndexDefinition` class provides a fluent interface for defining advanced indexes: ```php use App\Framework\Database\Schema\Index\AdvancedIndexDefinition; use App\Framework\Database\Schema\Index\AdvancedIndexType; // Create a standard index $index = AdvancedIndexDefinition::create( 'idx_users_email', ['email'], AdvancedIndexType::INDEX ); // Create a partial index (only indexes rows that match a condition) $partialIndex = AdvancedIndexDefinition::partial( 'idx_active_users', ['email'], AdvancedIndexType::INDEX, 'active = true' ); // Create a functional index (indexes the result of a function) $functionalIndex = AdvancedIndexDefinition::functional( 'idx_lower_email', AdvancedIndexType::INDEX, ['LOWER(email)'] ); // Create a PostgreSQL GIN index (for full-text search, JSON, arrays) $ginIndex = AdvancedIndexDefinition::gin( 'idx_document_content', ['content'] ); // Create a PostgreSQL GiST index (for geometric data, ranges) $gistIndex = AdvancedIndexDefinition::gist( 'idx_location_position', ['position'] ); // Create a MySQL BTREE index with options $btreeIndex = AdvancedIndexDefinition::btree( 'idx_users_name', ['first_name', 'last_name'], ['fillfactor' => 70] ); ``` The index definition can then be converted to SQL for different database systems: ```php // Generate SQL for PostgreSQL $sql = $index->toSql('pgsql', 'users'); // Generate SQL for MySQL $sql = $index->toSql('mysql', 'users'); ``` ## Enhanced Schema Versioning The Database module now includes enhanced schema versioning capabilities, including dependency tracking and schema comparison tools. ### Schema Comparison The schema comparison tools allow you to compare two database schemas and generate migration code to update one schema to match the other. ```php use App\Framework\Database\Schema\Comparison\SchemaComparator; // Create a comparator with source and target connections $comparator = new SchemaComparator($sourceConnection, $targetConnection); // Compare the schemas $difference = $comparator->compare(); // Check if there are differences if ($difference->hasDifferences()) { // Get a summary of the differences $summary = $difference->getSummary(); // Get a detailed description of the differences $description = $difference->getDescription(); // Generate migration code to update the target schema to match the source schema $migrationCode = $difference->generateMigrationCode('UpdateSchema'); // Save the migration code to a file file_put_contents('database/migrations/UpdateSchema.php', $migrationCode); } ``` ### Dependent Migrations The enhanced migration system now supports dependencies between migrations: ```php use App\Framework\Database\ConnectionInterface; use App\Framework\Database\Migration\AbstractDependentMigration; use App\Framework\Database\Migration\MigrationVersion; use App\Framework\Database\Schema\Schema; final class CreateCommentsTable extends AbstractDependentMigration { public function getVersion(): MigrationVersion { return MigrationVersion::fromString('20250805123456'); } public function getDescription(): string { return 'Create comments table'; } public function getDependencies(): array { // This migration depends on the CreateUsersTable and CreatePostsTable migrations return [ MigrationVersion::fromString('20250805123455'), // CreateUsersTable MigrationVersion::fromString('20250805123454') // CreatePostsTable ]; } public function up(ConnectionInterface $connection): void { $schema = new Schema($connection); $schema->create('comments', function ($table) { $table->id(); $table->text('content'); $table->foreignId('user_id')->references('id')->on('users'); $table->foreignId('post_id')->references('id')->on('posts'); $table->timestamps(); }); $schema->execute(); } public function down(ConnectionInterface $connection): void { $schema = new Schema($connection); $schema->dropIfExists('comments'); $schema->execute(); } } ``` The migration runner will ensure that migrations are executed in the correct order based on their dependencies. ## Usage Examples ### Creating and Using a Stored Procedure ```php use App\Framework\Database\StoredProcedure\StoredProcedureDefinition; use App\Framework\Database\StoredProcedure\StoredProcedureManager; // Define a stored procedure to get active users $procedure = StoredProcedureDefinition::create('get_active_users') ->withParameter('min_login_count', 'INT') ->withBody(' SELECT * FROM users WHERE active = true AND login_count >= min_login_count ORDER BY last_login DESC; ') ->returnsType('TABLE'); // Create the procedure in the database $manager = new StoredProcedureManager($connection); $manager->createProcedure($procedure); // Execute the procedure $result = $manager->executeProcedure('get_active_users', [5]); // Process the results foreach ($result->fetchAll() as $user) { echo "User: {$user['name']} (Last login: {$user['last_login']})\n"; } ``` ### Creating Advanced Indexes ```php use App\Framework\Database\Schema\Index\AdvancedIndexDefinition; use App\Framework\Database\Schema\Index\AdvancedIndexType; // In a migration public function up(ConnectionInterface $connection): void { $schema = new Schema($connection); $schema->create('posts', function ($table) { $table->id(); $table->string('title'); $table->text('content'); $table->boolean('published')->default(false); $table->timestamps(); }); $schema->execute(); // Create a partial index on published posts $partialIndex = AdvancedIndexDefinition::partial( 'idx_published_posts', ['title'], AdvancedIndexType::INDEX, 'published = true' ); // Create a functional index for case-insensitive search $functionalIndex = AdvancedIndexDefinition::functional( 'idx_lower_title', AdvancedIndexType::INDEX, ['LOWER(title)'] ); // Generate and execute SQL for the current database $driver = $connection->getPdo()->getAttribute(\PDO::ATTR_DRIVER_NAME); $connection->execute($partialIndex->toSql($driver, 'posts')); $connection->execute($functionalIndex->toSql($driver, 'posts')); } ``` ### Comparing Schemas and Generating Migrations ```php use App\Framework\Database\Schema\Comparison\SchemaComparator; // Compare development and production schemas $comparator = new SchemaComparator($devConnection, $prodConnection); $difference = $comparator->compare(); if ($difference->hasDifferences()) { // Print a summary of the differences $summary = $difference->getSummary(); echo "Found {$summary['total_differences']} differences:\n"; echo " Missing tables: {$summary['missing_tables']}\n"; echo " Extra tables: {$summary['extra_tables']}\n"; echo " Modified tables: {$summary['modified_tables']}\n"; // Generate migration code $timestamp = date('YmdHis'); $className = "UpdateProductionSchema{$timestamp}"; $migrationCode = $difference->generateMigrationCode($className); // Save the migration $migrationPath = "database/migrations/{$className}.php"; file_put_contents($migrationPath, $migrationCode); echo "Generated migration: {$migrationPath}\n"; } ```