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

[8.x] Add castAsJson method for database assertions #34302

Merged
merged 2 commits into from Sep 14, 2020

Conversation

browner12
Copy link
Contributor

database fields of type 'json' cannot be evaluated using strings, they must be cast to a database specific JSON type.

$this->assertDatabaseHas('users', [
    'name' => 'Peter Parker',
    'email' => 'spidey@yahoo.com',
    'skills' => $this->castAsJson(json_encode(['web slinging', 'spidey-sense', 'sticky feet'])),
]);

database fields of type 'json' cannot be evaluted using strings, they must be cast to a database specific JSON type.
@GrahamCampbell GrahamCampbell changed the title [8.x] add castAsJson method for database assertions [8.x] Add castAsJson method for database assertions Sep 12, 2020
@taylorotwell
Copy link
Member

It feels like this should be more automatic maybe?

@browner12
Copy link
Contributor Author

that would be nice, but I'm not sure that would be reasonably possible. you'd have to know/query the field type prior.

even if you had the Model, you couldn't base it off that, because some people use the 'json' cast, but still use a 'longtext' or similar as the database type, and we don't need to do this for those field types.

If you have a thought on how to accomplish this, I'm definitely open to it.

@laurencei
Copy link
Contributor

laurencei commented Sep 14, 2020

If you are calling the function castAsJson - why do you need to call json_encode for the string you are passing it?

i.e.

- $this->castAsJson(json_encode(['web slinging', 'spidey-sense', 'sticky feet'])),
+ $this->castAsJson(['web slinging', 'spidey-sense', 'sticky feet']),

And then have the function do the json_encoding() itself?

@browner12
Copy link
Contributor Author

PHP JSON encoding is different than database type casting.

I'm passing in an array, so first that needs to be encoded as a string, and then that string needs to be cast to JSON in the database query.

@laurencei
Copy link
Contributor

laurencei commented Sep 14, 2020

Sorry - I was not very clear - I meant then do the json_encoding in the other function. Something like this:

    public function castAsJson($value)
    {
+        $value = json_encode($value);
         return DB::raw("CAST('$value' AS JSON)");
    }

@browner12
Copy link
Contributor Author

Ah, I see. I go back and forth on if that's the responsibility of this method. I'm not sure if there'd be a scenario where someone already has a value as JSON, so then they would need to decode it prior to passing it to the function, so it doesn't get double encoded.

Honestly, I could go either way on this, so would be open to hearing other people's opinions.

@taylorotwell taylorotwell merged commit 18940d5 into laravel:8.x Sep 14, 2020
@browner12 browner12 deleted the json-assertions branch September 14, 2020 14:12
@halloei
Copy link
Contributor

halloei commented Sep 17, 2020

What's still missing here is escaping. $this->castAsJson(['\Some\Class']) will fail.
I am using the solution of talentia, which you can find in this answer: https://laracasts.com/discuss/channels/testing/how-to-assert-that-the-database-contains-a-value-stored-as-json?page=1#reply=416476
Here, addslashes() and null checks are used.

@vlakoff
Copy link
Contributor

vlakoff commented Jun 11, 2021

Refs #37619

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.

None yet

5 participants