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] JSON update for SQLite #31472

Closed
wants to merge 1 commit into from
Closed

[6.x] JSON update for SQLite #31472

wants to merge 1 commit into from

Conversation

iamgergo
Copy link
Contributor

This PR implements an SQLite specific update for nested JSON columns and paths.


When using SQLite, an Eloquent update like this:

Customer::whereIn('id', [1, 2, 3])->update([
    'meta->size' => 'L',
]);

Compiles to an SQL like this:

update "customers" set json_extract("meta", '$."size"') = 'L' where "id" in (1, 2, 3)

This is not a valid update query. This happens only when trying to update multiple models at the same time.


By checking if the column is JSON when compiling update queries, it's possible to fix this and update the value that belongs to the JSON path. The update statement for a JSON column should look like this:

update "customers" set "meta" = (select json_set(ifnull("meta", json('{}')), '$."size"', 'L'));

The JSON column can be null. If it is, the update query won't affect the column. By adding an empty JSON object as a fallback, json_set can put the value in the desired path.


Unfortunately, this approach has some pitfalls as well. For example:

Customer::whereIn('id', [1, 2, 3])->update([
    'meta->size' => 'L',
    'meta->color' => 'yellow',
    'options->security' => ['2fa'],
]);

In this case, the meta->color update will override the meta->size update, which means it will keep its original value.


Adding JSON update support to SQLite (even partially) would be a great help when using test environments.

As far as I know, this is not a breaking change.

@taylorotwell
Copy link
Member

taylorotwell commented Feb 14, 2020

Not merging because of the listed pitfalls. Why introduce more bugs? If you need more robust JSON support, use MySQL or Postgres.

@mfn
Copy link
Contributor

mfn commented Feb 17, 2020

Adding JSON update support to SQLite (even partially) would be a great help when using test environments.

Does only defers possible problems. The best advice is: always use the same stack for testing as in production, aka same database. "problem solved".

Yes, it's likely slower and needs some adaption.

But tests are for asserting correctness and different SQL engines behave differently (q.e.d) so for proper project it doesn't make sense to try to work this around.

@iamgergo
Copy link
Contributor Author

I agree the same stack should be used for testing and production to ensure things are working.

However, what if someone just wants to validate a concept, or to start a smaller package/project and later switch to a more robust database? For those who start testing/developing with SQLite, it can be a small help to have a bit wider support for SQLite.

Also, the new PR does not have the listed pitfalls. Still, of course, SQLite has more limited JSON support than MySQL for example. So, yes for a real project should use MySQL or Postgres.

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.

3 participants