@@ -3183,6 +3183,96 @@ public function testQueryCaching(): void
31833183        $ this assertEquals ($ countBefore$ cachecount ()); // No new cache entry 
31843184    }
31853185
3186+     public  function  testDialectRegistryAndCacheManagerCoverage (): void 
3187+     {
3188+         // DialectRegistry 
3189+         $ driverstommyknocker \pdodb \connection \DialectRegistry::getSupportedDrivers ();
3190+         $ this assertNotEmpty ($ drivers
3191+         $ this assertTrue (\tommyknocker \pdodb \connection \DialectRegistry::isSupported ('sqlite ' ));
3192+         $ dialecttommyknocker \pdodb \connection \DialectRegistry::resolve ('sqlite ' );
3193+         $ this assertEquals ('sqlite ' , $ dialectgetDriverName ());
3194+ 
3195+         // CacheManager basic ops 
3196+         $ cachenew  ArrayCache ();
3197+         $ cmnew  \tommyknocker \pdodb \cache \CacheManager ($ cache'enabled '  => true , 'default_ttl '  => 60 , 'prefix '  => 'p ' ]);
3198+         $ key$ cmgenerateKey ('SELECT 1 ' , ['a '  => 1 ], 'sqlite ' );
3199+         $ this assertIsString ($ key
3200+         $ this assertFalse ($ cmhas ($ key
3201+         $ this assertTrue ($ cmset ($ key'val ' ));
3202+         $ this assertTrue ($ cmhas ($ key
3203+         $ this assertEquals ('val ' , $ cmget ($ key
3204+         $ this assertTrue ($ cmdelete ($ key
3205+         $ this assertTrue ($ cmclear ());
3206+     }
3207+ 
3208+     public  function  testIdentifierQuotingAndUnsafeDetection (): void 
3209+     {
3210+         $ dbnew  \tommyknocker \pdodb \PdoDb ('sqlite ' , ['path '  => ':memory: ' ]);
3211+         $ dbrawQuery ('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INT) ' );
3212+ 
3213+         // Quoting of qualified identifier 
3214+         $ dbfind ()->from ('users ' )->select (['users.name ' ])->get ();
3215+         $ this assertStringContainsString ('"users"."name" ' , $ dblastQuery );
3216+ 
3217+         // Pass-through expression 
3218+         $ dbfind ()->from ('users ' )->select (['SUM(age) ' ])->get ();
3219+         $ this assertStringContainsString ('SUM(age) ' , $ dblastQuery );
3220+ 
3221+         // Unsafe token should throw 
3222+         $ this expectException (\InvalidArgumentException::class);
3223+         $ dbfind ()->from ('users ' )->select (['name; DROP TABLE ' ])->get ();
3224+     }
3225+ 
3226+     public  function  testExplainDescribeAndIndexes (): void 
3227+     {
3228+         $ dbnew  \tommyknocker \pdodb \PdoDb ('sqlite ' , ['path '  => ':memory: ' ]);
3229+         $ dbrawQuery ('CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT, age INT) ' );
3230+         $ dbrawQuery ('CREATE INDEX idx_t_name ON t(name) ' );
3231+ 
3232+         $ report$ dbfind ()->from ('t ' )->where ('name ' , 'Alice ' )->explain ();
3233+         $ this assertIsArray ($ report
3234+ 
3235+         $ reportAnalyze$ dbfind ()->from ('t ' )->where ('name ' , 'Alice ' )->explainAnalyze ();
3236+         $ this assertIsArray ($ reportAnalyze
3237+ 
3238+         $ desc$ dbfind ()->from ('t ' )->describe ();
3239+         $ this assertIsArray ($ desc
3240+ 
3241+         $ idx$ dbfind ()->from ('t ' )->indexes ();
3242+         $ this assertIsArray ($ idx
3243+ 
3244+         $ keys$ dbfind ()->from ('t ' )->keys ();
3245+         $ this assertIsArray ($ keys
3246+ 
3247+         $ constraints$ dbfind ()->from ('t ' )->constraints ();
3248+         $ this assertIsArray ($ constraints
3249+     }
3250+ 
3251+     public  function  testFilterValueAndWindowFunctionResolution (): void 
3252+     {
3253+         $ dbnew  \tommyknocker \pdodb \PdoDb ('sqlite ' , ['path '  => ':memory: ' ]);
3254+         $ dbrawQuery ('CREATE TABLE s (id INTEGER PRIMARY KEY, grp INT, val INT) ' );
3255+         $ dbfind ()->table ('s ' )->insertMulti ([
3256+             ['grp '  => 1 , 'val '  => 10 ],
3257+             ['grp '  => 1 , 'val '  => 20 ],
3258+             ['grp '  => 2 , 'val '  => 30 ],
3259+         ]);
3260+ 
3261+         // FilterValue COUNT(*) where val > 10 -> in SQLite fallback to CASE WHEN form 
3262+         $ fvnew  \tommyknocker \pdodb \helpers \values \FilterValue ('COUNT(*) ' );
3263+         $ fvfilter ('val ' , 10 , '> ' );
3264+         $ dbfind ()->from ('s ' )->select (['cnt '  => $ fvget ();
3265+         $ this assertTrue (
3266+             str_contains ($ dblastQuery , ' FILTER (WHERE ' )
3267+             || str_contains ($ dblastQuery , 'COUNT(CASE WHEN ' )
3268+         );
3269+ 
3270+         // Window function example: ROW_NUMBER() OVER (PARTITION BY grp ORDER BY val) 
3271+         $ wfnew  \tommyknocker \pdodb \helpers \values \WindowFunctionValue ('ROW_NUMBER ' );
3272+         $ dbfind ()->from ('s ' )->select (['rn '  => $ wfget ();
3273+         $ this assertStringContainsString ('ROW_NUMBER ' , $ dblastQuery );
3274+     }
3275+ 
31863276    /** 
31873277     * Ensure wildcard selections work uniformly across input forms. 
31883278     * - select(['*']) behaves like select('*') 
@@ -3228,6 +3318,75 @@ public function testSelectWildcardForms(): void
32283318        $ this assertEquals ($ rows20 ]['amount ' ], $ rows30 ]['amount ' ]);
32293319    }
32303320
3321+     public  function  testRoundRobinAndWeightedLoadBalancers (): void 
3322+     {
3323+         // Minimal ConnectionInterface stub 
3324+         $ makeConnfunction  (string  $ driver\tommyknocker \pdodb \connection \ConnectionInterface   {
3325+             return  new  class ($ driverimplements  \tommyknocker \pdodb \connection \ConnectionInterface {
3326+                 public  function  __construct (private  string  $ driver
3327+                 public  function  getPdo (): \PDO   { return  new  \PDO ('sqlite::memory: ' ); }
3328+                 public  function  getDriverName (): string  { return  $ this driver ; }
3329+                 public  function  getDialect (): \tommyknocker \pdodb \dialects \DialectInterface   { throw  new  \RuntimeException ('not used ' ); }
3330+                 public  function  resetState (): void  {}
3331+                 public  function  prepare (string  $ sqlarray  $ paramsstatic return  $ this 
3332+                 public  function  execute (array  $ params\PDOStatement   { throw  new  \RuntimeException ('not used ' ); }
3333+                 public  function  query (string  $ sql\PDOStatement  |false  { return  false ; }
3334+                 public  function  quote (mixed  $ valuestring |false  { return  (string )$ value
3335+                 public  function  transaction (): bool  { return  true ; }
3336+                 public  function  commit (): bool  { return  true ; }
3337+                 public  function  rollBack (): bool  { return  true ; }
3338+                 public  function  inTransaction (): bool  { return  false ; }
3339+                 public  function  getLastInsertId (?string  $ namenull ): false |string  { return  '0 ' ; }
3340+                 public  function  getLastQuery (): ?string  { return  null ; }
3341+                 public  function  getLastError (): ?string  { return  null ; }
3342+                 public  function  getLastErrno (): int  { return  0 ; }
3343+                 public  function  getExecuteState (): ?bool  { return  true ; }
3344+                 public  function  setAttribute (int  $ attributemixed  $ valuebool  { return  true ; }
3345+                 public  function  getAttribute (int  $ attributemixed  { return  null ; }
3346+             };
3347+         };
3348+ 
3349+         $ connections
3350+             'a '  => $ makeConn'sqlite ' ),
3351+             'b '  => $ makeConn'sqlite ' ),
3352+             'c '  => $ makeConn'sqlite ' ),
3353+         ];
3354+ 
3355+         // RoundRobin 
3356+         $ rrnew  \tommyknocker \pdodb \connection \loadbalancer \RoundRobinLoadBalancer ();
3357+         $ first$ rrselect ($ connections
3358+         $ second$ rrselect ($ connections
3359+         $ this assertContains ($ firstarray_values ($ connections
3360+         $ this assertContains ($ secondarray_values ($ connections
3361+         $ this assertNotSame ($ first$ second
3362+         $ rrmarkFailed ('b ' );
3363+         $ third$ rrselect ($ connections
3364+         $ this assertContains ($ thirdarray_values ($ connections
3365+         $ rrreset ();
3366+         $ fourth$ rrselect ($ connections
3367+         $ this assertContains ($ fourtharray_values ($ connections
3368+ 
3369+         // Weighted: ensure failed nodes excluded and selection returns healthy names 
3370+         $ wlbnew  \tommyknocker \pdodb \connection \loadbalancer \WeightedLoadBalancer ();
3371+         $ wlbsetWeights (['a '  => 1 , 'b '  => 5 , 'c '  => 1 ]);
3372+         $ wlbmarkFailed ('b ' );
3373+         $ seen
3374+         for  ($ i0 ; $ i20 ; $ i
3375+             $ picked$ wlbselect ($ connections
3376+             $ this assertContains ($ picked$ connections'a ' ], $ connections'c ' ]]);
3377+             $ seenspl_object_hash ($ pickedtrue ;
3378+         }
3379+         // Both a and c appeared at least once 
3380+         $ this assertCount (2 , $ seen
3381+         // After reset failure, 'b' can be selected 
3382+         $ wlbmarkHealthy ('b ' );
3383+         $ foundBfalse ;
3384+         for  ($ i0 ; $ i50 ; $ i
3385+             if  ($ wlbselect ($ connections$ connections'b ' ]) { $ foundBtrue ; break ; }
3386+         }
3387+         $ this assertTrue ($ foundB
3388+     }
3389+ 
32313390    /** 
32323391     * Test caching without cache manager (should work normally). 
32333392     */ 
0 commit comments