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

[6.x] Fix postgres grammar for nested json arrays #31448

Merged
merged 1 commit into from
Feb 12, 2020

Conversation

mathieutu
Copy link
Contributor

@mathieutu mathieutu commented Feb 12, 2020

Hi,
This PR fix a bug when quering postgres json field.

I have a json details field which contains :

{"firstName": "John", "lastName": "Doe", "phones": ["+33123456789", "+44123456789"]}

With this Eloquent query:

Contact::where([
    'details->firstName' => 'John',
    'details->lastName' => 'Doe',
    'details->phones->0' => '+33123456789',
])->firstOrFail();

The builder should return the row.

The problem is that the Postgres query generated is :

"select * from "contacts" where ("details"->>'firstName' = 'John' and "details"->>'lastName' = 'Doe' and "details"->'phones'->>'0' = '+33123456789') limit 1"

which return no result, and fail.

The working query is:

"select * from "contacts" where ("details"->>'firstName' = 'John' and "details"->>'lastName' = 'Doe' and "details"->'phones'->>0 = '+33123456789') limit 1"

See the difference:

- "details"->'phones'->>'0'
+ "details"->'phones'->>0

This PR fix this issue, by omitting the quote if the attribute is a integer.

A test was added.

Thanks.
Matt'

@staudenmeir
Copy link
Contributor

Please see #26415 (comment) on why this is a breaking change.

@@ -380,6 +380,10 @@ protected function wrapJsonBooleanValue($value)
protected function wrapJsonPathAttributes($path)
{
return array_map(function ($attribute) {
if (\strval(\intval($attribute)) === $attribute) {
Copy link
Member

Choose a reason for hiding this comment

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

Please don't use these val functions. Please use casts. They do the same.

@GrahamCampbell GrahamCampbell changed the title [6.x] Fix postgres grammar for nested json arrays. [6.x] Fix postgres grammar for nested json arrays Feb 12, 2020
@taylorotwell taylorotwell merged commit 53f3a81 into laravel:6.x Feb 12, 2020
@taylorotwell
Copy link
Member

Ah, just saw @staudenmeir's comment. Will likely have to revert.

@taylorotwell
Copy link
Member

@staudenmeir this seems like a slightly different situation than the issue you linked?

@mathieutu
Copy link
Contributor Author

mathieutu commented Feb 12, 2020

Actually here the Contact I would like to fetch is created with:

Contact::create([
    'details->firstName' => 'John',
    'details->lastName' => 'Doe',
    'details->phones->0' => '+33123456789',
]);

This is the behavior of Laravel (and even of php json_encode actually) to set the phones->0 to an array, instead of an object with key 0.

Also, it feels quite normal to be able to query an entity by the same arguments it was created.

Update works exactly the same.

In my opinion, not considering this as a bug and set the opposite as the default would be quite weird.

However, we can provide a way to force the understanding of the query as string, like details->phones->'0'. (And I can make the PR if it helps approving this one)

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.

4 participants