-
Notifications
You must be signed in to change notification settings - Fork 11.2k
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
[10.x] database expressions with grammar-specific formatting #44784
Conversation
This would be really nice in my opinion! This would make the DB expressions more typesafe. |
This is pretty slick, nicely done. Two things: First, is the Second, should we preserve the |
That is a typo. I simplified the example to make it easier to understand and missed the new keyword.
That's not easily possible. We could do that but then we have two different expression implementations that need to be handled differently. And I guess almost no one really extended the |
I can see how this PR seems like a good compromise. It basically expands the In summary, I don't particularly like the code that will be written as a result of this feature, but this feature in itself isn't that much harmful to the framework. I just wonder whether there's a simpler approach to provide the Grammar to the Expression class with less changes, but that requires digging deeper... |
Can you provide the breaking changes and the upgrade steps we would need to include in the 10.x upgrade guide if this is merged? |
Sure. Breaking ChangesThe Upgrade GuideIf you use |
@tpetry It might also be worth noting that because of the removal from I wonder if we could add that back somehow? I am however not even sure if doing |
I am not sure whether that counts as a breaking change for users of Laravel, as only the Laravel core is transforming those expressions into strings. I did choose against both ways to get the string for an expression because it increases the complexity of handling those expressions. One way is more straightforward than two ways. And as I said, I don't expect anyone having extended those classes. I only found the idea of doing it in a tweet which I used as an idea to work on this PR. |
@tpetry That is fantastic. What do you think about adding a separate |
As said before, I found no one really extending the |
I think this look fairly good to me if we can get the conflicts fixed @tpetry 👍 |
1bccc11
to
c09a9fc
Compare
@taylorotwell Done. Rebased it on the newest |
Thanks! 👍 |
@tpetry I'm curious, in what case would an expression ever return anything but a SQL string from |
An integer or float is still representable as string. And it was completely valid to use them before, so I doesnt want to break this. |
@tpetry I know it allowed those types previously, I was just wondering if there was an example of a situation in which something other than a string would need to be returned. |
Hey @tpetry - I've finally finished my review of this. Thanks for your patience! I wanted to get some further elaboration on your "Outlook" section regarding adding bindings / quoted values from the expression. What was your thoughts there on how that would work. While this PR definitely provides an improvement over our current expression capabilities, I can see people quickly asking for the ability for their expressions to be able to safely add bindings to the query. Any thoughts on how that would look or be implemented? |
I did that in my old PR. Basically we have to the grammar. In the future (in my opinion) the query grammar instance should contain a database connection object (PDO). That way it could provide escaping of raw content based on the current connection settings (the charset encoding is important with mysql to prevent sql injections!) or export the version number of the database (to use newer sql features when available). I could work backport this one tomorrow or tuesday if this merged. And we‘ll check it for 10.x or better plan it for 11.x. |
@tpetry now that I have a pretty decent grasp of this PR we can just try to expose the PDO connection to the grammar with another commit on this PR if you don't mind? |
I can do that, on tomorrow. If those changes are then too much for you, feel free to just revert the additional commit. |
While thinking about it, I would like to delay that change about linking the grammar with the connection. I don‘t want to break the 10.x release. Let me work on the grammar thing in a backward compatible way within L10. I guess other db providers (like mine, staudenmeier or singlestore) may break with such a change? Its a little bit late for that in the 10.x process. I‘ll find a way shortly after the 10.x release for grammars to opt-in for that feature if they want support it. |
@taylorotwell Sorry, I did write the last message misleading last night. I am ok with merging this PR. Adding the connection to grammars I would like to work on shortly after the 10.x release to do it in a safe backwards-compatible way. I don‘t want to break other non-core drivers so shortly before the final release. |
Signed-off-by: Mior Muhammad Zaki <[email protected]>
Signed-off-by: Mior Muhammad Zaki <[email protected]>
The `Expression` class no longer provides a `__toString()` method, so we cannot cast it to a string here. We'll now use the `->getValue()` method and pass the current database connection's query grammar. laravel#44784
The `Expression` class no longer provides a `__toString()` method, so we cannot cast it to a string here. We'll now use the `->getValue()` method and pass the current database connection's query grammar. #44784
The `Expression` class no longer provides a `__toString()` method, so we cannot cast it to a string here. We'll now use the `->getValue()` method and pass the current database connection's query grammar. laravel#44784
Was there a reason for not just passing in an extension of https://www.php.net/manual/en/class.stringable.php I might be missing something? |
@tpetry Why did you not add the classes like |
Last year I proposed PR #40115 to change database expressions to be grammar-enhanced. But my PR was changing too much, so I redid the whole concept to change as least as possible to be easier to merge for the next Laravel major release.
What is the problem?
Laravel's database implementation provides us a good way of working with multiple databases while abstracting away the inner workings. We don't have to think about small syntax differences when using a query builder or how column names are escaped to not interfere with reserved keywords.
However, when we want to use more database functionality we have to fall back to raw database code and writing database-specific code to e.g. quote column names or column aliases:
How can this be solved?
Currently the
Expression
class returned byDB::raw
is just a container to indicate that the value should not be further processed. My implementation changes that approach a little bit by declaring an expression contractDB::raw
uses and custom classes can implement:Following that idea, the operations normally done by raw expressions and statements can be created as reusable expression classes. The former example could be written like this, which is totally database-agnostic for the one using those classes instead of raw expressions:
But isn't it much work to write those classes?
Kind of. But keep in mind these have to be written only once and you don't have to be the one. Like with every package created by the community anyone can start and write those SQL expressions for anyone to use. When this PR will be merged into 10.x I will start by writing the most common ones at tpetry/laravel-query-expressions.
But I don't like the syntax
That's ok as I don't propose any syntax, I propose a system of how this can work. You can start a package that will provide a macro-able facade to do the same with static function calls as long as those calls return expression objects:
An implementation even doesn't have to use this wrapping. I can imagine a parser could transform a special little syntax to create those object chains from a string:
As said, this PR is not about providing syntax. It is about adding a building block packages can use to build something great
Outlook
In future PRs I would like to work on more things useful for database expressions:
Grammar
would provide methods to identify it as e.g. a MySQL grammar, the expression could use a different function for regex replacement than for e.g. PostgreSQL.Grammar
would provide method toquote()
a value these could be safely injected into an expression.Grammar
would provide the database type and version a grammar class could use best implementation for every database and version.