sql)->toBe('SELECT * FROM users WHERE id = ?'); expect($log->bindings)->toBe([123]); expect($log->executionTimeMs)->toBe(5.5); expect($log->rowCount)->toBe(1); expect($log->callerClass)->toBe('UserController'); expect($log->callerMethod)->toBe('index'); expect($log->callerLine)->toBe(42); }); it('normalizes SQL pattern correctly', function () { $log = new QueryLog( sql: "SELECT * FROM users WHERE id = 123 AND email = 'test@example.com'", bindings: [], executionTimeMs: 1.0, stackTrace: '' ); $pattern = $log->getPattern(); expect($pattern)->toBe('SELECT * FROM users WHERE id = ? AND email = ?'); }); it('normalizes IN clauses', function () { $log = new QueryLog( sql: 'SELECT * FROM users WHERE id IN (1, 2, 3, 4, 5)', bindings: [], executionTimeMs: 1.0, stackTrace: '' ); $pattern = $log->getPattern(); expect($pattern)->toBe('SELECT * FROM users WHERE id IN (?)'); }); it('detects SELECT queries', function () { $log = new QueryLog( sql: 'SELECT * FROM users', bindings: [], executionTimeMs: 1.0, stackTrace: '' ); expect($log->isSelect())->toBeTrue(); expect($log->isInsert())->toBeFalse(); expect($log->isUpdate())->toBeFalse(); expect($log->isDelete())->toBeFalse(); }); it('detects INSERT queries', function () { $log = new QueryLog( sql: 'INSERT INTO users (name, email) VALUES (?, ?)', bindings: ['John', 'john@example.com'], executionTimeMs: 2.0, stackTrace: '' ); expect($log->isInsert())->toBeTrue(); expect($log->isSelect())->toBeFalse(); }); it('extracts table name from SELECT', function () { $log = new QueryLog( sql: 'SELECT * FROM users WHERE id = ?', bindings: [1], executionTimeMs: 1.0, stackTrace: '' ); expect($log->getTableName())->toBe('users'); }); it('extracts table name from INSERT', function () { $log = new QueryLog( sql: 'INSERT INTO orders (user_id, total) VALUES (?, ?)', bindings: [1, 100], executionTimeMs: 1.0, stackTrace: '' ); expect($log->getTableName())->toBe('orders'); }); it('detects WHERE clause', function () { $log = new QueryLog( sql: 'SELECT * FROM users WHERE id = ?', bindings: [1], executionTimeMs: 1.0, stackTrace: '' ); expect($log->hasWhereClause())->toBeTrue(); }); it('detects missing WHERE clause', function () { $log = new QueryLog( sql: 'SELECT * FROM users', bindings: [], executionTimeMs: 1.0, stackTrace: '' ); expect($log->hasWhereClause())->toBeFalse(); }); it('detects JOIN queries', function () { $log = new QueryLog( sql: 'SELECT * FROM users LEFT JOIN profiles ON users.id = profiles.user_id', bindings: [], executionTimeMs: 1.0, stackTrace: '' ); expect($log->hasJoin())->toBeTrue(); }); it('detects slow queries', function () { $log = new QueryLog( sql: 'SELECT * FROM users', bindings: [], executionTimeMs: 150.0, stackTrace: '' ); expect($log->isSlow(100.0))->toBeTrue(); expect($log->isSlow(200.0))->toBeFalse(); }); it('throws on negative execution time', function () { new QueryLog( sql: 'SELECT * FROM users', bindings: [], executionTimeMs: -5.0, stackTrace: '' ); })->throws(InvalidArgumentException::class, 'Execution time cannot be negative'); it('throws on negative row count', function () { new QueryLog( sql: 'SELECT * FROM users', bindings: [], executionTimeMs: 1.0, stackTrace: '', rowCount: -1 ); })->throws(InvalidArgumentException::class, 'Row count cannot be negative'); });