-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Add support for conditionally inserting a single row. #2528
Conversation
I'm going to pass for now, thanks. |
Hi @coleifer would you have another suggestion for being able to accomplish the insert myself? I came up with this but do not like it. Is there a better way?
|
I'd suggest just wrapping it up in a helper method on a BaseModel class you keep in your library: class BaseModel(Model):
@classmethod
def insert_where(cls, data, *where):
fields, values = zip(*data.items())
sq = Select(columns=values).where(~fn.EXISTS(cls.select().where(*where)))
return cls.insert_from(sq, fields)
ins = Tweet.insert_where({
Tweet.content: 'my_tweet',
Tweet.user: user,
Tweet.timestamp: datetime.now()},
(Tweet.user == user) & (Tweet.timestamp > datetime.now() - timedelta(hours=1))) |
Sweet, thank you. |
I've gone ahead and thrown this into the from playhouse import shortcuts
class BaseModel(Model):
@classmethod
def insert_where(cls, data, *where):
return shortcuts.insert_where(cls, data, *where) |
Hi @coleifer Thank you. I have a few suggestions. Please let me know what you think.
Here is the function that I've been using this weekend for my application:
This let's me use it in the following way:
I like this API because it closely resembles This also automatically provides default values like The |
Adding the defaults and providing more flexibility definitely seems fine to me. Check out 23ae5d2 -- I'm still returning the query rather than executing it, since that is the common pattern in Peewee. But most of the other changes you described are present. |
Hello,
This PR enables conditional insertion of a single row, with default values automatically provided, in a single trip to the database.
Would you be willing to support this syntactic sugar?
In this example, we are conditionally inserting a Tweet, so long as the User has not already tweeted in the last hour, via a single trip to the DB:
This would translate into the following SQL (Note the replacement of VALUES with SELECT)
This PR is a POC with minimal code changes to get this working. You could either use this PR or redo it yourself according to your preference. I could add some documentation or tests to beef up this PR later if you are on board with the idea.
I've tested both cases where it successfully inserts and returns the PK or when it does not insert and returns None instead.
You might wonder what the point of this is since you could just do it like the following:
The main problem with this is that it requires two remote calls to the database.
The secondary issue is that it has a race condition when another thread modifies the User row after the exists() check and before the Tweet.insert. (Actually, my solution also has a race condition - I think - but it is a much smaller window, by an order of magnitude, compared to using two remote calls).
The only other way to accomplish this right now that I've figured out is a bit ugly and doesn't compute default values.