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

Add getting column spec for RowIterator #337

Closed
wants to merge 4 commits into from

Conversation

macher259
Copy link
Contributor

Fixes: #336
We add a getter for ColumnSpec for *_iter query methods.
Enables users to learn about column names when they are using *_iter methods.
I took implementation from cvybhu@6bf7182 and made tests for it.

Pre-review checklist

  • I have split my patch into logically separate commits.
  • All commit messages clearly explain what they change and why.
  • I added relevant tests for new features and bug fixes.
  • All commits compile, pass static checks and pass test.
  • PR description sums up the changes and reasons why they should be introduced.
  • I added appropriate Fixes: annotations to PR description.

Exposing column spec through iterator allows us to get column names and to stay consistent with QueryResult's api.
Tests for simple queries and using prepared statement ones are slightly amended to check column_spec getter for RowIterator in query_iter() and execute_iter().
Comment on lines 82 to 85
for (spec, name) in query_result.get_column_specs().iter().zip(["a", "b", "c"]) {
assert_eq!(spec.name, name); // Check column name.
assert_eq!(spec.table_spec.ks_name, "ks");
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This test doesn't detect the case when the get_column_specs is empty. The zip method takes two iterators and produces a new one which stops after the shorter of them finishes (doc link) - so if the columns specs slice is empty, the loop will immediately stop.

Besides, it's precisely what happens now. The way that the RowIterator is implemented now is that it caches a single page of rows and lazily updates it after the page is exhausted and the next method is called - but the iterator starts with a dummy, empty page (see e.g. here) which has empty metadata. So, until you call next() on the iterator for the first time, you will get empty metadata.

To solve this problem, let's change the Session::execute_iter and Session::query_iter so that they return an iterator already initialized with the first page. Most of the changes needed to implement this should happen in RowIterator::new_for_query and RowIterator::new_for_prepared_statement.

iterator: changed creating RowIterator for queries and prepared queries, so they do load first page of the result. Changed new_for_query and new_for_prepared_statement into async functions as the consequence.

session: changed invoking new_for_query and new_for_prepared_statement in compliance with above changes.

Before these changes we were allowing for constructing an iterator in an invalid state - i.e. we could get empty metadata unless we called next method at least once.
@@ -146,16 +146,24 @@ impl RowIterator {

tokio::task::spawn(worker_task);

RowIterator {
let pages_received = receiver.recv().await.unwrap()?;
Copy link
Collaborator

@piodul piodul Nov 22, 2021

Choose a reason for hiding this comment

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

It's not really obvious if the worker always pushes at least one value before the channel is closed. If not, the unwrap() here will trigger a panic which will crash the application - and that is something we would like to avoid.

Let's be defensive and use unwrap_with_default() instead - it will return a Default::default() page if the channel does not produce any page.

Additionally, the variable holds only one page, so the page in the variable name should be singular (page_received).

The same comments apply to the logic in new_for_prepared_statement.

Copy link
Collaborator

Choose a reason for hiding this comment

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

After our conversation in private I was convinced that unwrapping here is OK. It's a bug if there are no pages returned.

@macher259 macher259 marked this pull request as draft November 23, 2021 17:15
@macher259 macher259 marked this pull request as ready for review November 29, 2021 11:40
@piodul piodul closed this in b46f913 Dec 3, 2021
@piodul
Copy link
Collaborator

piodul commented Dec 3, 2021

Merged. The commits needed some cleaning up, so in order not to delay merging this PR further I reorganized them a little before merging. Some tips for the future:

  • The third commit looks like a squash of three commits with unedited commit message after the squash. Remember that the first line in the message serves as a very short summary of what the commit does. That commit introduced a change which cause the RowIterator to have the first page already loaded after it was returning, but the commit message started with result: removed deriving Default trait for Rows struct. - which wasn't very informative. I rearranged the commit message a bit to make it more clear.
  • You had a commit which introduced tests and then another which fixes them. It's better to have one commit which introduces correct tests, so I squashed them.

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.

Expose column spec information for the _iter interface
2 participants