Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upAdd a story for upsert #196
Comments
sgrif
referenced this issue
Apr 22, 2016
Closed
Provide an easy way to "insert or replace" or conditionally insert #296
sgrif
added this to the 0.7 milestone
Apr 22, 2016
This comment has been minimized.
|
Bumping to the 0.7 milestone. SQLite has extremely simple semantics, and we should at least be able to implement it for at least that backend. PG might get bumped to 0.8. I don't think we can abstract over this in a database agnostic way. Instead we will provide backend specific APIs. SQLite will probably be |
This comment has been minimized.
|
SQLite provides 5 options for alternate behaviors. |
added a commit
that referenced
this issue
Apr 23, 2016
sgrif
modified the milestones:
1.0,
0.7
Jun 27, 2016
This comment has been minimized.
|
Any ETA for postgres support ? :) |
This comment has been minimized.
|
Is this a blocker for your application? I can definitely get it done for 0.8 |
This comment has been minimized.
|
Yes, it's a blocker. |
sgrif
modified the milestones:
0.8,
1.0
Aug 1, 2016
This comment has been minimized.
|
Tentative release date for 0.8 is the 28th (if enough little things like this get completed I might release sooner though) |
This comment has been minimized.
|
Cool, thank you ! |
This comment has been minimized.
drusellers
commented
Oct 11, 2016
|
|
This comment has been minimized.
norcalli
commented
Nov 28, 2016
|
This doesn't seem to have made it into the 0.8 release for Postgres, is it possible to prioritize a backend specific method for the next release? If I have the time, I may be able to send a PR (over the next few weeks) |
This comment has been minimized.
|
It will be in the next release. 0.8 was featureless as we needed to get macros 1.1 support out. |
This comment has been minimized.
|
I'm going to release 0.9 today. Unfortunately, I wasn't able to complete this in time despite my best efforts. PG's upsert is an extremely complex feature, and it's just going to take some more time for me to implement proper support with an API that is up to our standards. I can't push back the 0.9 release any longer, as I am going on vacation on Tuesday and I want to release with enough time to fix any issues that may occur. So I will move this to the 0.10 release, which is slated for the end of January. |
sgrif
modified the milestones:
0.10,
0.9
Dec 8, 2016
This comment has been minimized.
norcalli
commented
Dec 8, 2016
|
I understand. |
This comment has been minimized.
norcalli
commented
Dec 8, 2016
|
I didn't mean to submit that comment, dang mobile. I understand, as I've had some dealings with trying to implement it myself in Scala/Slick, and I appreciate waiting to implement it properly. Have a good vacation! |
This comment has been minimized.
seamusabshere
commented
Feb 7, 2017
|
hey @sgrif do you have a WIP branch for this? |
This comment has been minimized.
|
@seamusabshere No, just a few spikes which I'm going to throw the code away from. |
This comment has been minimized.
|
I would be interested on working on this (as soon as I finish the |
This comment has been minimized.
|
That's the main thing I'm trying to decide on. I need to spike on it a bit more to decide for sure. I think it'll probably be something like the examples below. Feel free to take a swing at it if you'd like, but I suspect that implementing this properly will require a pretty thorough knowledge of our internals. I'm skipping all of the modifiers on the conflict target for now. I'm also unsure if I want to handle multiple on conflict clauses to start, but I've included it below. // In addition to the examples that I say must fail to compile, all of this must fail to compile if used with a backend other than PG.
// single record ON CONFLICT DO NOTHING
insert(&new_user.on_conflict_do_nothing()).into(users)
// multi-record ON CONFLICT DO NOTHING
insert(&vec![user1, user2].on_conflict_do_nothing()).into(users)
// Need to ensure that this does not compile
insert(&vec![user1.on_conflict_do_nothing()]).into(users)
// everything below should also work with vecs, should also fail to compile if the conflict handler is on a record inside the vec
// single record single handler by constraint name
insert(&new_user.on_conflict(on_constraint("users_pkey"), do_update().set(any_valid_as_changeset)).into(users)
// should fail to compile
insert(&new_user.on_conflict(on_constraint("users_pkey"), do_update().set(posts::title.eq("foo"))).into(users)
// single record single handler with where clause
insert(&new_user.on_conflict(on_constraint("users_pkey"), do_update().set(any_valid_as_changeset).filter(any_valid_predicate)).into(users)
// should fail to compile
insert(&new_user.on_conflict(on_constraint("users_pkey"), do_update().set(any_valid_as_changeset).filter(non_bool_expr)).into(users)
// should fail to compile
insert(&new_user.on_conflict(on_constraint("users_pkey"), do_update().set(any_valid_as_changeset).filter(posts::title.eq("hi"))).into(users)
// single record single handler by single column
insert(&new_user.on_conflict(id, do_update().set(any_valid_as_changeset)).into(users)
// single record single handler by multiple columns
insert(&new_user.on_conflict((project_id, email), do_update().set(any_valid_as_changeset)).into(users)
// single record single handler by arbitrary expr
insert(&new_user.on_conflict(lower(email), do_update().set(any_valid_as_changeset)).into(users)
// should fail to compile
insert(&new_user.on_conflict(posts::id, do_update().set(any_valid_as_changeset)).into(users)
// single record multiple handlers
insert(&new_user.on_conflict(any_valid_args).on_conflict(any_valid_args)).into(users)
// ON CONFLICT DO NOTHING with conflict_target
insert(&new_user.on_conflict(id, do_nothing()))I think that's everything, though I might have forgotten a few cases. |
This comment has been minimized.
|
Hmm, yeah, that's complicated enough that it would take me a long time to get up to speed. Are there any reasonably good ways to work around this missing feature? It turns out that we need it fairly badly in our Rust production app. I can obviously fall back to Any thoughts on the best way to tackle this? (I'm currently working on integration tests that prove we can mix |
This comment has been minimized.
|
Depending on how important actual atomicity is, the easiest workaround would just be to do a |
This comment has been minimized.
|
Yes, I agree. The hard part is mostly just making sure that incorrect uses fail to compile. |
This comment has been minimized.
seamusabshere
commented
Feb 13, 2017
|
hey @sgrif please do push this out to us if you have other priorities |
This comment has been minimized.
|
The plan is to have |
added a commit
that referenced
this issue
Feb 15, 2017
added a commit
that referenced
this issue
Feb 15, 2017
This comment has been minimized.
|
Removing from the milestone since |
sgrif
removed this from the 0.11 milestone
Feb 15, 2017
added a commit
that referenced
this issue
Feb 16, 2017
This comment has been minimized.
|
It's great to have this! I accidentally omitted
But this was then followed by dozens of lines of errors like the following:
I'm not sure what's going on with that error message, but in addition to spamming my error output console, it looks a bit suspicious. We do have |
This comment has been minimized.
|
It's a Rust bug, not a Diesel one. It sometimes does weird recursive trait lookups when the type at the bottom of it is a type error. |
This comment has been minimized.
|
Ah, thank you! Good to know. Is there an upstream bug for that which I can watch? I've fixed that, but now I'm hitting more weird errors. The following code compiles fine: for score in new_scores {
diesel::insert(&score.on_conflict_do_nothing())
.into(scores::table)
.execute(&*dconn)?;
}But if I change it to: for score_chunk in new_scores.chunks(5000) {
diesel::insert(&score_chunk.on_conflict_do_nothing())
.into(scores::table)
.execute(&*dconn)?;
}...I get:
I've tried several variations of the basic syntax, but it generally results in errors before reaching (I'm inserting rows in batches of 5,000 to avoid generating SQL |
This comment has been minimized.
|
Here's what happens:
The |
This comment has been minimized.
|
Yeah, maybe give |
This comment has been minimized.
|
The second produces:
There's probably a magic permutation which will work, but I haven't found it yet. |
This comment has been minimized.
|
Nope, I need to add a |
This comment has been minimized.
|
OK, cool. :-) Thank you for your help figuring this out! |
This comment has been minimized.
|
I'll release a 0.11.1 with #723 once it's green. |
sgrif
added this to the 0.12 milestone
Feb 17, 2017
added a commit
that referenced
this issue
Feb 23, 2017
This was referenced Feb 23, 2017
added a commit
that referenced
this issue
Feb 25, 2017
added a commit
that referenced
this issue
Mar 11, 2017
added a commit
that referenced
this issue
Mar 11, 2017
added a commit
that referenced
this issue
Mar 11, 2017
This comment has been minimized.
|
#793 implements this with two main exceptions:
These are both things that we will eventually support, but at the moment they are not prioritized. If you need one of those two features, please let me know. |
sgrif commentedFeb 6, 2016
This is currently a gap in our API. Both SQLite and PG support it, though I'm not sure we can do a backend agnostic abstraction. I'm fine with providing two backend specific abstractions for this case.