Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable --format=<format> for db search #247

Merged
merged 5 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions features/db-search.feature
Original file line number Diff line number Diff line change
Expand Up @@ -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,[email protected]
"""

When I try `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
"""
66 changes: 62 additions & 4 deletions src/DB_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -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` instead. Place the 'table:column' output on the same line as the row id and match ('table:column:id:match'). Overrides --table_column_once.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What argument should they use with --format?

*
* [--matches_only]
* : Only output the string matches (including context). No 'table:column's or row ids are outputted.
* : Deprecated: use `--format` instead. Only output the string matches (including context). No 'table:column's or row ids are outputted.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What argument should they use with --format?

*
* [--stats]
* : Output stats on the number of matches found, time taken, tables/columns/rows searched, tables skipped.
Expand All @@ -1225,6 +1225,12 @@ public function prefix() {
* [--match_color=<color_code>]
* : 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=<fields>]
* : Get a specific subset of the fields.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What fields are supported here?

*
* [--format=<format>]
* : Render output in a particular format.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should document supported --format=<format> options with YAML:

[--format=<format>]
---
options:
  - TK
---

*
* The percent color codes available are:
*
* | Code | Color
Expand Down Expand Up @@ -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 ) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 ) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be 'value' instead of 'ID'? It seems a little bit weird to call this 'ID' when the primary key column could be called something else.

// 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 );
Expand Down
Loading