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

Allow internal functions to be overridden. #6500

Merged
merged 9 commits into from
Jun 20, 2017
Merged

Allow internal functions to be overridden. #6500

merged 9 commits into from
Jun 20, 2017

Conversation

ThePixelDeveloper
Copy link

@ThePixelDeveloper ThePixelDeveloper commented Jun 13, 2017

Background

This came about because we're writing a driver for PrestoDB and wanted to implement windowing for the aggregate functions. This is fine for anything new, but we struggled when trying to add windowing support for count, avg, etc ...

All Aggregate Functions can be used as window functions by adding the OVER clause. The aggregate function is computed for each row over the rows within the current row’s window frame.

Source: 6.15. Window Functions — Presto 0.178 Documentation

Solution

Obvious solution for us was to have the ability to override the internal aggregate functions. We moved the internal aggregate functions into the $_NUMERIC_FUNCTIONS property so they can be overridden; They were handled as a special case before.

The only part we weren't sure of was the dctrn alias used: https://github.com/SamKnows/doctrine2/pull/1/files#diff-0c8825d1265a66bb8b20f3d99c276961

If that doesn't matter and we can go with sclr, then this is another path that can be removed.

Thoughts?

PS. First big PR for the Doctrine internals 👍

@Ocramius
Copy link
Member

Overall, this removes the internal and non-internal functions separation, which is quite an improvement.

I'm not sure if I'd like folks to override stuff like MAX or AVG though: lots of space for hurting yourself there... Also, the SqlWalker still treats them as "special" via instanceof checks, so it's not like they became reusable or replaceable anyway...

@ThePixelDeveloper
Copy link
Author

Also, the SqlWalker still treats them as "special" via instanceof checks, so it's not like they became reusable or replaceable anyway...

The only reason there's a case in SqlWalker is because of the dctrn alias. I didn't know if it had special meaning within Doctrine. If it doesn't, I'll remove that case statement and let it be handled by the one below it.

I'm not sure if I'd like folks to override stuff like MAX or AVG though: lots of space for hurting yourself there...

I'm not sure I agree, there's plenty of other places to shoot yourself in the foot already. Custom SQL Walkers allow us to rewrite the output SQL in ways that don't relate to the SQL we write.

I'd rather have a clean / consistent way to override functionality. Before I came up with this solution I was trying to think of alternatives via custom SQL Walkers, which would have been far more magical. At least with this I can look for a DQL function with the key count and see what the new logic is.

@Ocramius
Copy link
Member

Just a note here: patch looks very much clean and IMO it should be merged, but I'd like to have @beberlei, @guilhermeblanco and @lcobucci look at it first.

@guilhermeblanco
Copy link
Member

LGTM.

*
* @return ORMException
*/
public static function overwriteInternalDQLFunctionNotAllowed($functionName)
Copy link
Member

Choose a reason for hiding this comment

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

This method removal is effectively a BC break, and while it is an internal method, it should be documented in UPGRADE.md

@@ -541,10 +533,6 @@ public function setCustomNumericFunctions(array $functions)
*/
public function addCustomDatetimeFunction($name, $className)
{
if (Query\Parser::isInternalFunction($name)) {
Copy link
Member

Choose a reason for hiding this comment

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

@throws in docblock needs to be removed

@@ -483,10 +479,6 @@ public function setCustomStringFunctions(array $functions)
*/
public function addCustomNumericFunction($name, $className)
{
if (Query\Parser::isInternalFunction($name)) {
Copy link
Member

Choose a reason for hiding this comment

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

@throws in docblock needs to be removed

@@ -425,10 +425,6 @@ public function ensureProductionSettings()
*/
public function addCustomStringFunction($name, $className)
{
if (Query\Parser::isInternalFunction($name)) {
Copy link
Member

Choose a reason for hiding this comment

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

@throws in docblock needs to be removed

/**
* @var AggregateExpression
*/
public $aggregateExpression;
Copy link
Member

Choose a reason for hiding this comment

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

Can this be made private?

/**
* @inheritDoc
*/
public function parse(Parser $parser)
Copy link
Member

Choose a reason for hiding this comment

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

: void

*
* @return bool
*/
static public function isInternalFunction($functionName)
Copy link
Member

Choose a reason for hiding this comment

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

This method removal is potentially a BC break, and it needs to be documented in UPGRADE.md even though this is internal API

@@ -1579,10 +1579,14 @@ public function walkSimpleSelectExpression($simpleSelectExpression)
$sql .= $this->walkPathExpression($expr);
break;

case ($expr instanceof AST\AggregateExpression):
case ($expr instanceof AST\Functions\AvgFunction):
Copy link
Member

Choose a reason for hiding this comment

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

Since custom expressions are allowed, why not simply checking against $expr instanceof FunctionNode? Any reason why that wasn't done?

*/
private $aggregateExpression;

public function parse(Parser $parser)
Copy link
Member

Choose a reason for hiding this comment

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

Add return hints

$this->aggregateExpression = $parser->AggregateExpression();
}

public function getSql(SqlWalker $sqlWalker)
Copy link
Member

Choose a reason for hiding this comment

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

Add return hints

@Ocramius Ocramius added this to the 2.6.0 milestone Jun 19, 2017
@Ocramius Ocramius self-assigned this Jun 19, 2017
@ThePixelDeveloper
Copy link
Author

@Ocramius Think I've covered everything, although are you sure you want to have void return types? Just making sure. Tests are failing because of that reason alone.

@lcobucci
Copy link
Member

@ThePixelDeveloper @Ocramius tests are failing because these changes depends on #6507. I'll review your PR now 😉

Copy link
Member

@lcobucci lcobucci left a comment

Choose a reason for hiding this comment

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

Besides that it LGTM

* @since 2.6
* @author Mathew Davies <[email protected]>
*/
class AvgFunction extends FunctionNode
Copy link
Member

Choose a reason for hiding this comment

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

Since it's brand new class we can make it final, right?

Copy link
Member

Choose a reason for hiding this comment

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

Yup, they should all be final if they are new.

* @since 2.6
* @author Mathew Davies <[email protected]>
*/
class CountFunction extends FunctionNode
Copy link
Member

Choose a reason for hiding this comment

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

Since it's brand new class we can make it final, right?

* @since 2.6
* @author Mathew Davies <[email protected]>
*/
class MaxFunction extends FunctionNode
Copy link
Member

Choose a reason for hiding this comment

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

Since it's brand new class we can make it final, right?

* @since 2.6
* @author Mathew Davies <[email protected]>
*/
class MinFunction extends FunctionNode
Copy link
Member

Choose a reason for hiding this comment

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

Since it's brand new class we can make it final, right?

* @since 2.6
* @author Mathew Davies <[email protected]>
*/
class SumFunction extends FunctionNode
Copy link
Member

Choose a reason for hiding this comment

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

Since it's brand new class we can make it final, right?

@ThePixelDeveloper
Copy link
Author

@lcobucci Agreed, updated.

@lcobucci
Copy link
Member

@Ocramius @ThePixelDeveloper I've just rebased the branch to sync with master and I think it's good to go.

@Ocramius Ocramius merged commit 2560912 into doctrine:master Jun 20, 2017
@Ocramius
Copy link
Member

@lcobucci seen, :shipit:

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

Successfully merging this pull request may close these issues.

4 participants