diff --git a/CHANGELOG.md b/CHANGELOG.md index f2bb264..993a48f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ All notable changes to this project will be documented in this file. This project adhere to the [Semantic Versioning](http://semver.org/) standard. +## [3.2.0] 2026-01-05 + +* Feature - Add support for nested sub-WHERE clauses in `paginate()` and `get_total_items()` methods. This allows building complex queries like `WHERE (col1 = 'a' OR col2 = 'b') AND col3 = 'c'`. +* Feature - Add new `stellarwp_schema_custom_table_paginate_query` filter to allow modification of the paginate query before execution. +* Feature - Add new `stellarwp_schema_custom_table_total_items_query` filter to allow modification of the total items count query before execution. +* Tweak - Rename hooks from `tec_common_*` prefix to `stellarwp_schema_*` prefix for consistency with the StellarWP namespace. + +### Breaking Changes + +The following hooks have been renamed: +- `tec_common_custom_table_query_pre_results` → `stellarwp_schema_custom_table_query_pre_results` +- `tec_common_custom_table_query_post_results` → `stellarwp_schema_custom_table_query_post_results` +- `tec_common_custom_table_query_results` → `stellarwp_schema_custom_table_query_results` +- `tec_common_custom_table_query_where` → `stellarwp_schema_custom_table_query_where` + +[3.2.0]: https://github.com/stellarwp/schema/releases/tag/3.2.0 + ## [3.1.4] 2025-10-16 * Fix - Handle array values correctly in the `get_*` query methods. diff --git a/composer.json b/composer.json index 49be587..3cc3c5b 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "symfony/event-dispatcher-contracts": "^2.5.1", "symfony/string": "^5.4", "szepeviktor/phpstan-wordpress": "^1.1", - "php-stubs/wp-cli-stubs": "^2.11" + "php-stubs/wp-cli-stubs": "^2.11", + "lucatume/codeception-snapshot-assertions": "^0.5.0" }, "minimum-stability": "stable", "autoload": { diff --git a/composer.lock b/composer.lock index 2c9f40c..c5d2519 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4520621c62ecebc167f526b56e02c36f", + "content-hash": "f0a1786f04bcbc622161f202cbba9d18", "packages": [ { "name": "psr/container", @@ -2054,6 +2054,55 @@ }, "time": "2021-04-17T13:49:01+00:00" }, + { + "name": "gajus/dindent", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/gajus/dindent.git", + "reference": "d81c3a6f78fbe1ab26f5e753098bbbef6b6a9f3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/gajus/dindent/zipball/d81c3a6f78fbe1ab26f5e753098bbbef6b6a9f3c", + "reference": "d81c3a6f78fbe1ab26f5e753098bbbef6b6a9f3c", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "satooshi/php-coveralls": "dev-master" + }, + "type": "library", + "autoload": { + "psr-4": { + "Gajus\\Dindent\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Gajus Kuizinas", + "email": "gk@anuary.com" + } + ], + "description": "HTML indentation library for development and testing.", + "homepage": "https://github.com/gajus/dindent", + "keywords": [ + "format", + "html", + "indent" + ], + "support": { + "issues": "https://github.com/gajus/dindent/issues", + "source": "https://github.com/gajus/dindent/tree/master" + }, + "time": "2014-10-08T10:03:04+00:00" + }, { "name": "gettext/gettext", "version": "v4.8.12", @@ -3041,6 +3090,51 @@ ], "time": "2024-09-21T08:32:55+00:00" }, + { + "name": "lucatume/codeception-snapshot-assertions", + "version": "0.5.0", + "source": { + "type": "git", + "url": "https://github.com/lucatume/codeception-snapshot-assertions.git", + "reference": "4583b0e9337d0ddd82d82710e4467b06f2915ba9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lucatume/codeception-snapshot-assertions/zipball/4583b0e9337d0ddd82d82710e4467b06f2915ba9", + "reference": "4583b0e9337d0ddd82d82710e4467b06f2915ba9", + "shasum": "" + }, + "require": { + "codeception/codeception": "^4.0", + "ext-dom": "*", + "gajus/dindent": "^2.0" + }, + "require-dev": { + "squizlabs/php_codesniffer": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "tad\\Codeception\\SnapshotAssertions\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "theAverageDev (Luca Tumedei)", + "email": "luca@theaveragedev.com" + } + ], + "description": "Snapshot assertions sugar for Codeception.", + "support": { + "issues": "https://github.com/lucatume/codeception-snapshot-assertions/issues", + "source": "https://github.com/lucatume/codeception-snapshot-assertions/tree/0.5.0" + }, + "time": "2025-07-01T07:40:18+00:00" + }, { "name": "lucatume/di52", "version": "4.0.1", diff --git a/docs/query-methods.md b/docs/query-methods.md index 3b2e9a7..fdfb4b5 100644 --- a/docs/query-methods.md +++ b/docs/query-methods.md @@ -271,7 +271,7 @@ $args = [ 'orderby' => 'created_at', // Column to sort by. 'order' => 'DESC', // ASC or DESC. 'offset' => 0, // Starting offset. - 'query_operator' => 'AND', // AND or OR. + 'query_operator' => 'AND', // AND or OR for top-level conditions. // Column filters. [ @@ -284,6 +284,21 @@ $args = [ 'value' => 1000, 'operator' => '<', ], + + // Sub-WHERE clauses (v3.2.0+) - group conditions with their own operator. + [ + 'query_operator' => 'OR', // Operator for this group. + [ + 'column' => 'type', + 'value' => 'classic', + 'operator' => '=', + ], + [ + 'column' => 'type', + 'value' => 'premium', + 'operator' => '=', + ], + ], ]; ``` @@ -321,6 +336,33 @@ $results = Sandwiches::paginate( 1 ); +// Sub-WHERE clauses (v3.2.0+). +// Query: WHERE (type = 'classic' OR type = 'premium') AND price_cents < 1500 +$results = Sandwiches::paginate( + [ + [ + 'query_operator' => 'OR', + [ + 'column' => 'type', + 'value' => 'classic', + 'operator' => '=', + ], + [ + 'column' => 'type', + 'value' => 'premium', + 'operator' => '=', + ], + ], + [ + 'column' => 'price_cents', + 'value' => 1500, + 'operator' => '<', + ], + ], + 20, + 1 +); + // With JOIN. $results = Sandwiches::paginate( $args, @@ -498,28 +540,46 @@ Query methods provide hooks for customization: ```php // Before query execution. -add_action( 'tec_common_custom_table_query_pre_results', function( $args, $class ) { +add_action( 'stellarwp_schema_custom_table_query_pre_results', function( $args, $class ) { // Modify args, log, etc. }, 10, 2 ); // After query execution. -add_action( 'tec_common_custom_table_query_post_results', function( $results, $args, $class ) { +add_action( 'stellarwp_schema_custom_table_query_post_results', function( $results, $args, $class ) { // Log, analyze, etc. }, 10, 3 ); // Filter results. -add_filter( 'tec_common_custom_table_query_results', function( $results, $args, $class ) { +add_filter( 'stellarwp_schema_custom_table_query_results', function( $results, $args, $class ) { // Modify results. return $results; }, 10, 3 ); // Filter WHERE clause. -add_filter( 'tec_common_custom_table_query_where', function( $where, $args, $class ) { +add_filter( 'stellarwp_schema_custom_table_query_where', function( $where, $args, $class ) { // Add custom WHERE conditions. return $where; }, 10, 3 ); + +// Filter the paginate query before execution (v3.2.0+). +add_filter( 'stellarwp_schema_custom_table_paginate_query', function( $query ) { + // Modify the SQL query string before execution. + // Useful for debugging, logging, or query modifications. + error_log( "Paginate query: {$query}" ); + return $query; +} ); + +// Filter the total items count query before execution (v3.2.0+). +add_filter( 'stellarwp_schema_custom_table_total_items_query', function( $query ) { + // Modify the SQL count query string before execution. + // Useful for debugging, logging, or query modifications. + error_log( "Total items query: {$query}" ); + return $query; +} ); ``` +> **Note (v3.2.0):** The hook names were changed from `tec_common_*` prefix to `stellarwp_schema_*` prefix. If you're upgrading from an earlier version, update your hook callbacks accordingly. + ## Performance Tips 1. **Batch Operations**: Use `insert_many()` and `update_many()` for bulk operations @@ -533,4 +593,4 @@ add_filter( 'tec_common_custom_table_query_where', function( $where, $args, $cla - [Column System](columns.md) - [Index System](indexes.md) - [Table Schemas](schemas-table.md) -- [Migrating from v2 to v3](migrating-from-v2-to-v3.md) \ No newline at end of file +- [Migrating from v2 to v3](migrating-from-v2-to-v3.md) diff --git a/src/Schema/Traits/Custom_Table_Query_Methods.php b/src/Schema/Traits/Custom_Table_Query_Methods.php index 095c065..4e88682 100644 --- a/src/Schema/Traits/Custom_Table_Query_Methods.php +++ b/src/Schema/Traits/Custom_Table_Query_Methods.php @@ -324,12 +324,26 @@ public static function get_total_items( array $args = [] ): int { $database = Config::get_db(); $where = static::build_where_from_args( $args ); - return (int) $database::get_var( + /** + * Filters the query used to get the total number of items in the table. + * + * @since 3.2.0 + * + * @param string $query The query to use. + * @param array $args The query arguments. + * @param string $where The WHERE clause to use. + */ + $query = apply_filters( + 'stellarwp_schema_custom_table_total_items_query', $database::prepare( "SELECT COUNT(*) FROM %i a {$where}", static::table_name( true ) - ) + ), + $args, + $where, ); + + return (int) $database::get_var( $query ); } /** @@ -468,17 +482,47 @@ public static function paginate( array $args, int $per_page = 20, int $page = 1, * @param array $args The query arguments. * @param class-string $class The class name. */ - do_action( 'tec_common_custom_table_query_pre_results', $args, static::class ); + do_action( 'stellarwp_schema_custom_table_query_pre_results', $args, static::class ); $database = Config::get_db(); - $results = $database::get_results( + /** + * Filters the query used to paginate the results. + * + * @since 3.2.0 + * + * @param string $query The query to use. + * @param array $args The query arguments. + * @param int $per_page The number of items to display per page. + * @param int $page The current page number. + * @param array $columns The columns to select. + * @param string $join_table The table to join. + * @param string $join_condition The condition to join on. + * @param array $selectable_joined_columns The columns from the joined table to select. + * @param int $offset The offset to use. + * @param string $where The WHERE clause to use. + */ + $query = apply_filters( + 'stellarwp_schema_custom_table_paginate_query', $database::prepare( "SELECT {$formatted_columns}{$secondary_columns} FROM %i a {$join} {$where} ORDER BY a.{$orderby} {$order} LIMIT %d, %d", static::table_name( true ), $offset, $per_page ), + $args, + $per_page, + $page, + $columns, + $join_table, + $join_condition, + $selectable_joined_columns, + $offset, + $where, + ); + + $results = $database::get_results( + $query, ARRAY_A ); @@ -498,7 +542,7 @@ public static function paginate( array $args, int $per_page = 20, int $page = 1, * @param array $args The query arguments. * @param class-string $class The class name. */ - do_action( 'tec_common_custom_table_query_post_results', $results, $args, static::class ); + do_action( 'stellarwp_schema_custom_table_query_post_results', $results, $args, static::class ); /** * Filters the results of the query. @@ -509,13 +553,14 @@ public static function paginate( array $args, int $per_page = 20, int $page = 1, * @param array $args The query arguments. * @param class-string $class The class name. */ - return apply_filters( 'tec_common_custom_table_query_results', $results, $args, static::class ); + return apply_filters( 'stellarwp_schema_custom_table_query_results', $results, $args, static::class ); } /** * Builds a WHERE clause from the provided arguments. * * @since 3.0.0 + * @since 3.2.0 Now sub where clauses are supported. * * @param array $args The query arguments. * @@ -552,12 +597,61 @@ protected static function build_where_from_args( array $args = [] ): string { $columns = static::get_columns()->get_names(); + $sub_wheres = self::build_sub_wheres_from_args( + array_filter( $args, 'is_array' ), + $columns, + $joined_prefix + ); + + $where = array_merge( $where, $sub_wheres ); + + /** + * Filters the WHERE clause. + * + * @since 3.0.0 + * + * @param array $where The WHERE clause parts. + * @param array $args The query arguments. + * @param class-string $class The class name. + */ + $where = apply_filters( 'stellarwp_schema_custom_table_query_where', array_filter( $where ), $args, static::class ); + + if ( empty( $where ) ) { + return ''; + } + + return 'WHERE ' . implode( " {$query_operator} ", $where ); + } + + /** + * Builds the sub WHERE clauses from the provided arguments. + * + * @since 3.2.0 + * + * @param array $args The query arguments. + * @param array $columns The columns to select. + * @param string $joined_prefix The prefix to use for the joined columns. + * + * @return array The sub WHERE clauses. + */ + private static function build_sub_wheres_from_args( array $args = [], array $columns = [], string $joined_prefix = '' ): array { + $sub_wheres = []; + foreach ( $args as $arg ) { if ( ! is_array( $arg ) ) { continue; } if ( empty( $arg['column'] ) ) { + $check_for_sub_query = array_filter( array_values( $arg ), static fn( $value ) => ! empty( $value['column'] ) ); + if ( ! empty( $check_for_sub_query ) ) { + $sub_wheres[] = [ + 'queries' => self::build_sub_wheres_from_args( $arg, $columns, $joined_prefix ), + 'operator' => ! empty( $arg['query_operator'] ) && in_array( strtoupper( $arg['query_operator'] ), [ 'AND', 'OR' ], true ) ? strtoupper( $arg['query_operator'] ) : 'AND', + ]; + } else { + _doing_it_wrong( __METHOD__, 'A sub where clause must contain a column.', '3.2.0' ); + } continue; } @@ -589,34 +683,38 @@ protected static function build_where_from_args( array $args = [] ): string { $query = "{$joined_prefix}{$column} {$operator} {$placeholder}"; if ( is_array( $value ) ) { - $where[] = $database::prepare( $query, ...$value ); + $sub_wheres[] = $database::prepare( $query, ...$value ); continue; } if ( 'NULL' === $placeholder ) { - $where[] = $query; + $sub_wheres[] = $query; continue; } - $where[] = $database::prepare( $query, $value ); + $sub_wheres[] = $database::prepare( $query, $value ); } - /** - * Filters the WHERE clause. - * - * @since 3.0.0 - * - * @param array $where The WHERE clause parts. - * @param array $args The query arguments. - * @param class-string $class The class name. - */ - $where = apply_filters( 'tec_common_custom_table_query_where', array_filter( $where ), $args, static::class ); - - if ( empty( $where ) ) { - return ''; - } - - return 'WHERE ' . implode( " {$query_operator} ", $where ); + return array_filter( + array_map( + static function ( $sub_where ) { + if ( ! is_array( $sub_where ) ) { + return $sub_where; + } + + if ( empty( $sub_where['queries'] ) ) { + return ''; + } + + if ( ! isset( $sub_where['operator'] ) || ! in_array( strtoupper( $sub_where['operator'] ), [ 'AND', 'OR' ], true ) ) { + $sub_where['operator'] = 'AND'; + } + + return '(' . implode( " {$sub_where['operator']} ", $sub_where['queries'] ) . ')'; + }, + $sub_wheres + ) + ); } /** diff --git a/tests/_support/Traits/Query_Snapshot_Assertions.php b/tests/_support/Traits/Query_Snapshot_Assertions.php new file mode 100644 index 0000000..b1e6e02 --- /dev/null +++ b/tests/_support/Traits/Query_Snapshot_Assertions.php @@ -0,0 +1,91 @@ +captured_query = ''; + + add_filter( 'stellarwp_schema_custom_table_paginate_query', function( $query ) { + $this->captured_query = $query; + return $query; + }, 10, 1 ); + + add_filter( 'stellarwp_schema_custom_table_total_items_query', function( $query ) { + $this->captured_query = $query; + return $query; + }, 10, 1 ); + } + + /** + * Tears down the query capture filter. + * + * @after + * + * @return void + */ + protected function tear_down_query_capture(): void { + $this->captured_query = ''; + + remove_all_filters( 'stellarwp_schema_custom_table_paginate_query' ); + remove_all_filters( 'stellarwp_schema_custom_table_total_items_query' ); + } + + /** + * Gets the captured query. + * + * @return string + */ + protected function get_captured_query(): string { + return $this->captured_query; + } + + /** + * Asserts that the captured query matches a stored snapshot. + * + * @return void + */ + protected function assertCapturedQueryMatchesSnapshot(): void { + $this->assertNotEmpty( $this->captured_query ); + $this->assertMatchesCodeSnapshot( $this->captured_query ); + } + + /** + * Asserts that the captured query contains the expected pattern. + * + * @param string $expected_pattern The expected pattern. + * @param string $message Optional message. + * + * @return void + */ + protected function assertQueryContains( string $expected_pattern, string $message = '' ): void { + $this->assertStringContainsString( + $expected_pattern, + $this->captured_query, + $message ?: 'Query does not contain expected pattern' + ); + } +} diff --git a/tests/wpunit/Traits/Custom_Table_Query_MethodsTest.php b/tests/wpunit/Traits/Custom_Table_Query_MethodsTest.php index 52d4276..bbbb003 100644 --- a/tests/wpunit/Traits/Custom_Table_Query_MethodsTest.php +++ b/tests/wpunit/Traits/Custom_Table_Query_MethodsTest.php @@ -5,6 +5,7 @@ use StellarWP\Schema\Register; use StellarWP\Schema\Tests\SchemaTestCase; use StellarWP\Schema\Tests\Traits\Table_Fixtures; +use StellarWP\Schema\Tests\Traits\Query_Snapshot_Assertions; use StellarWP\Schema\Columns\Integer_Column; use StellarWP\Schema\Columns\String_Column; use StellarWP\Schema\Columns\ID; @@ -16,6 +17,7 @@ class Custom_Table_Query_MethodsTest extends SchemaTestCase { use Table_Fixtures; + use Query_Snapshot_Assertions; /** * @before @@ -85,24 +87,18 @@ public function should_get_all_by_with_array_values() { 'status' => 1, ] ); - $id1 = DB::last_insert_id(); - $table::insert( [ 'name' => 'Test 2', 'slug' => 'test-2', 'status' => 1, ] ); - $id2 = DB::last_insert_id(); - $table::insert( [ 'name' => 'Test 3', 'slug' => 'test-3', 'status' => 0, ] ); - $id3 = DB::last_insert_id(); - // Get all by status using array (simulating IN operator scenario) $results = $table::get_all_by( 'status', [ 1, 0 ], 'IN' ); @@ -131,24 +127,18 @@ public function should_handle_empty_array() { 'status' => 1, ] ); - $id1 = DB::last_insert_id(); - $table::insert( [ 'name' => 'Test 2', 'slug' => 'test-2', 'status' => 1, ] ); - $id2 = DB::last_insert_id(); - $table::insert( [ 'name' => 'Test 3', 'slug' => 'test-3', 'status' => 0, ] ); - $id3 = DB::last_insert_id(); - $results = $table::get_all_by( 'status', [], 'IN' ); $this->assertEmpty( $results ); @@ -236,6 +226,806 @@ public function should_handle_scalar_values_in_queries() { $this->assertEquals( 'Scalar Test', $result['name'] ); } + /** + * @test + */ + public function should_paginate_with_simple_where_clause() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + // Insert test data + $table::insert( [ 'name' => 'Item 1', 'slug' => 'item-1', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Item 2', 'slug' => 'item-2', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Item 3', 'slug' => 'item-3', 'status' => 0 ] ); + $table::insert( [ 'name' => 'Item 4', 'slug' => 'item-4', 'status' => 1 ] ); + + // Query with simple where clause + $results = $table::paginate( + [ + [ + 'column' => 'status', + 'value' => 1, + 'operator' => '=', + ], + ], + 10, + 1 + ); + + $this->assertCount( 3, $results ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_paginate_with_sub_where_clauses_using_or() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + // Insert test data + $table::insert( [ 'name' => 'Alpha', 'slug' => 'alpha', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Beta', 'slug' => 'beta', 'status' => 0 ] ); + $table::insert( [ 'name' => 'Gamma', 'slug' => 'gamma', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Delta', 'slug' => 'delta', 'status' => 0 ] ); + + // Query: WHERE (slug = 'alpha' OR slug = 'beta') + $results = $table::paginate( + [ + [ + 'query_operator' => 'OR', + [ + 'column' => 'slug', + 'value' => 'alpha', + 'operator' => '=', + ], + [ + 'column' => 'slug', + 'value' => 'beta', + 'operator' => '=', + ], + ], + ], + 10, + 1 + ); + + $this->assertCount( 2, $results ); + $slugs = array_column( $results, 'slug' ); + $this->assertContains( 'alpha', $slugs ); + $this->assertContains( 'beta', $slugs ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_paginate_with_nested_sub_where_clauses() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + // Insert test data + $table::insert( [ 'name' => 'Active Alpha', 'slug' => 'alpha', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Inactive Alpha', 'slug' => 'alpha-inactive', 'status' => 0 ] ); + $table::insert( [ 'name' => 'Active Beta', 'slug' => 'beta', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Inactive Beta', 'slug' => 'beta-inactive', 'status' => 0 ] ); + $table::insert( [ 'name' => 'Active Gamma', 'slug' => 'gamma', 'status' => 1 ] ); + + // Query: WHERE (slug = 'alpha' OR slug = 'beta') AND status = 1 + $results = $table::paginate( + [ + [ + 'query_operator' => 'OR', + [ + 'column' => 'slug', + 'value' => 'alpha', + 'operator' => '=', + ], + [ + 'column' => 'slug', + 'value' => 'beta', + 'operator' => '=', + ], + ], + [ + 'column' => 'status', + 'value' => 1, + 'operator' => '=', + ], + ], + 10, + 1 + ); + + $this->assertCount( 2, $results ); + $slugs = array_column( $results, 'slug' ); + $this->assertContains( 'alpha', $slugs ); + $this->assertContains( 'beta', $slugs ); + + // Verify all results have status = 1 + foreach ( $results as $result ) { + $this->assertEquals( 1, $result['status'] ); + } + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_paginate_with_multiple_sub_where_groups() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + // Insert test data + $table::insert( [ 'name' => 'A', 'slug' => 'a', 'status' => 1 ] ); + $table::insert( [ 'name' => 'B', 'slug' => 'b', 'status' => 0 ] ); + $table::insert( [ 'name' => 'C', 'slug' => 'c', 'status' => 1 ] ); + $table::insert( [ 'name' => 'D', 'slug' => 'd', 'status' => 0 ] ); + + // Query with OR at the top level: WHERE (slug = 'a') OR (slug = 'b') + $results = $table::paginate( + [ + 'query_operator' => 'OR', + [ + 'column' => 'slug', + 'value' => 'a', + 'operator' => '=', + ], + [ + 'column' => 'slug', + 'value' => 'b', + 'operator' => '=', + ], + ], + 10, + 1 + ); + + $this->assertCount( 2, $results ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_count_total_items_with_sub_where_clauses() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + // Insert test data + $table::insert( [ 'name' => 'X', 'slug' => 'x', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Y', 'slug' => 'y', 'status' => 0 ] ); + $table::insert( [ 'name' => 'Z', 'slug' => 'z', 'status' => 1 ] ); + + // Count with sub-where: WHERE (slug = 'x' OR slug = 'y') + $total = $table::get_total_items( + [ + [ + 'query_operator' => 'OR', + [ + 'column' => 'slug', + 'value' => 'x', + 'operator' => '=', + ], + [ + 'column' => 'slug', + 'value' => 'y', + 'operator' => '=', + ], + ], + ] + ); + + $this->assertEquals( 2, $total ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_handle_sub_where_with_different_operators() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + // Insert test data + $table::insert( [ 'name' => 'First', 'slug' => 'first', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Second', 'slug' => 'second', 'status' => 2 ] ); + $table::insert( [ 'name' => 'Third', 'slug' => 'third', 'status' => 3 ] ); + $table::insert( [ 'name' => 'Fourth', 'slug' => 'fourth', 'status' => 4 ] ); + + // Query: WHERE (status > 1 AND status < 4) + $results = $table::paginate( + [ + [ + 'query_operator' => 'AND', + [ + 'column' => 'status', + 'value' => 1, + 'operator' => '>', + ], + [ + 'column' => 'status', + 'value' => 4, + 'operator' => '<', + ], + ], + ], + 10, + 1 + ); + + $this->assertCount( 2, $results ); + $statuses = array_column( $results, 'status' ); + $this->assertContains( 2, $statuses ); + $this->assertContains( 3, $statuses ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_use_stellarwp_schema_hook_prefix() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Hook Test', 'slug' => 'hook-test', 'status' => 1 ] ); + + $action_count_before = did_action( 'stellarwp_schema_custom_table_query_pre_results' ); + $action_count_after = did_action( 'stellarwp_schema_custom_table_query_post_results' ); + $filter_count_before = did_filter( 'stellarwp_schema_custom_table_query_results' ); + $filter_count_after = did_filter( 'stellarwp_schema_custom_table_query_where' ); + + $table::paginate( [], 10, 1 ); + + $this->assertSame( $action_count_before + 1, did_action( 'stellarwp_schema_custom_table_query_pre_results' ), 'stellarwp_schema_custom_table_query_pre_results action should fire' ); + $this->assertSame( $action_count_after + 1, did_action( 'stellarwp_schema_custom_table_query_post_results' ), 'stellarwp_schema_custom_table_query_post_results action should fire' ); + $this->assertSame( $filter_count_before + 1, did_filter( 'stellarwp_schema_custom_table_query_results' ), 'stellarwp_schema_custom_table_query_results filter should fire' ); + $this->assertSame( $filter_count_after + 1, did_filter( 'stellarwp_schema_custom_table_query_where' ), 'stellarwp_schema_custom_table_query_where filter should fire' ); + } + + /** + * @test + */ + public function should_ignore_sub_where_with_missing_column_key() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Test 1', 'slug' => 'test-1', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Test 2', 'slug' => 'test-2', 'status' => 0 ] ); + + add_filter( 'doing_it_wrong_trigger_error', '__return_false' ); + + $doing_it_wrong_called = false; + add_action( 'doing_it_wrong_run', function() use ( &$doing_it_wrong_called ) { + $doing_it_wrong_called = true; + } ); + + // Malformed: missing 'column' key. + $results = $table::paginate( + [ + [ + 'value' => 'test-1', + 'operator' => '=', + ], + ], + 10, + 1 + ); + + $this->assertTrue( $doing_it_wrong_called, '_doing_it_wrong should be called' ); + + // Should return all rows since the malformed filter is ignored. + $this->assertCount( 2, $results ); + + // Query should not contain WHERE clause. + $this->assertStringNotContainsString( 'WHERE', $this->get_captured_query() ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_handle_sub_where_with_missing_value_key() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Test 1', 'slug' => 'test-1', 'status' => 1 ] ); + $table::insert( [ 'name' => '', 'slug' => 'test-2', 'status' => 0 ] ); + + $doing_it_wrong_called = false; + + add_filter( 'doing_it_wrong_trigger_error', '__return_false' ); + + add_action( 'doing_it_wrong_run', function () use ( &$doing_it_wrong_called ) { + $doing_it_wrong_called = true; + } ); + + // Missing 'value' key - should default to checking column is not empty. + $results = $table::paginate( + [ + [ + 'column' => 'name', + ], + ], + 10, + 1 + ); + + $this->assertFalse( $doing_it_wrong_called, '_doing_it_wrong should not be called' ); + + // Should return only the row with non-empty name. + $this->assertCount( 1, $results ); + $this->assertEquals( 'Test 1', $results[0]['name'] ); + + // Query should contain WHERE clause with != ''. + $this->assertQueryContains( "a.name != ''" ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_normalize_invalid_operator_to_equals() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Test 1', 'slug' => 'test-1', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Test 2', 'slug' => 'test-2', 'status' => 0 ] ); + + // Invalid operator should be normalized to '='. + $results = $table::paginate( + [ + [ + 'column' => 'slug', + 'value' => 'test-1', + 'operator' => 'INVALID_OP', + ], + ], + 10, + 1 + ); + + $this->assertCount( 1, $results ); + $this->assertEquals( 'test-1', $results[0]['slug'] ); + + // Should use '=' operator. + $this->assertQueryContains( "a.slug = 'test-1'" ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_ignore_sub_where_with_invalid_column_name() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Test 1', 'slug' => 'test-1', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Test 2', 'slug' => 'test-2', 'status' => 0 ] ); + + // Column 'nonexistent' does not exist. + $results = $table::paginate( + [ + [ + 'column' => 'nonexistent_column', + 'value' => 'test-1', + 'operator' => '=', + ], + ], + 10, + 1 + ); + + // Should return all rows since invalid column filter is ignored. + $this->assertCount( 2, $results ); + + // Query should not contain WHERE clause. + $this->assertStringNotContainsString( 'WHERE', $this->get_captured_query() ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_ignore_nested_sub_where_with_missing_column() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Alpha', 'slug' => 'alpha', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Beta', 'slug' => 'beta', 'status' => 0 ] ); + + // Nested sub-where with one valid and one invalid entry. + $results = $table::paginate( + [ + [ + 'query_operator' => 'OR', + [ + 'column' => 'slug', + 'value' => 'alpha', + 'operator' => '=', + ], + [ + // Missing 'column' key - should be ignored. + 'value' => 'beta', + 'operator' => '=', + ], + ], + ], + 10, + 1 + ); + + // Should return only alpha since the invalid sub-where is ignored. + $this->assertCount( 1, $results ); + $this->assertEquals( 'alpha', $results[0]['slug'] ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_normalize_invalid_query_operator_in_sub_where() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Test 1', 'slug' => 'test-1', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Test 2', 'slug' => 'test-2', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Test 3', 'slug' => 'test-3', 'status' => 0 ] ); + + // Invalid query_operator should be normalized to 'AND'. + $results = $table::paginate( + [ + [ + 'query_operator' => 'INVALID', + [ + 'column' => 'slug', + 'value' => 'test-1', + 'operator' => '=', + ], + [ + 'column' => 'status', + 'value' => 1, + 'operator' => '=', + ], + ], + ], + 10, + 1 + ); + + // With AND operator, only 'test-1' matches both conditions. + $this->assertCount( 1, $results ); + + // Should use 'AND' operator (the default). + $this->assertQueryContains( "AND" ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_handle_deeply_nested_sub_wheres_four_levels() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + // Insert test data covering various combinations. + $table::insert( [ 'name' => 'A1', 'slug' => 'a1', 'status' => 1 ] ); + $table::insert( [ 'name' => 'A2', 'slug' => 'a2', 'status' => 1 ] ); + $table::insert( [ 'name' => 'B1', 'slug' => 'b1', 'status' => 0 ] ); + $table::insert( [ 'name' => 'B2', 'slug' => 'b2', 'status' => 0 ] ); + $table::insert( [ 'name' => 'C1', 'slug' => 'c1', 'status' => 1 ] ); + $table::insert( [ 'name' => 'C2', 'slug' => 'c2', 'status' => 0 ] ); + + // Level 4 deep nesting: + // WHERE ( + // ( + // (slug = 'a1' OR slug = 'a2') + // AND + // (status = 1) + // ) + // OR + // (slug = 'b1') + // ) + $results = $table::paginate( + [ + [ + 'query_operator' => 'OR', + // Level 2 + [ + 'query_operator' => 'AND', + // Level 3 + [ + 'query_operator' => 'OR', + // Level 4 + [ + 'column' => 'slug', + 'value' => 'a1', + 'operator' => '=', + ], + [ + 'column' => 'slug', + 'value' => 'a2', + 'operator' => '=', + ], + ], + [ + 'column' => 'status', + 'value' => 1, + 'operator' => '=', + ], + ], + // OR with this + [ + 'column' => 'slug', + 'value' => 'b1', + 'operator' => '=', + ], + ], + ], + 10, + 1 + ); + + // Should match: a1 (status=1), a2 (status=1), b1 (any status). + $this->assertCount( 3, $results ); + $slugs = array_column( $results, 'slug' ); + $this->assertContains( 'a1', $slugs ); + $this->assertContains( 'a2', $slugs ); + $this->assertContains( 'b1', $slugs ); + + // Verify the query structure has proper nesting. + $query = $this->get_captured_query(); + $this->assertStringContainsString( 'WHERE', $query ); + // Should contain nested parentheses. + $this->assertStringContainsString( '((', $query ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_handle_complex_four_level_nesting_with_all_operators() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Item 1', 'slug' => 'item-1', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Item 2', 'slug' => 'item-2', 'status' => 2 ] ); + $table::insert( [ 'name' => 'Item 3', 'slug' => 'item-3', 'status' => 3 ] ); + $table::insert( [ 'name' => 'Item 4', 'slug' => 'item-4', 'status' => 4 ] ); + $table::insert( [ 'name' => 'Item 5', 'slug' => 'item-5', 'status' => 5 ] ); + + // Complex query: + // WHERE ( + // ( + // (status >= 2 AND status <= 4) + // OR + // (slug = 'item-1') + // ) + // AND + // (status != 3) + // ) + $results = $table::paginate( + [ + [ + 'query_operator' => 'AND', + // Level 2 + [ + 'query_operator' => 'OR', + // Level 3 + [ + 'query_operator' => 'AND', + // Level 4 + [ + 'column' => 'status', + 'value' => 2, + 'operator' => '>=', + ], + [ + 'column' => 'status', + 'value' => 4, + 'operator' => '<=', + ], + ], + [ + 'column' => 'slug', + 'value' => 'item-1', + 'operator' => '=', + ], + ], + [ + 'column' => 'status', + 'value' => 3, + 'operator' => '!=', + ], + ], + ], + 10, + 1 + ); + + // Should match: item-1 (status=1, not 3), item-2 (status=2, in range, not 3), item-4 (status=4, in range, not 3). + $this->assertCount( 3, $results ); + $slugs = array_column( $results, 'slug' ); + $this->assertContains( 'item-1', $slugs ); + $this->assertContains( 'item-2', $slugs ); + $this->assertContains( 'item-4', $slugs ); + $this->assertNotContains( 'item-3', $slugs ); // Excluded by != 3. + $this->assertNotContains( 'item-5', $slugs ); // Not in range and not item-1. + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_capture_query_with_paginate_filter() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Test', 'slug' => 'test', 'status' => 1 ] ); + + $table::paginate( + [ + [ + 'column' => 'status', + 'value' => 1, + 'operator' => '=', + ], + ], + 10, + 1 + ); + + $query = $this->get_captured_query(); + + // Verify query structure. + $this->assertNotEmpty( $query ); + $this->assertStringContainsString( 'SELECT', $query ); + $this->assertStringContainsString( 'FROM', $query ); + $this->assertStringContainsString( 'WHERE', $query ); + $this->assertStringContainsString( 'a.status = 1', $query ); + $this->assertStringContainsString( 'LIMIT', $query ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_produce_correct_query_for_simple_sub_where() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Test', 'slug' => 'test', 'status' => 1 ] ); + + $table::paginate( + [ + 'orderby' => 'id', + 'order' => 'ASC', + [ + 'column' => 'slug', + 'value' => 'test', + 'operator' => '=', + ], + ], + 20, + 1 + ); + + $this->assertQueryContains( "WHERE a.slug = 'test'" ); + $this->assertQueryContains( "ORDER BY a.id ASC" ); + $this->assertQueryContains( "LIMIT 0, 20" ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_produce_correct_query_for_or_sub_where() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'A', 'slug' => 'a', 'status' => 1 ] ); + $table::insert( [ 'name' => 'B', 'slug' => 'b', 'status' => 0 ] ); + + $table::paginate( + [ + [ + 'query_operator' => 'OR', + [ + 'column' => 'slug', + 'value' => 'a', + 'operator' => '=', + ], + [ + 'column' => 'slug', + 'value' => 'b', + 'operator' => '=', + ], + ], + ], + 10, + 1 + ); + + // Verify the query has OR grouped in parentheses. + $this->assertQueryContains( "(a.slug = 'a' OR a.slug = 'b')" ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_produce_correct_query_for_nested_sub_where() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Test', 'slug' => 'test', 'status' => 1 ] ); + + // WHERE ((slug = 'a' OR slug = 'b') AND status = 1) + $table::paginate( + [ + [ + 'query_operator' => 'OR', + [ + 'column' => 'slug', + 'value' => 'a', + 'operator' => '=', + ], + [ + 'column' => 'slug', + 'value' => 'b', + 'operator' => '=', + ], + ], + [ + 'column' => 'status', + 'value' => 1, + 'operator' => '=', + ], + ], + 10, + 1 + ); + + // Verify the query structure. + $query = $this->get_captured_query(); + $this->assertStringContainsString( "(a.slug = 'a' OR a.slug = 'b')", $query ); + $this->assertStringContainsString( "a.status = 1", $query ); + $this->assertStringContainsString( " AND ", $query ); + $this->assertCapturedQueryMatchesSnapshot(); + } + + /** + * @test + */ + public function should_handle_empty_sub_where_group() { + $table = $this->get_query_test_table(); + Register::table( $table ); + + $table::insert( [ 'name' => 'Test 1', 'slug' => 'test-1', 'status' => 1 ] ); + $table::insert( [ 'name' => 'Test 2', 'slug' => 'test-2', 'status' => 0 ] ); + + // Empty sub-where group should be ignored. + $results = $table::paginate( + [ + [ + 'query_operator' => 'OR', + // Empty - no conditions. + ], + [ + 'column' => 'status', + 'value' => 1, + 'operator' => '=', + ], + ], + 10, + 1 + ); + + $this->assertCount( 1, $results ); + $this->assertEquals( 'test-1', $results[0]['slug'] ); + $this->assertCapturedQueryMatchesSnapshot(); + } + /** * Get a test table for query method testing. */ diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_capture_query_with_paginate_filter__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_capture_query_with_paginate_filter__0.snapshot.php new file mode 100644 index 0000000..b271c62 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_capture_query_with_paginate_filter__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE a.status = 1 ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_count_total_items_with_sub_where_clauses__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_count_total_items_with_sub_where_clauses__0.snapshot.php new file mode 100644 index 0000000..4c4d4c7 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_count_total_items_with_sub_where_clauses__0.snapshot.php @@ -0,0 +1 @@ +SELECT COUNT(*) FROM `wp_query_test` a WHERE (a.slug = 'x' OR a.slug = 'y') \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_complex_four_level_nesting_with_all_operators__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_complex_four_level_nesting_with_all_operators__0.snapshot.php new file mode 100644 index 0000000..4ac222e --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_complex_four_level_nesting_with_all_operators__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE (((a.status >= 2 AND a.status <= 4) OR a.slug = 'item-1') AND a.status != 3) ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_deeply_nested_sub_wheres_four_levels__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_deeply_nested_sub_wheres_four_levels__0.snapshot.php new file mode 100644 index 0000000..5cfbb1d --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_deeply_nested_sub_wheres_four_levels__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE (((a.slug = 'a1' OR a.slug = 'a2') AND a.status = 1) OR a.slug = 'b1') ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_empty_sub_where_group__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_empty_sub_where_group__0.snapshot.php new file mode 100644 index 0000000..b271c62 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_empty_sub_where_group__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE a.status = 1 ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_sub_where_with_different_operators__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_sub_where_with_different_operators__0.snapshot.php new file mode 100644 index 0000000..7f21f82 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_sub_where_with_different_operators__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE (a.status > 1 AND a.status < 4) ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_sub_where_with_missing_value_key__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_sub_where_with_missing_value_key__0.snapshot.php new file mode 100644 index 0000000..a0225f5 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_handle_sub_where_with_missing_value_key__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE a.name != '' ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_ignore_nested_sub_where_with_missing_column__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_ignore_nested_sub_where_with_missing_column__0.snapshot.php new file mode 100644 index 0000000..7436784 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_ignore_nested_sub_where_with_missing_column__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE (a.slug = 'alpha') ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_ignore_sub_where_with_invalid_column_name__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_ignore_sub_where_with_invalid_column_name__0.snapshot.php new file mode 100644 index 0000000..08b78be --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_ignore_sub_where_with_invalid_column_name__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_ignore_sub_where_with_missing_column_key__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_ignore_sub_where_with_missing_column_key__0.snapshot.php new file mode 100644 index 0000000..08b78be --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_ignore_sub_where_with_missing_column_key__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_normalize_invalid_operator_to_equals__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_normalize_invalid_operator_to_equals__0.snapshot.php new file mode 100644 index 0000000..0d3874d --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_normalize_invalid_operator_to_equals__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE a.slug = 'test-1' ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_normalize_invalid_query_operator_in_sub_where__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_normalize_invalid_query_operator_in_sub_where__0.snapshot.php new file mode 100644 index 0000000..7c33a65 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_normalize_invalid_query_operator_in_sub_where__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE (a.slug = 'test-1' AND a.status = 1) ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_multiple_sub_where_groups__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_multiple_sub_where_groups__0.snapshot.php new file mode 100644 index 0000000..1a4fe36 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_multiple_sub_where_groups__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE a.slug = 'a' OR a.slug = 'b' ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_nested_sub_where_clauses__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_nested_sub_where_clauses__0.snapshot.php new file mode 100644 index 0000000..74e579f --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_nested_sub_where_clauses__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE (a.slug = 'alpha' OR a.slug = 'beta') AND a.status = 1 ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_simple_where_clause__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_simple_where_clause__0.snapshot.php new file mode 100644 index 0000000..b271c62 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_simple_where_clause__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE a.status = 1 ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_sub_where_clauses_using_or__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_sub_where_clauses_using_or__0.snapshot.php new file mode 100644 index 0000000..260b13d --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_paginate_with_sub_where_clauses_using_or__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE (a.slug = 'alpha' OR a.slug = 'beta') ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_produce_correct_query_for_nested_sub_where__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_produce_correct_query_for_nested_sub_where__0.snapshot.php new file mode 100644 index 0000000..bb756d0 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_produce_correct_query_for_nested_sub_where__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE (a.slug = 'a' OR a.slug = 'b') AND a.status = 1 ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_produce_correct_query_for_or_sub_where__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_produce_correct_query_for_or_sub_where__0.snapshot.php new file mode 100644 index 0000000..987ca20 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_produce_correct_query_for_or_sub_where__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE (a.slug = 'a' OR a.slug = 'b') ORDER BY a.id ASC LIMIT 0, 10 \ No newline at end of file diff --git a/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_produce_correct_query_for_simple_sub_where__0.snapshot.php b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_produce_correct_query_for_simple_sub_where__0.snapshot.php new file mode 100644 index 0000000..84db9d6 --- /dev/null +++ b/tests/wpunit/Traits/__snapshots__/Custom_Table_Query_MethodsTest__should_produce_correct_query_for_simple_sub_where__0.snapshot.php @@ -0,0 +1 @@ +SELECT a.* FROM `wp_query_test` a WHERE a.slug = 'test' ORDER BY a.id ASC LIMIT 0, 20 \ No newline at end of file