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 support for DISTINCT statement #3695

Closed
wants to merge 4 commits into from
Closed

Add support for DISTINCT statement #3695

wants to merge 4 commits into from

Conversation

bingo-soft
Copy link
Contributor

Q A
Type improvement
BC Break no
Fixed issues

Summary

The same functionality as in Doctrine/ORM. New method distinct($flag = true) in QueryBuilder class and new test testSimpleSelectWithDistinct in QueryBuilderTest are provided.

@greg0ire
Copy link
Member

greg0ire commented Oct 12, 2019

That functionality is already available by using select('DISTINCT u.id') correct? Is the point to be able to make it conditional easily? Can you provide a code sample that shows in what situation this will make your life easier?

Also, is develop the correct target branch when there are no BC breaks?

@bingo-soft
Copy link
Contributor Author

bingo-soft commented Oct 12, 2019

@greg0ire. There is a number of arguments for providing this functionality.

First of all, in SQL DISTINCT is a separate operation, similar to GROUP BY, but with a specific focus on eliminating duplicates. So, if we have groupBy in API, why not to provide a more granular distinct method?

Secondly, DISTINCT is a row operation, not a column function, so if you write higher level query language on top of Doctrine DBAL, which allows users to specify returned fields on the fly, it would be easier to apply distinct=true once, than to inject this logic into the part of the algorithm responsible for handling fields. So, two lines of code in Doctrine DBAL would save numbers of lines of client code (looping through all fields, injecting DISTINCT to the first field - $qb->addSelect("DISTINCT field_name"); if client does not provide the list of fields, then adding DISTINCT to * - like $qb->addSelect(DISTINCT *)). So, what is expected to be rather a row operation, becomes a column operation in DBAL client code.

In short, yes, the point is to make it conditional easily.

Copy link
Member

@greg0ire greg0ire left a comment

Choose a reason for hiding this comment

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

Also, is develop the correct target branch when there are no BC breaks?

Please address this

*/
public function distinct(bool $flag = true)
{
$this->sqlParts['distinct'] = (bool) $flag;
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this cast is needed.

Suggested change
$this->sqlParts['distinct'] = (bool) $flag;
$this->sqlParts['distinct'] = $flag;

*
* @return $this This QueryBuilder instance.
*/
public function distinct(bool $flag = true)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public function distinct(bool $flag = true)
final public function distinct(bool $flag = true) : self

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree with self part, but not sure of final specificator. It would be the only one final method in QueryBuilder.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah but it is one of the most recent ones, right? We can wait for the advice of another maintainer if you want, I will not merge this without the approval of some other maintainers anyway.

@@ -1088,7 +1110,8 @@ public function resetQueryPart(string $queryPartName) : self
*/
private function getSQLForSelect() : string
{
$query = 'SELECT ' . implode(', ', $this->sqlParts['select']);
$query = 'SELECT ' . ($this->sqlParts['distinct'] === true ? 'DISTINCT ' : '') .
Copy link
Member

Choose a reason for hiding this comment

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

This is already supposed to be a boolean, and if happens not to be, the bug might still go undetected. If you feel unsafe about it being a boolean, then check that and throw if it isn't, or introduce a private accessor to do the type check. If you feel safe, then simply do this:

Suggested change
$query = 'SELECT ' . ($this->sqlParts['distinct'] === true ? 'DISTINCT ' : '') .
$query = 'SELECT ' . ($this->sqlParts['distinct'] ? 'DISTINCT ' : '') .

@@ -62,6 +62,7 @@ class QueryBuilder
* @var array<string, mixed>
*/
private $sqlParts = [
'distinct' => false,
Copy link
Member

Choose a reason for hiding this comment

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

I'd move it one line below, it looks like there this array is ordered with the same order in which you would find these keywords in an SQL query.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like that. You are right

* ->from('users', 'u');
* </code>
*
* @param bool $flag If true, then DISTINCT is added to the query
Copy link
Member

Choose a reason for hiding this comment

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

In what scenario is that parameter going to be useful?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you mean, that there is no sense to mention this parameter in the docstring, since it is self evident? And by the way, as for develop branch, should I make a new merge request to the master branch to fix this?

Copy link
Member

Choose a reason for hiding this comment

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

No I mean, maybe we should remove the parameter entirely?

And by the way, as for develop branch, should I make a new merge request to the master branch to fix this?

You can edit your PR to target master, and rebase your branch on it: git rebase --onto master origin/develop develop (you should probably not have named your local branch develop BTW, it makes this a bit confusing :P)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ups, I've never done that magic yet and made another fork for another PR. So, I think I will close this one and start another PR, if you don't mind. And I will take into account all you suggestions, probably except final key word

@greg0ire
Copy link
Member

@bingo-soft bingo-soft closed this Oct 12, 2019
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 7, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants