Files
michaelschiemer/tests/debug/test-range-types.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

249 lines
9.8 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/../../src/Framework/Database/Schema/SchemaCompiler.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/Blueprint.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/ColumnDefinition.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/IndexDefinition.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/IndexType.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/ForeignKeyDefinition.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/ForeignKeyAction.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/PostgreSQLSchemaCompiler.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/Commands/CreateTableCommand.php';
require_once __DIR__ . '/../../src/Framework/Database/Schema/Commands/DropTableCommand.php';
use App\Framework\Database\Schema\Blueprint;
use App\Framework\Database\Schema\PostgreSQLSchemaCompiler;
use App\Framework\Database\Schema\Commands\CreateTableCommand;
echo "Testing PostgreSQL Range Types\n";
echo "===============================\n\n";
try {
$pdo = new PDO(
'pgsql:host=db;dbname=michaelschiemer',
'postgres',
'StartSimple2024!'
);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "✅ Database connection established\n\n";
$compiler = new PostgreSQLSchemaCompiler();
// Cleanup
echo "Cleanup...\n";
$pdo->exec("DROP TABLE IF EXISTS test_ranges CASCADE");
echo "✅ Cleanup complete\n\n";
// Test 1: Create table with all range types
echo "Test 1: Create Table With Range Types\n";
echo "======================================\n";
$blueprint = new Blueprint('test_ranges');
$blueprint->bigIncrements('id');
$blueprint->string('description');
// Numeric ranges
$blueprint->int4range('age_range')->nullable();
$blueprint->int8range('population_range')->nullable();
$blueprint->numrange('price_range')->nullable();
// Timestamp ranges
$blueprint->tsrange('event_period')->nullable();
$blueprint->tstzrange('booking_period')->nullable();
// Date ranges
$blueprint->daterange('valid_dates')->nullable();
$createCommand = new CreateTableCommand('test_ranges', $blueprint);
$sql = $compiler->compile($createCommand);
echo "Creating table with range columns:\n";
echo $sql . "\n\n";
$pdo->exec($sql);
echo "✅ Table 'test_ranges' created with all range types\n\n";
// Test 2: Insert data with range values
echo "Test 2: Insert Range Data\n";
echo "==========================\n";
$pdo->exec("
INSERT INTO test_ranges (
description,
age_range,
population_range,
price_range,
event_period,
booking_period,
valid_dates
) VALUES (
'Hotel Booking',
'[18,65)', -- Age 18 to 64 (inclusive start, exclusive end)
'[1000000,5000000)', -- Population range
'[99.99,499.99]', -- Price range (both inclusive)
'[2024-06-01 10:00:00, 2024-06-01 18:00:00)', -- Event period
'[2024-06-01 10:00:00+02, 2024-06-01 18:00:00+02)', -- Booking with timezone
'[2024-01-01, 2024-12-31]' -- Valid date range
)
");
echo "✅ Range data inserted\n\n";
// Test 3: Query range data
echo "Test 3: Query Range Data\n";
echo "=========================\n";
$stmt = $pdo->query("SELECT * FROM test_ranges WHERE id = 1");
$result = $stmt->fetch(PDO::FETCH_ASSOC);
echo "Retrieved data:\n";
echo " - Description: {$result['description']}\n";
echo " - Age Range: {$result['age_range']}\n";
echo " - Population Range: {$result['population_range']}\n";
echo " - Price Range: {$result['price_range']}\n";
echo " - Event Period: {$result['event_period']}\n";
echo " - Booking Period: {$result['booking_period']}\n";
echo " - Valid Dates: {$result['valid_dates']}\n";
echo "✅ Range data successfully retrieved\n\n";
// Test 4: Range operators
echo "Test 4: Range Operators\n";
echo "========================\n";
// Insert test data for operator tests
$pdo->exec("
INSERT INTO test_ranges (description, age_range, price_range, valid_dates)
VALUES
('Product A', '[25,50)', '[100.00,200.00]', '[2024-01-01,2024-06-30]'),
('Product B', '[30,60)', '[150.00,300.00]', '[2024-03-01,2024-09-30]'),
('Product C', '[40,70)', '[250.00,500.00]', '[2024-06-01,2024-12-31]')
");
echo "✅ Test data inserted\n\n";
// Test @> (contains) operator
echo "Test @> (contains) operator:\n";
$stmt = $pdo->query("SELECT description FROM test_ranges WHERE age_range @> 35");
$results = $stmt->fetchAll(PDO::FETCH_COLUMN);
echo " Products with age range containing 35: " . implode(', ', $results) . "\n";
echo (count($results) == 3) ? "✅ Contains operator works\n\n" : "❌ Should find 3 products\n\n";
// Test <@ (is contained by) operator
echo "Test <@ (is contained by) operator:\n";
$stmt = $pdo->query("SELECT description FROM test_ranges WHERE '[100,150]'::numrange <@ price_range");
$results = $stmt->fetchAll(PDO::FETCH_COLUMN);
echo " Products containing price range [100,150]: " . implode(', ', $results) . "\n";
echo (count($results) >= 1) ? "✅ Is contained by operator works\n\n" : "❌ Should find products\n\n";
// Test && (overlap) operator
echo "Test && (overlap) operator:\n";
$stmt = $pdo->query("SELECT description FROM test_ranges WHERE valid_dates && '[2024-05-01,2024-07-31]'::daterange");
$results = $stmt->fetchAll(PDO::FETCH_COLUMN);
echo " Products with overlapping date range: " . implode(', ', $results) . "\n";
echo (count($results) >= 2) ? "✅ Overlap operator works\n\n" : "❌ Should find overlapping products\n\n";
// Test 5: Range functions
echo "Test 5: Range Functions\n";
echo "========================\n";
// lower() and upper() functions
$stmt = $pdo->query("
SELECT
description,
lower(age_range) as min_age,
upper(age_range) as max_age,
lower(price_range) as min_price,
upper(price_range) as max_price
FROM test_ranges
WHERE description = 'Product A'
");
$result = $stmt->fetch(PDO::FETCH_ASSOC);
echo "Product A bounds:\n";
echo " - Min Age: {$result['min_age']}\n";
echo " - Max Age: {$result['max_age']}\n";
echo " - Min Price: {$result['min_price']}\n";
echo " - Max Price: {$result['max_price']}\n";
echo "✅ Range boundary functions work\n\n";
// isempty() function
echo "Test isempty() function:\n";
$stmt = $pdo->query("SELECT COUNT(*) FROM test_ranges WHERE isempty(age_range)");
$emptyCount = $stmt->fetchColumn();
echo " - Empty ranges: {$emptyCount}\n";
echo ($emptyCount == 0) ? "✅ No empty ranges found (as expected)\n\n" : "✅ isempty() function works\n\n";
// Test 6: Range intersection
echo "Test 6: Range Intersection\n";
echo "===========================\n";
// Test range intersection
$stmt = $pdo->query("
SELECT
'[25,60)'::int4range * '[30,50)'::int4range as intersection,
'[100.00,200.00]'::numrange * '[150.00,300.00]'::numrange as price_intersection
");
$result = $stmt->fetch(PDO::FETCH_ASSOC);
echo "Range intersections:\n";
echo " - Age range [25,60) * [30,50) = {$result['intersection']}\n";
echo " - Price range [100,200] * [150,300] = {$result['price_intersection']}\n";
echo "✅ Range intersection operator works\n\n";
// Test 7: GiST index on range column
echo "Test 7: GiST Index on Range Column\n";
echo "===================================\n";
$pdo->exec("CREATE INDEX idx_test_ranges_age ON test_ranges USING GIST (age_range)");
echo "✅ GiST index created on age_range column\n";
$pdo->exec("CREATE INDEX idx_test_ranges_price ON test_ranges USING GIST (price_range)");
echo "✅ GiST index created on price_range column\n";
$pdo->exec("CREATE INDEX idx_test_ranges_dates ON test_ranges USING GIST (valid_dates)");
echo "✅ GiST index created on valid_dates column\n\n";
// Test 8: Verify indexes are used
echo "Test 8: Verify Index Usage\n";
echo "===========================\n";
$stmt = $pdo->query("
SELECT indexname, indexdef
FROM pg_indexes
WHERE tablename = 'test_ranges'
AND indexname LIKE 'idx_test_ranges_%'
ORDER BY indexname
");
$indexes = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo "Found " . count($indexes) . " GiST indexes:\n";
foreach ($indexes as $index) {
echo " - {$index['indexname']}\n";
}
echo (count($indexes) == 3) ? "✅ All GiST indexes created\n\n" : "❌ Expected 3 indexes\n\n";
// Cleanup
echo "Cleanup...\n";
$pdo->exec("DROP TABLE IF EXISTS test_ranges CASCADE");
echo "✅ Test data cleaned up\n";
echo "\n✅ All Range Types tests passed!\n";
echo "\nSummary:\n";
echo "========\n";
echo "✅ INT4RANGE (integer ranges) works\n";
echo "✅ INT8RANGE (bigint ranges) works\n";
echo "✅ NUMRANGE (numeric ranges) works\n";
echo "✅ TSRANGE (timestamp ranges) works\n";
echo "✅ TSTZRANGE (timestamp with timezone ranges) works\n";
echo "✅ DATERANGE (date ranges) works\n";
echo "✅ Range operators (@>, <@, &&) work\n";
echo "✅ Range functions (lower, upper, isempty) work\n";
echo "✅ Range intersection operator (*) works\n";
echo "✅ GiST indexes on range columns work\n";
} catch (\Exception $e) {
echo "❌ Error: " . $e->getMessage() . "\n";
echo "Stack trace:\n" . $e->getTraceAsString() . "\n";
exit(1);
}