Fix/34271 unlimited results (#34289)

Support for unlimited ('-1') results in COT queries.
This commit is contained in:
Barry Hughes 2022-08-12 08:22:32 -07:00 committed by GitHub
parent 4693e251f7
commit 1a4060d689
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 6 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Ensure COT order queries respect unlimited ('-1') as a pagination limit.

View File

@ -12,6 +12,12 @@ defined( 'ABSPATH' ) || exit;
/** /**
* This class provides a `WP_Query`-like interface to custom order tables. * This class provides a `WP_Query`-like interface to custom order tables.
*
* @property-read int $found_orders Number of found orders.
* @property-read int $found_posts Alias of the `$found_orders` property.
* @property-read int $max_num_pages Max number of pages matching the current query.
* @property-read array $orders Order objects, or order IDs.
* @property-read array $posts Alias of the $orders property.
*/ */
class OrdersTableQuery { class OrdersTableQuery {
@ -25,6 +31,13 @@ class OrdersTableQuery {
*/ */
public const REGEX_SHORTHAND_DATES = '/([^.<>]*)(>=|<=|>|<|\.\.\.)([^.<>]+)/'; public const REGEX_SHORTHAND_DATES = '/([^.<>]*)(>=|<=|>|<|\.\.\.)([^.<>]+)/';
/**
* Highest possible unsigned bigint value (unsigned bigints being the type of the `id` column).
*
* This is deliberately held as a string, rather than a numeric type, for inclusion within queries.
*/
private const MYSQL_MAX_UNSIGNED_BIGINT = '18446744073709551615';
/** /**
* Names of all COT tables (orders, addresses, operational_data, meta) in the form 'table_id' => 'table name'. * Names of all COT tables (orders, addresses, operational_data, meta) in the form 'table_id' => 'table name'.
* *
@ -562,7 +575,13 @@ class OrdersTableQuery {
$orderby = $this->orderby ? ( 'ORDER BY ' . implode( ', ', $this->orderby ) ) : ''; $orderby = $this->orderby ? ( 'ORDER BY ' . implode( ', ', $this->orderby ) ) : '';
// LIMITS. // LIMITS.
$limits = $this->limits ? 'LIMIT ' . implode( ',', $this->limits ) : ''; $limits = '';
if ( ! empty( $this->limits ) && count( $this->limits ) === 2 ) {
list( $offset, $row_count ) = $this->limits;
$row_count = $row_count === -1 ? self::MYSQL_MAX_UNSIGNED_BIGINT : (int) $row_count;
$limits = 'LIMIT ' . (int) $offset . ', ' . $row_count;
}
// GROUP BY. // GROUP BY.
$groupby = $this->groupby ? 'GROUP BY ' . implode( ', ', (array) $this->groupby ) : ''; $groupby = $this->groupby ? 'GROUP BY ' . implode( ', ', (array) $this->groupby ) : '';
@ -876,15 +895,20 @@ class OrdersTableQuery {
* @return void * @return void
*/ */
private function process_limit(): void { private function process_limit(): void {
$limit = ( $this->arg_isset( 'limit' ) ? absint( $this->args['limit'] ) : false ); $row_count = ( $this->arg_isset( 'limit' ) ? (int) $this->args['limit'] : false );
$page = ( $this->arg_isset( 'page' ) ? absint( $this->args['page'] ) : 1 ); $page = ( $this->arg_isset( 'page' ) ? absint( $this->args['page'] ) : 1 );
$offset = ( $this->arg_isset( 'offset' ) ? absint( $this->args['offset'] ) : false ); $offset = ( $this->arg_isset( 'offset' ) ? absint( $this->args['offset'] ) : false );
if ( ! $limit ) { // Bool false indicates no limit was specified; less than -1 means an invalid value was passed (such as -3).
if ( $row_count === false || $row_count < -1 ) {
return; return;
} }
$this->limits = array( $offset ? $offset : absint( ( $page - 1 ) * $limit ), $limit ); if ( $offset === false && $row_count > -1 ) {
$offset = (int) ( ( $page - 1 ) * $row_count );
}
$this->limits = array( $offset, $row_count );
} }
/** /**

View File

@ -790,6 +790,54 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case {
$this->assertCount( 6, $query->orders ); $this->assertCount( 6, $query->orders );
} }
/**
* @testdox Test pagination works for COT queries.
*
* @return void
*/
public function test_cot_query_pagination(): void {
$test_orders = array();
$this->assertEquals( 0, ( new OrdersTableQuery() )->found_orders, 'We initially have zero orders within our custom order tables.' );
for ( $i = 0; $i < 30; $i++ ) {
$order = new WC_Order();
$this->switch_data_store( $order, $this->sut );
$order->save();
$test_orders[] = $order->get_id();
}
$query = new OrdersTableQuery();
$this->assertCount( 30, $query->orders, 'If no limits are specified, we fetch all available orders.' );
$query = new OrdersTableQuery( array( 'limit' => -1 ) );
$this->assertCount( 30, $query->orders, 'A limit of -1 is equivalent to requesting all available orders.' );
$query = new OrdersTableQuery( array( 'limit' => -10 ) );
$this->assertCount( 30, $query->orders, 'An invalid limit is treated as a request for all available orders.' );
$query = new OrdersTableQuery(
array(
'limit' => -1,
'offset' => 18,
)
);
$this->assertCount( 12, $query->orders, 'A limit of -1 can successfully be combined with an offset.' );
$this->assertEquals( array_slice( $test_orders, 18 ), $query->orders, 'The expected dataset is supplied when an offset is combined with a limit of -1.' );
$query = new OrdersTableQuery( array( 'limit' => 5 ) );
$this->assertCount( 5, $query->orders, 'Limits are respected when applied.' );
$query = new OrdersTableQuery(
array(
'limit' => 5,
'paged' => 2,
'return' => 'ids',
)
);
$this->assertCount( 5, $query->orders, 'Pagination works with specified limit.' );
$this->assertEquals( array_slice( $test_orders, 5, 5 ), $query->orders, 'The expected dataset is supplied when paginating through orders.' );
}
/** /**
* Helper function to delete all meta for post. * Helper function to delete all meta for post.
* *