query( "CREATE TABLE `{$wpdb->posts}` ( ID BIGINT UNSIGNED NOT NULL, post_type VARCHAR(20) NOT NULL DEFAULT 'post', post_status VARCHAR(20) NOT NULL DEFAULT 'publish', post_date DATETIME NOT NULL DEFAULT '2000-01-01 00:00:00', PRIMARY KEY (ID) ) ENGINE=InnoDB" ); $wpdb->query( 'CREATE TABLE `' . self::TABLE . '` ( id BIGINT NOT NULL AUTO_INCREMENT, post_id BIGINT NOT NULL, fr_price DECIMAL(18,6) DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_entity (post_id) ) ENGINE=InnoDB' ); $wpdb->query( "INSERT INTO `{$wpdb->posts}` (ID, post_type) VALUES (1, 'fr_item'), (2, 'fr_item'), (3, 'fr_item')" ); $wpdb->query( 'INSERT INTO `' . self::TABLE . '` (post_id, fr_price) VALUES (1, 10), (2, 20), (3, 30)' ); $GLOBALS['_wp_options'] = array(); $GLOBALS['_wp_cache'] = array(); $GLOBALS['_wp_last_changed'] = array(); $GLOBALS['_wp_is_admin'] = false; $GLOBALS['_wp_current_filter'] = ''; $GLOBALS['_wp_post_types'] = array( 1 => 'fr_item', 2 => 'fr_item', 3 => 'fr_item' ); $ref = new ReflectionProperty( WPDO_Schema_Manager::class, 'table_exists_cache' ); $ref->setAccessible( true ); $ref->setValue( null, array() ); $mode = new ReflectionProperty( WPDO_Mode_Manager::class, 'cache' ); $mode->setAccessible( true ); $mode->setValue( null, array( 'post' => 'aeav_only', 'user' => 'disabled', 'term' => 'disabled', 'comment' => 'disabled' ) ); TMDO_Post_Query_Router::flush_copy_cache(); WPDO_Entity_Registry::init(); WPDO_Entity_Registry::register_adapter( 'post', new WPDO_Adapter_Post() ); WPDO_Entity_Registry::register_group( 'post', 'fr_core', array( array( 'key' => 'fr_price', 'type' => 'decimal' ) ), array( 'post_types' => array( 'fr_item' ) ) ); } protected function tearDown(): void { self::drop(); WPDO_Entity_Registry::init(); $mode = new ReflectionProperty( WPDO_Mode_Manager::class, 'cache' ); $mode->setAccessible( true ); $mode->setValue( null, null ); } private static function drop(): void { global $wpdb; foreach ( array( $wpdb->posts, self::TABLE ) as $table ) { $wpdb->query( "DROP TABLE IF EXISTS `{$table}`" ); } } /** A routed query plus the SQL WordPress would build for it (page size 1). */ private function routed(): array { global $wpdb; $query = new WP_Query(); $query->set( 'post_type', 'fr_item' ); $query->set( 'post_status', 'publish' ); $query->set( 'meta_query', array( array( 'key' => 'fr_price', 'value' => 15, 'compare' => '>=' ) ) ); $router = new TMDO_Post_Query_Router(); $router->pre_get_posts( $query ); $request = "SELECT SQL_CALC_FOUND_ROWS {$wpdb->posts}.ID FROM {$wpdb->posts} " . $router->posts_join( '', $query ) . " WHERE 1=1 AND {$wpdb->posts}.post_type = 'fr_item' AND (({$wpdb->posts}.post_status = 'publish'))" . $router->posts_where( '', $query ) . " GROUP BY {$wpdb->posts}.ID ORDER BY {$wpdb->posts}.post_date DESC LIMIT 0, 1"; return array( $router, $query, $request ); } public function test_routed_request_drops_sql_calc_found_rows(): void { list( $router, $query, $request ) = $this->routed(); $sql = $router->posts_request( $request, $query ); $this->assertStringNotContainsString( 'SQL_CALC_FOUND_ROWS', $sql ); $this->assertStringContainsString( 'LIMIT 0, 1', $sql ); } public function test_unrouted_request_is_left_alone(): void { $router = new TMDO_Post_Query_Router(); $request = 'SELECT SQL_CALC_FOUND_ROWS wp_itest_posts.ID FROM wp_itest_posts WHERE 1=1 LIMIT 0, 10'; $this->assertSame( $request, $router->posts_request( $request, new WP_Query() ) ); $this->assertSame( 'SELECT FOUND_ROWS()', $router->found_posts_query( 'SELECT FOUND_ROWS()', new WP_Query() ) ); } public function test_total_is_counted_once_and_served_from_cache_until_posts_change(): void { global $wpdb; list( $router, $query, $request ) = $this->routed(); $router->posts_request( $request, $query ); $this->assertSame( '2', $wpdb->get_var( $router->found_posts_query( 'SELECT FOUND_ROWS()', $query ) ) ); $wpdb->query( 'UPDATE `' . self::TABLE . '` SET fr_price = 5 WHERE post_id = 2' ); $this->assertSame( '2', $wpdb->get_var( $router->found_posts_query( 'SELECT FOUND_ROWS()', $query ) ), 'cached' ); wp_cache_set_posts_last_changed(); $this->assertSame( '1', $wpdb->get_var( $router->found_posts_query( 'SELECT FOUND_ROWS()', $query ) ), 'recounted' ); } public function test_flat_writes_and_deletes_move_posts_last_changed(): void { $GLOBALS['_wp_current_filter'] = 'update_post_metadata'; $before = wp_cache_get_last_changed( 'posts' ); WPDO_Hook_Bus::intercept_update( null, 1, 'fr_price', '11', '' ); $after_write = wp_cache_get_last_changed( 'posts' ); $GLOBALS['_wp_current_filter'] = 'delete_post_metadata'; WPDO_Hook_Bus::intercept_delete( null, 1, 'fr_price', '', false ); $this->assertNotSame( $before, $after_write ); $this->assertNotSame( $after_write, wp_cache_get_last_changed( 'posts' ) ); } }