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

feat(cli): improve CLI transient queries with headers and spacing (partial fix for #892) #3047

Merged
merged 6 commits into from
Jul 15, 2019

Conversation

agavra
Copy link
Contributor

@agavra agavra commented Jul 2, 2019

Description

Ladies and Gentlemen, the moment you have all been waiting for! Hot off the press 🔥 🔥 🔥 Formatted CLI output for transient queries, with a shiny new header row 🎉 🎉 🎉

ksql> SELECT * FROM ALL_PUBLICATIONS;
+-----------------------+-----------------------+-----------------------+-----------------------+
|ROWTIME                |ROWKEY                 |AUTHOR                 |TITLE                  |
+-----------------------+-----------------------+-----------------------+-----------------------+
|1562173641326          |C.S. Lewis             |C.S. Lewis             |The Silver Chair       |
|1562173641364          |George R. R. Martin    |George R. R. Martin    |A Song of Ice and Fire |
|1562173641378          |C.S. Lewis             |C.S. Lewis             |Perelandra             |
|1562173641392          |George R. R. Martin    |George R. R. Martin    |Fire & Blood           |
|1562173641406          |J. R. R. Tolkien       |J. R. R. Tolkien       |The Hobbit             |
|1562173641419          |J. R. R. Tolkien       |J. R. R. Tolkien       |The Lord of the Rings  |
|1562173641432          |George R. R. Martin    |George R. R. Martin    |A Dream of Spring      |
|1562173641446          |J. R. R. Tolkien       |J. R. R. Tolkien       |The Fellowship of the R|
|                       |                       |                       |ing                    |
|1562173641460          |George R. R. Martin    |George R. R. Martin    |The Ice Dragon         |

It even does very fancy 💃 🕺 wrapping for lines that are too long and adjusts based on your terminal size.

Notes

This has a hacked version of #3043 as part of it, we should resolve that independently

Testing done

  • Unit testing
  • CLI integration testing

Reviewer checklist

  • Ensure docs are updated if necessary. (eg. if a user visible feature is being added or changed).
  • Ensure relevant issues are linked (description should include text like "Fixes #")

@agavra agavra requested a review from a team as a code owner July 2, 2019 23:53
@MichaelDrogalis
Copy link
Contributor

May I suggest a slight cosmetic adjustment to match MySQL?

+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|       1 | A      |  3.45 |
|       1 | B      |  3.99 |
|       2 | A      | 10.99 |
|       3 | B      |  1.45 |
|       3 | C      |  1.69 |
|       3 | D      |  1.25 |
|       4 | D      | 19.95 |
+---------+--------+-------+
  • Top row of dashes before the headers
  • Row of dashes under the headers
  • No dashes between rows

Mostly curious to see how it looks if we try to line 'em up

@hjafarpour
Copy link
Contributor

This is great @agavra , I agree with @MichaelDrogalis 's comment on matching MySQL. Postgres also is very similar to MySQL. That way it would really look and feel like a database! ;)

Copy link
Contributor

@big-andy-coates big-andy-coates left a comment

Choose a reason for hiding this comment

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

Thanks @agavra

Some suggestions below. The reason I've requested changes is the attempt to get a fix in for the double meta column bug, which is fixed in my own PR.

private final List<String> value;
private final List<String> header;

public TabularRow(
Copy link
Contributor

Choose a reason for hiding this comment

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

header and value are used mutually exclusively. They both map to a list of strings. So this class could be simplified to just take the width and single List<String> param, pushing up the computation of what is passed as the list of strings to the caller, or maybe two factory methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the reason I have it this way is that in the near future I want to change the column format based on the header - so passing in both will soon be helpful (e.g. fixed width for int columns, etc...)

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, in that case I'd still go for two factory methods to make this clear:

TabularRow.createHeader(headers) vs TabularRow.createRow(headers, row).

And you can still decouple this class from FieldInfo and GenericRow by having the calling code do the toString stuff. Less couple is good! Plus, you can process the headers once for the query, rather than per-row.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And you can still decouple this class from FieldInfo and GenericRow by having the calling code do the toString stuff.

I don't think the current calling class would be a good place to do that. I could introduce another wrapper class (e.g. Tabular) that handled all of the row widths based on the field infos and things like that, but that is overkill for this PR. As it stands, it's pretty decoupled - it's just in a constructor (moved to be static initializer).

@@ -39,7 +39,17 @@ public KsqlBareOutputNode(
final OptionalInt limit,
final TimestampExtractionPolicy extractionPolicy
) {
super(id, source, schema, limit, extractionPolicy);
super(
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't think adding this was intentional.... we shouldn't be doing this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was just hacking it to make it work - wasn't going to commit until your fix is in :)

@big-andy-coates big-andy-coates requested a review from a team July 3, 2019 15:42
}

@Test
public void shouldMultilineFormatRow() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Add test for what happens if the number of columns is higher than the width....

Interesting edge case!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

😨 good catch! I think if this is the case I'll default back to the old behavior

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've decided to set a minimum cell width of 5 - it'll look all weird if the terminal is super small, but that's going to be the case anyway

@spena
Copy link
Member

spena commented Jul 3, 2019

@agavra While testing this, I see that the output fits the full screen. Can we use a fixed column instead? Mysql and other Dbs do not fit the whole screen, although I understand that those DBs know what's the max value read to use it in the column width, and KSQL does not know as it is streaming real-time data.

Btw, if I stop the query and rerun it again, the headers are not displayed anymore.

ksql> select * from t1;
|ROWTIME                                                |ROWKEY                                                 |ID                                                     |
+═══════════════════════════════════════════════════════+═══════════════════════════════════════════════════════+═══════════════════════════════════════════════════════+
|1562104196553                                          |null                                                   |1                                                      |
+-------------------------------------------------------+-------------------------------------------------------+-------------------------------------------------------+
^CQuery terminated
      select * from t1;
|1562104196553                                                                     |null                                                                              |1                                                                                 |
+----------------------------------------------------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------------------+
ksql> select * from t1;
|1562104196553                                                                     |null                                                                              |1                                                                                 |
+----------------------------------------------------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------------------+
ksql> 
ksql> 
ksql> select * from t1;
|1562104196553                                                                     |null                                                                              |1                                                                                 |
+----------------------------------------------------------------------------------+----------------------------------------------------------------------------------+----------------------------------------------------------------------------------+

@agavra
Copy link
Contributor Author

agavra commented Jul 3, 2019

@spena - I'm not sure what's going on with your terminal, but my headers do show multiple times...

and yeah, my concern was that I don't know the max value length when I start it up. The other SQL engines also have more powerful formatting options for the user to choose how they want it to show up. I think until we implement those, we should have a good default option (which, to me, full width makes sense)

+--------------------------------+--------------------------------+--------------------------------+
|ROWTIME                         |ROWKEY                          |ID                              |
+--------------------------------+--------------------------------+--------------------------------+
|1562021756897                   |a                               |1                               |
^CQuery terminated
ksql> SELECT * FROM FOO;
+--------------------------------+--------------------------------+--------------------------------+
|ROWTIME                         |ROWKEY                          |ID                              |
+--------------------------------+--------------------------------+--------------------------------+
|1562021756897                   |a                               |1                               |
^CQuery terminated
ksql> SELECT * FROM FOO;
+--------------------------------+--------------------------------+--------------------------------+
|ROWTIME                         |ROWKEY                          |ID                              |
+--------------------------------+--------------------------------+--------------------------------+
|1562021756897                   |a                               |1                               |
^CQuery terminated
ksql>

Also tested with resizing terminal:

|ROWTIME                   |ROWKEY                    |ID                        |
+--------------------------+--------------------------+--------------------------+
|1562021756897             |a                         |1                         |
^CQuery terminated
ksql> SELECT * FROM FOO;
+----------------------------------------------+----------------------------------------------+----------------------------------------------+
|ROWTIME                                       |ROWKEY                                        |ID                                            |
+----------------------------------------------+----------------------------------------------+----------------------------------------------+
|1562021756897                                 |a                                             |1                                             |
^CQuery terminated
ksql> SELECT * FROM FOO;
+-----------------+-----------------+-----------------+
|ROWTIME          |ROWKEY           |ID               |
+-----------------+-----------------+-----------------+
|1562021756897    |a                |1                |
^CQuery terminated

Copy link
Contributor

@vcrfxia vcrfxia left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks @agavra -- very nice feature :)

@vcrfxia vcrfxia requested a review from a team July 3, 2019 22:04
Copy link
Contributor

@big-andy-coates big-andy-coates left a comment

Choose a reason for hiding this comment

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

Thanks for the update @agavra.

I'm with you on using the full width by default as a good starting point.

private final List<String> value;
private final List<String> header;

public TabularRow(
Copy link
Contributor

Choose a reason for hiding this comment

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

OK, in that case I'd still go for two factory methods to make this clear:

TabularRow.createHeader(headers) vs TabularRow.createRow(headers, row).

And you can still decouple this class from FieldInfo and GenericRow by having the calling code do the toString stuff. Less couple is good! Plus, you can process the headers once for the query, rather than per-row.

}

@SuppressWarnings("ForLoopReplaceableByForEach") // clearer to read this way
private static void toString(
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: rename formatRow or something.

@agavra agavra merged commit 050b72a into confluentinc:master Jul 15, 2019
@agavra agavra deleted the cli_header branch July 15, 2019 22:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants