[HPOS] Fix regression in supporting nested date query arguments (#37827)

This commit is contained in:
Corey McKrill 2023-04-19 11:15:18 -07:00 committed by GitHub
commit 8ac3c29937
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 205 additions and 29 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Fix regression in supporting nested date query arguments in HPOS.

View File

@ -270,15 +270,6 @@ class OrdersTableQuery {
$this->args['meta_query'] = array( $shortcut_meta_query ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
}
}
// Date query.
if ( isset( $this->args['date_query'] ) && is_array( $this->args['date_query'] ) ) {
foreach ( $this->args['date_query'] as $index => $query ) {
if ( isset( $query['column'] ) && isset( $mapping[ $query['column'] ] ) ) {
$this->args['date_query'][ $index ]['column'] = $mapping[ $query['column'] ];
}
}
}
}
/**
@ -325,6 +316,11 @@ class OrdersTableQuery {
* @throws \Exception When date args are invalid.
*/
private function process_date_args(): void {
if ( $this->arg_isset( 'date_query' ) ) {
// Process already passed date queries args.
$this->args['date_query'] = $this->map_gmt_and_post_keys_to_hpos_keys( $this->args['date_query'] );
}
$valid_operators = array( '>', '>=', '=', '<=', '<', '...' );
$date_queries = array();
$local_to_gmt_date_keys = array(
@ -333,30 +329,13 @@ class OrdersTableQuery {
'date_paid' => 'date_paid_gmt',
'date_completed' => 'date_completed_gmt',
);
$gmt_date_keys = array_values( $local_to_gmt_date_keys );
$local_date_keys = array_keys( $local_to_gmt_date_keys );
$gmt_date_keys = array_values( $local_to_gmt_date_keys );
$local_date_keys = array_keys( $local_to_gmt_date_keys );
$valid_date_keys = array_merge( $gmt_date_keys, $local_date_keys );
$date_keys = array_filter( $valid_date_keys, array( $this, 'arg_isset' ) );
// Process already passed date queries args.
if ( $this->arg_isset( 'date_query' ) && is_array( $this->args['date_query'] ) ) {
foreach ( $this->args['date_query'] as $index => $query ) {
if ( ! isset( $query['column'] ) || ! in_array( $query['column'], $valid_date_keys, true ) ) {
unset( $this->args['date_query'][ $index ] );
continue;
}
// Convert any local dates to GMT.
if ( isset( $local_to_gmt_date_keys[ $query['column'] ] ) ) {
$this->args['date_query'][ $index ]['column'] = $local_to_gmt_date_keys[ $query['column'] ];
$op = isset( $query['after'] ) ? 'after' : 'before';
$date_value_local = $query[ $op ];
$date_value_gmt = wc_string_to_timestamp( get_gmt_from_date( wc_string_to_datetime( $date_value_local ) ) );
$this->args['date_query'][ $index ][ $op ] = $this->date_to_date_query_arg( $date_value_gmt, 'UTC' );
}
}
}
foreach ( $date_keys as $date_key ) {
$date_value = $this->args[ $date_key ];
$operator = '=';
@ -430,6 +409,63 @@ class OrdersTableQuery {
$this->process_date_query_columns();
}
/**
* Helper function to map posts and gmt based keys to HPOS keys.
*
* @param array $query Date query argument.
*
* @return array|mixed Date query argument with modified keys.
*/
private function map_gmt_and_post_keys_to_hpos_keys( $query ) {
if ( ! is_array( $query ) ) {
return $query;
}
$post_to_hpos_mappings = array(
'post_date' => 'date_created',
'post_date_gmt' => 'date_created_gmt',
'post_modified' => 'date_updated',
'post_modified_gmt' => 'date_updated_gmt',
'_date_completed' => 'date_completed',
'_date_paid' => 'date_paid',
'date_modified' => 'date_updated',
'date_modified_gmt' => 'date_updated_gmt',
);
$local_to_gmt_date_keys = array(
'date_created' => 'date_created_gmt',
'date_updated' => 'date_updated_gmt',
'date_paid' => 'date_paid_gmt',
'date_completed' => 'date_completed_gmt',
);
array_walk(
$query,
function ( &$sub_query ) {
$sub_query = $this->map_gmt_and_post_keys_to_hpos_keys( $sub_query );
}
);
if ( ! isset( $query['column'] ) ) {
return $query;
}
if ( isset( $post_to_hpos_mappings[ $query['column'] ] ) ) {
$query['column'] = $post_to_hpos_mappings[ $query['column'] ];
}
// Convert any local dates to GMT.
if ( isset( $local_to_gmt_date_keys[ $query['column'] ] ) ) {
$query['column'] = $local_to_gmt_date_keys[ $query['column'] ];
$op = isset( $query['after'] ) ? 'after' : 'before';
$date_value_local = $query[ $op ];
$date_value_gmt = wc_string_to_timestamp( get_gmt_from_date( wc_string_to_datetime( $date_value_local ) ) );
$query[ $op ] = $this->date_to_date_query_arg( $date_value_gmt, 'UTC' );
}
return $query;
}
/**
* Makes sure all 'date_query' columns are correctly prefixed and their respective tables are being JOIN'ed.
*

View File

@ -0,0 +1,136 @@
<?php
use Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper;
use Automattic\WooCommerce\RestApi\UnitTests\HPOSToggleTrait;
use Automattic\WooCommerce\Utilities\OrderUtil;
/**
* Class OrdersTableQueryTests.
*/
class OrdersTableQueryTests extends WC_Unit_Test_Case {
use HPOSToggleTrait;
/**
* Stores the original COT state.
*
* @var bool
*/
private $cot_state;
/**
* Setup - enable COT.
*/
public function setUp(): void {
parent::setUp();
$this->setup_cot();
$this->cot_state = OrderUtil::custom_orders_table_usage_is_enabled();
$this->toggle_cot( true );
}
/**
* Restore the original COT state.
*/
public function tearDown(): void {
$this->toggle_cot( $this->cot_state );
parent::tearDown();
}
/**
* Helper function to create different orders with different dates for testing.
*
* @return array Array of WC_Order objects.
*/
private function create_orders_with_different_dates() {
$order1 = OrderHelper::create_order();
$order2 = OrderHelper::create_order();
$order3 = OrderHelper::create_order();
$order1->set_date_created( '2000-01-01T10:00:00' );
$order1->set_date_modified( '2001-02-01T10:00:00' );
$order1->set_date_paid( '2002-03-01T10:00:00' );
$order1->save();
$order2->set_date_created( '2000-02-01T10:00:00' );
$order2->set_date_modified( '2001-01-01T10:00:00' );
$order2->set_date_paid( '2002-03-01T10:00:00' );
$order2->save();
$order3->set_date_created( '2001-01-01T10:00:00' );
$order3->set_date_modified( '2001-02-01T10:00:00' );
$order3->set_date_paid( '2002-03-01T10:00:00' );
$order3->save();
return array( $order1, $order2, $order3 );
}
/**
* @testDox Nested date queries works as expected.
*/
public function test_nested_date_queries_single() {
$orders = $this->create_orders_with_different_dates();
$date_query_created_in_2000 = array(
array(
'relation' => 'AND',
array(
'column' => 'date_created',
'inclusive' => true,
'after' => '2000-01-01T00:00:00',
),
array(
'column' => 'date_created',
'inclusive' => false,
'before' => '2001-01-01T10:00:00',
),
),
);
$queried_orders = wc_get_orders(
array(
'return' => 'ids',
'date_query' => $date_query_created_in_2000,
)
);
$this->assertEquals( 2, count( $queried_orders ) );
$this->assertContains( $orders[0]->get_id(), $queried_orders );
$this->assertContains( $orders[1]->get_id(), $queried_orders );
}
/**
* @testDox Multiple nested date queries works as expected.
*/
public function test_nested_date_queries_multi() {
$orders = $this->create_orders_with_different_dates();
$date_query_created_in_2000_and_modified_in_2001 = array(
array(
'relation' => 'AND',
array(
'column' => 'date_created',
'inclusive' => true,
'after' => '2000-01-01T00:00:00',
),
array(
'column' => 'post_date',
'inclusive' => false,
'before' => '2001-01-01T10:00:00',
),
),
array(
'column' => 'date_modified',
'before' => '2001-01-02T10:00:00',
),
);
$queried_orders = wc_get_orders(
array(
'return' => 'ids',
'date_query' => $date_query_created_in_2000_and_modified_in_2001,
)
);
$this->assertEquals( 1, count( $queried_orders ) );
$this->assertContains( $orders[1]->get_id(), $queried_orders );
}
}