*/ private static array $ids = []; private const BAD_SQL = 'SELECT * FROM table_that_does_not_exist'; public static function setUpBeforeClass(): void { self::createTable('users', [ 'id' => 'pk', 'username' => 'string', 'email' => 'string', 'bio' => 'text', 'age' => 'number', 'is_active' => 'bool', 'last_login' => 'timestamp', ]); foreach (['fer', 'fiona', 'frog'] as $name) { $user = new User(); $user->username = $name; $user->email = $name . '@duckbrain.dev'; $user->age = 33; $user->save(); self::$ids[] = (int) $user->id; } } private static function runQuery(string $sql, bool $resetQuery = true): void { (new ReflectionMethod(User::class, 'query'))->invokeArgs(null, [$sql, $resetQuery]); } private static function currentSql(): string { return (new ReflectionMethod(User::class, 'buildQuery'))->invoke(null); } #[Test] public function failingQueryDoesNotContaminateTheNextQuery(): void { User::where('id', self::$ids[0]); try { self::runQuery(self::BAD_SQL); $this->fail('a query against a missing table must throw'); } catch (Exception $e) { $this->assertStringContainsString('Error at query to database', $e->getMessage()); } // With the default resetQuery: true, the failed run must have left // the builder as good as new; get() therefore sees all three rows. $this->assertCount(3, User::get(), 'builder state leaked from the failed query'); } #[Test] public function failedKeepStateQueryLeavesTheWhereForRetry(): void { User::where('username', 'fiona'); try { self::runQuery(self::BAD_SQL, false); $this->fail('a query against a missing table must throw'); } catch (Exception $e) { $this->assertStringContainsString('Error at query to database', $e->getMessage()); } // resetQuery: false contracts to keep the where alive for the // caller's deliberate retry (also guards against a fix that resets // unconditionally). $this->assertStringContainsString('WHERE', self::currentSql()); $retry = User::get(); $this->assertCount(1, $retry, 'retry after failure must reuse the kept where'); $this->assertSame('fiona', $retry[0]->username); } }