@@ -484,4 +484,103 @@ public function testDeleteWithoutLimitOrOrderByStillWorks(): void
484484
485485 $ this ->assertSame (1 , $ affected );
486486 }
487+
488+ // =========================================================================
489+ // WHERE NULL BUG FIX TEST
490+ // Bug: where('column', null) generated "column = NULL" which is always false
491+ // in SQL. Users must use whereNull()/whereNotNull() instead.
492+ // =========================================================================
493+
494+ public function testWhereTwoArgNullThrowsException (): void
495+ {
496+ $ db = Database::sqlite (':memory: ' );
497+
498+ $ this ->expectException (QueryException::class);
499+
500+ $ db ->table ('users ' )->where ('status ' , null );
501+ }
502+
503+ public function testWhereThreeArgNullThrowsException (): void
504+ {
505+ $ db = Database::sqlite (':memory: ' );
506+
507+ $ this ->expectException (QueryException::class);
508+
509+ $ db ->table ('users ' )->where ('status ' , '= ' , null );
510+ }
511+
512+ public function testWhereArraySyntaxNullThrowsException (): void
513+ {
514+ $ db = Database::sqlite (':memory: ' );
515+
516+ $ this ->expectException (QueryException::class);
517+
518+ $ db ->table ('users ' )->where (['status ' => null ]);
519+ }
520+
521+ public function testWhereNullExceptionSuggestsWhereNull (): void
522+ {
523+ $ db = Database::sqlite (':memory: ' );
524+
525+ try {
526+ $ db ->table ('users ' )->where ('status ' , null );
527+ $ this ->fail ('Expected QueryException was not thrown ' );
528+ } catch (QueryException $ e ) {
529+ $ debug = $ e ->getDebugMessage () ?? '' ;
530+ $ this ->assertStringContainsString ('whereNull ' , $ debug );
531+ $ this ->assertStringContainsString ('status ' , $ debug );
532+ }
533+ }
534+
535+ public function testWhereThreeArgNullExceptionSuggestsWhereNull (): void
536+ {
537+ $ db = Database::sqlite (':memory: ' );
538+
539+ try {
540+ $ db ->table ('users ' )->where ('deleted_at ' , '= ' , null );
541+ $ this ->fail ('Expected QueryException was not thrown ' );
542+ } catch (QueryException $ e ) {
543+ $ debug = $ e ->getDebugMessage () ?? '' ;
544+ $ this ->assertStringContainsString ('whereNull ' , $ debug );
545+ $ this ->assertStringContainsString ('deleted_at ' , $ debug );
546+ }
547+ }
548+
549+ public function testWhereIsNullThrowsExceptionSuggestsWhereNull (): void
550+ {
551+ $ db = Database::sqlite (':memory: ' );
552+
553+ try {
554+ $ db ->table ('users ' )->where ('deleted_at ' , 'IS ' , null );
555+ $ this ->fail ('Expected QueryException was not thrown ' );
556+ } catch (QueryException $ e ) {
557+ $ debug = $ e ->getDebugMessage () ?? '' ;
558+ $ this ->assertStringContainsString ('whereNull ' , $ debug );
559+ }
560+ }
561+
562+ public function testWhereIsNotNullThrowsExceptionSuggestsWhereNotNull (): void
563+ {
564+ $ db = Database::sqlite (':memory: ' );
565+
566+ try {
567+ $ db ->table ('users ' )->where ('deleted_at ' , 'IS NOT ' , null );
568+ $ this ->fail ('Expected QueryException was not thrown ' );
569+ } catch (QueryException $ e ) {
570+ $ debug = $ e ->getDebugMessage () ?? '' ;
571+ $ this ->assertStringContainsString ('whereNotNull ' , $ debug );
572+ }
573+ }
574+
575+ public function testWhereWithNonNullValuesStillWorks (): void
576+ {
577+ $ db = Database::sqlite (':memory: ' );
578+ $ db ->execute ('CREATE TABLE users (id INTEGER PRIMARY KEY, status TEXT) ' );
579+ $ db ->insert ('users ' , ['status ' => 'active ' ]);
580+
581+ $ result = $ db ->table ('users ' )->where ('status ' , 'active ' )->first ();
582+
583+ $ this ->assertNotNull ($ result );
584+ $ this ->assertSame ('active ' , $ result ['status ' ]);
585+ }
487586}
0 commit comments