From 12cf8d60cfe1d8cc2f03f3ee742bdc88479fc308 Mon Sep 17 00:00:00 2001 From: Bernhard Kau Date: Fri, 10 Nov 2023 19:08:28 +0100 Subject: [PATCH] Enable formatter for search command --- features/db-search.feature | 24 ++++++++++++++ src/DB_Command.php | 66 +++++++++++++++++++++++++++++++++++--- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/features/db-search.feature b/features/db-search.feature index 8e929d00..56d25527 100644 --- a/features/db-search.feature +++ b/features/db-search.feature @@ -1066,3 +1066,27 @@ Feature: Search through the database :aöXYXYX """ And STDERR should be empty + + Scenario: Search for a string and output the format as a table + Given a WP install + + When I run `wp db search example.com --format=csv` + Then STDOUT should contain: + """ + wp_options,option_value,option_id,14,mail.example.com + wp_options,option_value,option_id,15,login@example.com + """ + + When I run `wp db search example.com --format=ids` + Then STDERR should be: + """ + Error: The "ids" format can only be used for a single table. + """ + And STDOUT should be empty + And the return code should be 1 + + When I run `wp db search example.com wp_options --format=ids` + Then STDOUT should contain: + """ + 14 15 + """ diff --git a/src/DB_Command.php b/src/DB_Command.php index 484d259c..b9ece56d 100644 --- a/src/DB_Command.php +++ b/src/DB_Command.php @@ -1208,10 +1208,10 @@ public function prefix() { * : Output the 'table:column' line once before all matching row lines in the table column rather than before each matching row. * * [--one_line] - * : Place the 'table:column' output on the same line as the row id and match ('table:column:id:match'). Overrides --table_column_once. + * : Deprecated: use `--format` insted. Place the 'table:column' output on the same line as the row id and match ('table:column:id:match'). Overrides --table_column_once. * * [--matches_only] - * : Only output the string matches (including context). No 'table:column's or row ids are outputted. + * : Deprecated: use `--format` insted. Only output the string matches (including context). No 'table:column's or row ids are outputted. * * [--stats] * : Output stats on the number of matches found, time taken, tables/columns/rows searched, tables skipped. @@ -1225,6 +1225,12 @@ public function prefix() { * [--match_color=] * : Percent color code to use for the match (unless both before and after context are 0, when no color code is used). For a list of available percent color codes, see below. Default '%3%k' (black on a mustard background). * + * [--fields=] + * : Get a specific subset of the fields. + * + * [--format=] + * : Render output in a particular format. + * * The percent color codes available are: * * | Code | Color @@ -1293,6 +1299,21 @@ public function prefix() { * # SQL search and delete records from database table 'wp_options' where 'option_name' match 'foo' * wp db query "DELETE from wp_options where option_id in ($(wp db query "SELECT GROUP_CONCAT(option_id SEPARATOR ',') from wp_options where option_name like '%foo%';" --silent --skip-column-names))" * + * # Search for a string and print the result as a table + * $ wp db search https://localhost:8889 --format=table + * +------------+--------------+-----------+----+-----------------------------+ + * | table | column | key | ID | match | + * +------------+--------------+-----------+----+-----------------------------+ + * | wp_options | option_value | option_id | 1 | https://localhost:8889 | + * | wp_options | option_value | option_id | 2 | https://localhost:8889 | + * | wp_posts | guid | ID | 1 | https://localhost:8889/?p=1 | + * | wp_users | user_url | ID | 1 | https://localhost:8889 | + * +------------+--------------+-----------+----+-----------------------------+ + * + * # Search for a string and get only the IDs (only works for a single table) + * $ wp db search https://localhost:8889 wp_options --format=ids + * 1 2 + * * @when after_wp_load */ public function search( $args, $assoc_args ) { @@ -1332,6 +1353,8 @@ public function search( $args, $assoc_args ) { $one_line = Utils\get_flag_value( $assoc_args, 'one_line', false ); $matches_only = Utils\get_flag_value( $assoc_args, 'matches_only', false ); $stats = Utils\get_flag_value( $assoc_args, 'stats', false ); + $fields = Utils\get_flag_value( $assoc_args, 'fields' ); + $format = Utils\get_flag_value( $assoc_args, 'format' ); $column_count = 0; $row_count = 0; @@ -1366,6 +1389,8 @@ public function search( $args, $assoc_args ) { $tables = Utils\wp_get_table_names( $args, $assoc_args ); + $search_results = []; + $start_search_time = microtime( true ); foreach ( $tables as $table ) { @@ -1409,7 +1434,7 @@ public function search( $args, $assoc_args ) { foreach ( $results as $result ) { $col_val = $result->$column; if ( preg_match_all( $search_regex, $col_val, $matches, PREG_OFFSET_CAPTURE ) ) { - if ( ! $matches_only && ( ! $table_column_once || ! $outputted_table_column_once ) && ! $one_line ) { + if ( ! $format && ! $matches_only && ( ! $table_column_once || ! $outputted_table_column_once ) && ! $one_line ) { WP_CLI::log( $table_column_val ); $outputted_table_column_once = true; } @@ -1457,13 +1482,46 @@ public function search( $args, $assoc_args ) { $match_count += $match_cnt; $col_val = implode( ' [...] ', $bits ); - WP_CLI::log( $matches_only ? $col_val : ( $one_line ? "{$table_column_val}:{$pk_val}{$col_val}" : "{$pk_val}{$col_val}" ) ); + if ( $format ) { + $search_results[] = [ + 'table' => $table, + 'column' => $column, + 'key' => $primary_key, + 'ID' => $result->$primary_key, + // Remove the colors for the format output. + 'match' => str_replace( [ $colors['match'][0], $colors['match'][1] ], [ '', '' ], $col_val ), + ]; + } else { + WP_CLI::log( $matches_only ? $col_val : ( $one_line ? "{$table_column_val}:{$pk_val}{$col_val}" : "{$pk_val}{$col_val}" ) ); + } } } } } } + if ( $format ) { + $formatter_args = [ + 'format' => $format, + ]; + $formatter_fields = [ 'table', 'column', 'key', 'ID', 'match' ]; + + if ( $fields ) { + $fields = explode( ',', $assoc_args['fields'] ); + $formatter_fields = array_values( array_intersect( $formatter_fields, $fields ) ); + } + + if ( in_array( $format, [ 'ids', 'count' ], true ) ) { + if ( count( $tables ) > 1 ) { + WP_CLI::error( 'The "ids" format can only be used for a single table.' ); + } + $search_results = array_column( $search_results, 'ID' ); + } + + $formatter = new Formatter( $formatter_args, $formatter_fields ); + $formatter->display_items( $search_results ); + } + if ( $stats ) { $table_count = count( $tables ); $skipped_count = count( $skipped );