fix(2meet-data-optimizer): keep searches native while a group is known to drift
- The post query router routes no clause of a group whose last drift-check recorded miss / diff / extra; all or nothing, so such a query stays fully native. A group never checked keeps routing (decision 2026-09-27: no slowdown after upgrading; PR-073 samples daily). - The check sits in route_clause(), which every routed clause, HivePress sort shape and meta_key sort goes through. - Verify: PostQueryRouterDriftTest (drifting group and drifting sort key RED before); dev36 hp_listing price search in shadow_read: clean → flat, drift → native, unchecked → flat, found 90347 each. - PR: PR-072
This commit is contained in:
@@ -523,9 +523,23 @@ class TMDO_Post_Query_Router {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last `wp tmdo drift-check` found the group out of step with native
|
||||||
|
* meta. A group never checked keeps routing.
|
||||||
|
*
|
||||||
|
* @param string $group Entity group name.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private static function drifting( string $group ): bool {
|
||||||
|
$status = get_option( TMDO_Drift_Check::OPTION, array() );
|
||||||
|
$last = is_array( $status ) ? ( $status['post'][ $group ] ?? null ) : null;
|
||||||
|
return is_array( $last ) && (int) ( $last['miss'] ?? 0 ) + (int) ( $last['diff'] ?? 0 ) + (int) ( $last['extra'] ?? 0 ) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The routed form of a clause, or null when the flat column would not
|
* The routed form of a clause, or null when the flat column would not
|
||||||
* compare the way WordPress compares the meta_value string.
|
* compare the way WordPress compares the meta_value string, or when the
|
||||||
|
* group is known to drift from native meta.
|
||||||
*
|
*
|
||||||
* Native casts meta_value by the clause type (CHAR when absent); flat
|
* Native casts meta_value by the clause type (CHAR when absent); flat
|
||||||
* columns are typed. Routed: EXISTS / NOT EXISTS; string columns with
|
* columns are typed. Routed: EXISTS / NOT EXISTS; string columns with
|
||||||
@@ -560,7 +574,7 @@ class TMDO_Post_Query_Router {
|
|||||||
&& in_array( $compare, array( '=', '!=', '<>', 'IN', 'NOT IN' ), true )
|
&& in_array( $compare, array( '=', '!=', '<>', 'IN', 'NOT IN' ), true )
|
||||||
&& array() === array_filter( (array) $value, static fn( $v ) => ! is_scalar( $v ) || (string) (int) $v !== (string) $v );
|
&& array() === array_filter( (array) $value, static fn( $v ) => ! is_scalar( $v ) || (string) (int) $v !== (string) $v );
|
||||||
}
|
}
|
||||||
if ( ! $ok ) {
|
if ( ! $ok || self::drifting( (string) $field['group'] ) ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -622,6 +622,7 @@ require_once TMDO_PATH . 'includes/engine/class-tmdo-query-compiler.php';
|
|||||||
require_once TMDO_PATH . 'includes/engine/class-tmdo-schema-manager.php';
|
require_once TMDO_PATH . 'includes/engine/class-tmdo-schema-manager.php';
|
||||||
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-registry.php';
|
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-registry.php';
|
||||||
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-migration-engine.php';
|
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-migration-engine.php';
|
||||||
|
require_once TMDO_PATH . 'includes/diagnostic/class-tmdo-drift-check.php';
|
||||||
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-health.php';
|
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-health.php';
|
||||||
require_once TMDO_PATH . 'includes/adapters/interface-entity-adapter.php';
|
require_once TMDO_PATH . 'includes/adapters/interface-entity-adapter.php';
|
||||||
require_once TMDO_PATH . 'includes/adapters/class-tmdo-adapter-post.php';
|
require_once TMDO_PATH . 'includes/adapters/class-tmdo-adapter-post.php';
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The post query router leaves a query native while the last drift-check
|
||||||
|
* found a routed clause's group out of step with native meta (2.2 PR-072).
|
||||||
|
* All or nothing: one drifting group keeps the whole query native. A group
|
||||||
|
* never checked keeps routing (decision 2026-09-27).
|
||||||
|
*/
|
||||||
|
class PostQueryRouterDriftTest extends TestCase {
|
||||||
|
|
||||||
|
public static function setUpBeforeClass(): void {
|
||||||
|
WPDO_Entity_Registry::init();
|
||||||
|
WPDO_Entity_Registry::register_adapter( 'post', new WPDO_Adapter_Post() );
|
||||||
|
WPDO_Post_Fields::register_entity_fields();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function tearDownAfterClass(): void {
|
||||||
|
self::set_modes( null );
|
||||||
|
WPDO_Entity_Registry::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setUp(): void {
|
||||||
|
$GLOBALS['_wp_options'] = array();
|
||||||
|
self::set_modes(
|
||||||
|
array(
|
||||||
|
'post' => 'shadow_read',
|
||||||
|
'user' => 'disabled',
|
||||||
|
'term' => 'disabled',
|
||||||
|
'comment' => 'disabled',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function set_modes( ?array $modes ): void {
|
||||||
|
$cache = ( new ReflectionClass( WPDO_Mode_Manager::class ) )->getProperty( 'cache' );
|
||||||
|
$cache->setAccessible( true );
|
||||||
|
$cache->setValue( null, $modes );
|
||||||
|
}
|
||||||
|
|
||||||
|
private function drift( string $group, int $diff ): void {
|
||||||
|
$GLOBALS['_wp_options'][ TMDO_Drift_Check::OPTION ]['post'][ $group ] = array(
|
||||||
|
'miss' => 0,
|
||||||
|
'diff' => $diff,
|
||||||
|
'extra' => 0,
|
||||||
|
'sample' => 0,
|
||||||
|
'checked_at' => '2026-09-27 00:00:00',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function price_query( array $extra = array() ): WP_Query {
|
||||||
|
$query = new WP_Query();
|
||||||
|
foreach ( array(
|
||||||
|
'post_type' => 'product',
|
||||||
|
'meta_query' => array(
|
||||||
|
array( 'key' => '_price', 'value' => '50', 'compare' => '>=', 'type' => 'NUMERIC' ),
|
||||||
|
),
|
||||||
|
) + $extra as $k => $v ) {
|
||||||
|
$query->set( $k, $v );
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_a_drifting_group_keeps_the_query_native(): void {
|
||||||
|
$this->drift( 'wc_product', 3 );
|
||||||
|
$query = $this->price_query();
|
||||||
|
$original = $query->get( 'meta_query' );
|
||||||
|
|
||||||
|
( new WPDO_Post_Query_Router() )->pre_get_posts( $query );
|
||||||
|
|
||||||
|
$this->assertSame( $original, $query->get( 'meta_query' ) );
|
||||||
|
$this->assertSame( '', $query->get( 'wpdo_post_clauses' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_a_clean_group_is_routed(): void {
|
||||||
|
$this->drift( 'wc_product', 0 );
|
||||||
|
$query = $this->price_query();
|
||||||
|
|
||||||
|
( new WPDO_Post_Query_Router() )->pre_get_posts( $query );
|
||||||
|
|
||||||
|
$this->assertNotEmpty( $query->get( 'wpdo_post_clauses' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_a_group_never_checked_is_routed(): void {
|
||||||
|
$query = $this->price_query();
|
||||||
|
|
||||||
|
( new WPDO_Post_Query_Router() )->pre_get_posts( $query );
|
||||||
|
|
||||||
|
$this->assertNotEmpty( $query->get( 'wpdo_post_clauses' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_drift_in_another_group_does_not_matter(): void {
|
||||||
|
$this->drift( 'hp_listing_core', 5 );
|
||||||
|
$query = $this->price_query();
|
||||||
|
|
||||||
|
( new WPDO_Post_Query_Router() )->pre_get_posts( $query );
|
||||||
|
|
||||||
|
$this->assertNotEmpty( $query->get( 'wpdo_post_clauses' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_sorting_by_a_drifting_key_stays_native(): void {
|
||||||
|
$this->drift( 'wc_product', 1 );
|
||||||
|
$query = new WP_Query();
|
||||||
|
$query->set( 'post_type', 'product' );
|
||||||
|
$query->set( 'meta_key', '_price' );
|
||||||
|
$query->set( 'orderby', 'meta_value_num' );
|
||||||
|
|
||||||
|
( new WPDO_Post_Query_Router() )->pre_get_posts( $query );
|
||||||
|
|
||||||
|
$this->assertSame( '_price', $query->get( 'meta_key' ) );
|
||||||
|
$this->assertSame( '', $query->get( 'wpdo_post_sort' ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -586,6 +586,7 @@ require_once TMDO_PATH . 'includes/engine/class-tmdo-query-compiler.php';
|
|||||||
require_once TMDO_PATH . 'includes/engine/class-tmdo-schema-manager.php';
|
require_once TMDO_PATH . 'includes/engine/class-tmdo-schema-manager.php';
|
||||||
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-registry.php';
|
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-registry.php';
|
||||||
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-migration-engine.php';
|
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-migration-engine.php';
|
||||||
|
require_once TMDO_PATH . 'includes/diagnostic/class-tmdo-drift-check.php';
|
||||||
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-health.php';
|
require_once TMDO_PATH . 'includes/engine/class-tmdo-entity-health.php';
|
||||||
require_once TMDO_PATH . 'includes/engine/class-tmdo-auto-promoter.php';
|
require_once TMDO_PATH . 'includes/engine/class-tmdo-auto-promoter.php';
|
||||||
require_once TMDO_PATH . 'includes/engine/class-tmdo-hook-bus.php';
|
require_once TMDO_PATH . 'includes/engine/class-tmdo-hook-bus.php';
|
||||||
|
|||||||
Reference in New Issue
Block a user