Make WordPress Core


Ignore:
Timestamp:
10/13/2014 10:02:18 PM (9 years ago)
Author:
boonebgorges
Message:

Introduce support for nested queries in WP_Meta_Query.

Previously, meta query arguments could be joined by a single AND or OR relation.
Now, these queries can be arbitrarily nested, allowing clauses to be linked
together with multiple relations.

Adds unit tests for the new nesting syntax. Modifies a few existing unit tests
that were overly specific for the old SQL syntax. Backward compatibility with
existing syntax is fully maintained.

Props boonebgorges, DrewAPicture.
See #29642.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/meta/query.php

    r29799 r29887  
    4141        ) );
    4242
    43         $this->assertSame( array( array() ), $query->queries );
     43        $this->assertSame( array(), $query->queries );
    4444    }
    4545
     
    154154
    155155        // just meta_value
    156         $query->parse_query_vars( array( 'meta_key' => 'abc' ) );
    157 
    158         $this->assertEquals( array( array( 'key' => 'abc' ) ), $query->queries );
     156        $expected = array(
     157            'relation' => 'OR',
     158            array(
     159                'key' => 'abc',
     160            ),
     161        );
     162        $query->parse_query_vars( array(
     163            'meta_key' => 'abc',
     164        ) );
     165        $this->assertEquals( $expected, $query->queries );
    159166
    160167        // meta_key & meta_value
    161         $query->parse_query_vars( array( 'meta_key' => 'abc', 'meta_value' => 'def' ) );
    162 
    163         $this->assertEquals( array( array( 'key' => 'abc', 'value' => 'def' ) ), $query->queries );
     168        $expected = array(
     169            'relation' => 'OR',
     170            array(
     171                'key' => 'abc',
     172                'value' => 'def',
     173            ),
     174        );
     175        $query->parse_query_vars( array(
     176            'meta_key' => 'abc',
     177            'meta_value' => 'def',
     178        ) );
     179        $this->assertEquals( $expected, $query->queries );
    164180
    165181        // meta_compare
    166         $query->parse_query_vars( array( 'meta_key' => 'abc', 'meta_compare' => '=>' ) );
    167 
    168         $this->assertEquals( array( array( 'key' => 'abc', 'compare' => '=>' ) ), $query->queries );
     182        $expected = array(
     183            'relation' => 'OR',
     184            array(
     185                'key' => 'abc',
     186                'compare' => '=>',
     187            ),
     188        );
     189        $query->parse_query_vars( array(
     190            'meta_key' => 'abc',
     191            'meta_compare' => '=>',
     192        ) );
     193        $this->assertEquals( $expected, $query->queries );
    169194    }
    170195
     
    203228    }
    204229
     230    public function test_sanitize_query_single_query() {
     231        $expected = array(
     232            'relation' => 'OR',
     233            array(
     234                'key' => 'foo',
     235                'value' => 'bar',
     236            ),
     237        );
     238
     239        $q = new WP_Meta_Query();
     240        $found = $q->sanitize_query( array(
     241            array(
     242                'key' => 'foo',
     243                'value' => 'bar',
     244            ),
     245        ) );
     246
     247        $this->assertEquals( $expected, $found );
     248    }
     249
     250    public function test_sanitize_query_multiple_first_order_queries_relation_default() {
     251        $expected = array(
     252            'relation' => 'AND',
     253            array(
     254                'key' => 'foo',
     255                'value' => 'bar',
     256            ),
     257            array(
     258                'key' => 'foo2',
     259                'value' => 'bar2',
     260            ),
     261        );
     262
     263        $q = new WP_Meta_Query();
     264        $found = $q->sanitize_query( array(
     265            array(
     266                'key' => 'foo',
     267                'value' => 'bar',
     268            ),
     269            array(
     270                'key' => 'foo2',
     271                'value' => 'bar2',
     272            ),
     273        ) );
     274
     275        $this->assertEquals( $expected, $found );
     276    }
     277
     278    public function test_sanitize_query_multiple_first_order_queries_relation_or() {
     279        $expected = array(
     280            'relation' => 'OR',
     281            array(
     282                'key' => 'foo',
     283                'value' => 'bar',
     284            ),
     285            array(
     286                'key' => 'foo2',
     287                'value' => 'bar2',
     288            ),
     289        );
     290
     291        $q = new WP_Meta_Query();
     292        $found = $q->sanitize_query( array(
     293            'relation' => 'OR',
     294            array(
     295                'key' => 'foo',
     296                'value' => 'bar',
     297            ),
     298            array(
     299                'key' => 'foo2',
     300                'value' => 'bar2',
     301            ),
     302        ) );
     303
     304        $this->assertEquals( $expected, $found );
     305    }
     306
     307    public function test_sanitize_query_multiple_first_order_queries_relation_or_lowercase() {
     308        $expected = array(
     309            'relation' => 'OR',
     310            array(
     311                'key' => 'foo',
     312                'value' => 'bar',
     313            ),
     314            array(
     315                'key' => 'foo2',
     316                'value' => 'bar2',
     317            ),
     318        );
     319
     320        $q = new WP_Meta_Query();
     321        $found = $q->sanitize_query( array(
     322            'relation' => 'or',
     323            array(
     324                'key' => 'foo',
     325                'value' => 'bar',
     326            ),
     327            array(
     328                'key' => 'foo2',
     329                'value' => 'bar2',
     330            ),
     331        ) );
     332
     333        $this->assertEquals( $expected, $found );
     334    }
     335
     336    public function test_sanitize_query_multiple_first_order_queries_invalid_relation() {
     337        $expected = array(
     338            'relation' => 'AND',
     339            array(
     340                'key' => 'foo',
     341                'value' => 'bar',
     342            ),
     343            array(
     344                'key' => 'foo2',
     345                'value' => 'bar2',
     346            ),
     347        );
     348
     349        $q = new WP_Meta_Query();
     350        $found = $q->sanitize_query( array(
     351            'relation' => 'FOO',
     352            array(
     353                'key' => 'foo',
     354                'value' => 'bar',
     355            ),
     356            array(
     357                'key' => 'foo2',
     358                'value' => 'bar2',
     359            ),
     360        ) );
     361
     362        $this->assertEquals( $expected, $found );
     363    }
     364
     365    public function test_sanitize_query_single_query_which_is_a_nested_query() {
     366        $expected = array(
     367            'relation' => 'OR',
     368            array(
     369                'relation' => 'AND',
     370                array(
     371                    'key' => 'foo',
     372                    'value' => 'bar',
     373                ),
     374                array(
     375                    'key' => 'foo2',
     376                    'value' => 'bar2',
     377                ),
     378            )
     379        );
     380
     381        $q = new WP_Meta_Query();
     382        $found = $q->sanitize_query( array(
     383            array(
     384                array(
     385                    'key' => 'foo',
     386                    'value' => 'bar',
     387                ),
     388                array(
     389                    'key' => 'foo2',
     390                    'value' => 'bar2',
     391                ),
     392            ),
     393        ) );
     394
     395        $this->assertEquals( $expected, $found );
     396    }
     397
     398    public function test_sanitize_query_multiple_nested_queries() {
     399        $expected = array(
     400            'relation' => 'OR',
     401            array(
     402                'relation' => 'AND',
     403                array(
     404                    'key' => 'foo',
     405                    'value' => 'bar',
     406                ),
     407                array(
     408                    'key' => 'foo2',
     409                    'value' => 'bar2',
     410                ),
     411            ),
     412            array(
     413                'relation' => 'AND',
     414                array(
     415                    'key' => 'foo3',
     416                    'value' => 'bar3',
     417                ),
     418                array(
     419                    'key' => 'foo4',
     420                    'value' => 'bar4',
     421                ),
     422            ),
     423        );
     424
     425        $q = new WP_Meta_Query();
     426        $found = $q->sanitize_query( array(
     427            'relation' => 'OR',
     428            array(
     429                array(
     430                    'key' => 'foo',
     431                    'value' => 'bar',
     432                ),
     433                array(
     434                    'key' => 'foo2',
     435                    'value' => 'bar2',
     436                ),
     437            ),
     438            array(
     439                array(
     440                    'key' => 'foo3',
     441                    'value' => 'bar3',
     442                ),
     443                array(
     444                    'key' => 'foo4',
     445                    'value' => 'bar4',
     446                ),
     447            ),
     448        ) );
     449
     450        $this->assertEquals( $expected, $found );
     451    }
     452
    205453    /**
    206454     * Invalid $type will fail to get a table from _get_meta_table()
     
    230478
    231479        // We should have 2 joins - one for my_first_key and one for my_second_key
    232         $this->assertEquals( 2, substr_count( $sql['join'], 'INNER JOIN' ) );
     480        $this->assertEquals( 2, substr_count( $sql['join'], 'JOIN' ) );
    233481
    234482        // The WHERE should check my_third_key against an unaliased table
     
    248496        $sql = $query->get_sql( 'post', $wpdb->posts, 'ID', $this );
    249497
    250         $this->assertEquals( 1, substr_count( $sql['where'], "CAST($wpdb->postmeta.meta_value AS CHAR) = '')" ) );
     498        $this->assertEquals( 1, substr_count( $sql['where'], "CAST($wpdb->postmeta.meta_value AS CHAR) = ''" ) );
    251499    }
    252500
     
    559807
    560808        $sql = $query->get_sql( 'post', $wpdb->posts, 'ID', $this );
    561         $this->assertContains( "{$wpdb->postmeta}.meta_key = 'exclude'\nOR", $sql['where'] );
     809
     810        // Use regex because we don't care about the whitespace before OR.
     811        $this->assertRegExp( "/{$wpdb->postmeta}\.meta_key = \'exclude\'\s+OR/", $sql['where'] );
    562812        $this->assertNotContains( "{$wpdb->postmeta}.post_id IS NULL", $sql['where'] );
    563813    }
Note: See TracChangeset for help on using the changeset viewer.