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

Extended returning support #155

Conversation

marlon-sousa
Copy link
Contributor

@marlon-sousa marlon-sousa commented Oct 5, 2021

In this pull request, we implement a feature eco-system which enables returning statements to be used in different back-ends.

We also configure returning method to take a list of columns instead of a full select expression, because in majority of cases omne will be asking for either none, * (all) or a list of columns of changed rows to be returned instead.

Associated issue is #156

Copy link
Member

@tyt2y3 tyt2y3 left a comment

Choose a reason for hiding this comment

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

Thank you so much for the contribution.

First, I think Returing should be named as ReturningClause. It is nice to have its own data structure indeed, instead of reusing SelectExpr.
Second, while SQLite supports returning in latest version, it's support is not universal.
I think that it is the best to have MySQL always ignore the returning clause, no matter whether returning is enabled.

That say, I don't think the use of feature guard here is correct.
The problem is, cargo features are supposed to be independent. Imagine within a dependency tree, one crate turned on postgres while another crate turned on sqlite. It would subtly alter the generated query, such that the SQLite user would be surprised because it never turned on the returning feature, but it was turned on as a side effect of postgres.

I would sugguest to remove the feature guard.

All in all, nice work!

@marlon-sousa
Copy link
Contributor Author

marlon-sousa commented Oct 5, 2021

Hello,

Thank you so much. This is my first pull request for a project in rust language and I have been learning a lot lately.

It seems we have support for returning in MariaDB. Take a look at https://mariadb.com/kb/en/insertreturning/#:~:text=RETURNING%20returns%20a%20resultset%20of,alternatively%2C%20the%20specified%20SELECT%20expression.

If this support exists, we should be handling it accordingly. As far as I understand, mysql / maria db support are kind of unified, so this is why.

Secondly, I do agree with your view on cargo tools. But, never-the-less, I still need to be able to enable or disable returning in a way which is always enabled for postgres, conditionally enabled for other back ends. This is not so much important to sea-query because one using returning is supposed to know if their database supports it or not, but for other clients such as sea-orm we need a way of enabling / disabling it. Any suggestions?

@tyt2y3
Copy link
Member

tyt2y3 commented Oct 5, 2021

Sure. You are definitely welcomed by the Rust community )

Thank you for pointing that out with MariaDB.
Then we'd simply let the user decide. If the statement has a returning clause, just output it no matter what.
Do you have other concerns?

A note of reference on cargo feature rust-lang/cargo#4328

@marlon-sousa
Copy link
Contributor Author

Feature guard has been removed.

@marlon-sousa
Copy link
Contributor Author

I have choosen to not alter the version of the crate because you are controlling the release process.

Copy link
Member

@tyt2y3 tyt2y3 left a comment

Choose a reason for hiding this comment

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

There is actually never a select * within sea-query. Do you have a specific reason you need it?
(It's hardly useful in Rust, because we aren't able to deserialize arbitrary select list anyway)

At the same time, Returning::Nothing is redundant too?

So, I'd suggest having a Returning::columns method (instead of cols) which is more consistent with Query::select()::columns()

@marlon-sousa
Copy link
Contributor Author

Hello,

Here is why I have chosen at first to represent this as an enum:

"returning *" is a very very common pattern, which specifies that you want to return every single column of changed rows when performing delete, update and insert.

I thought that putting on users the burden of having to specify (list) every time all columns was just not ergonomic enough. Plus, the user would have to rewrite the code whenever the entity has columns added / removed, whereas using ::all this would not need to be changed.

Examples of potential users for ::All is the save method on sea orm, which will have to return the updated record anyways, or folks wanting to get ActiveModels with all columns filled for changed records.

Also, making a query with "returning *" is shorter and thus more performant than sending a query with "returning tablename.a, tablename.b, ... tablename.n", if you understand me.

For deserializing the framework would have to match on the returning enum to see the columns expected in the result set to deserialize the result.

match statement.returning {
  All => Deserialize(originalEntity::get_columns(),
  colls(c) => deserealize(c)
  Nothing => do_nothing_because_result_set_will_be_empty(),
}

The nothing was thought by another reason: suppose that one uses any kind of builder that implies that you want to have either the id or even all columns returned, but for your particular use-case you don't need this data. You could still use the builder and then, before performing the execution, just overwrite the returning to specify nothing instead, so that you still can keep your code fluent and alleviate database workload.

The cols helper just take and iterator and fill a list of columns.

I just wanted to show my point of view, but will of course code what you define. I just need a clearer definition on how the feature should be working.

Thank you for reviewing!

@tyt2y3
Copy link
Member

tyt2y3 commented Oct 7, 2021

I do not actually disagree on all or nothing. But the API style is slightly inconsistent with the rest of the library. They are perfectly fine on their own, and there is no good or bad. It's just nicer to be consistent.

So the following

.returning(Returning::Columns(vec![Glyph::Id.into_column_ref()]))

would be better to be

.returning(Query::returning().column(Glyph::Id))
.returning(Query::returning().columns(vec![Glyph::Id, Glyph::Name]))
.returning(Query::returning().all())
.returning(Query::returning()) // this is nothing

Basically a mirror of the SelectStatement interface.

@marlon-sousa
Copy link
Contributor Author

A ... ok, I see. Well, I will implement that and let you know. I am not so familliar with sea-query so it is good to see governance over the public api.

@tyt2y3
Copy link
Member

tyt2y3 commented Oct 19, 2021

Now that SeaORM 0.3 has been released, we can focus on this task now.
Do you also happens to have an update?

@billy1624 billy1624 mentioned this pull request Nov 5, 2021
@RomainMazB
Copy link
Contributor

@marlon-sousa
Just a note on this one if you are still working on it: I submitted a SELECT * feature here: #219 .
I didn't follow the entire conversation but I noticed that this may ease the implementation of this feature.

@ikrivosheev
Copy link
Member

@marlon-sousa do you want to finish this PR?

@ikrivosheev ikrivosheev changed the base branch from master to feature/issues-156_extended-returning-support May 4, 2022 11:40
@ikrivosheev ikrivosheev deleted the branch SeaQL:feature/issues-156_extended-returning-support May 4, 2022 11:43
@ikrivosheev ikrivosheev closed this May 4, 2022
@ikrivosheev ikrivosheev reopened this May 4, 2022
@ikrivosheev ikrivosheev merged commit 4dea263 into SeaQL:feature/issues-156_extended-returning-support May 4, 2022
@ikrivosheev
Copy link
Member

I will continue to work: #317

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Better support for returnimg statement on back ends
5 participants