piccolo-orm / piccolo

A fast, user friendly ORM and query builder which supports asyncio.
https://piccolo-orm.com/
MIT License
1.46k stars 91 forks source link

increment number count using object style #1073

Closed trondhindenes closed 2 months ago

trondhindenes commented 2 months ago

It would be good if it was possible to do something like:

band = await Band.objects().get(Band.name == 'Pythonistas')
assert band.count == 1
band.count.increment(1)
band = await band.update()
assert band.count == 2

that is, using "database-level" number increments together woth "object-style" queries. I can't find any sign of this in the documentation, so I guess only dict-style queries support "server-side" increments atm?

dantownsend commented 2 months ago

If there's a number in the database which you want to increment, you can do it with update queries.

# If we have this table
class Concert(Table):
    tickets_available = Integer()

We can change the value like this:

# If we have this table
await Concert.update({
    Concert.tickets_available: Concert.tickets_available + 1
}).where(Concert.id == some_id)

If you have an object, you can do this:

concert = await Concert.objects().where(Concert.id == some_id).first()
concert.tickets_available += 1
await concert.save()

The problem with the approach above is if there are multiple saves at the same time - the tickets_available might be incorrect.

So you're suggesting something like this:

concert = await Concert.objects().where(Concert.id == some_id).first()
await concert.increment(Concert.tickets_available)

# Where increment effectively runs this query under the hood:
await Concert.update({
    Concert.tickets_available: Concert.tickets_available + 1
}).where(
    Concert.id == concert.id
).returning(
    Concert.tickets_available
)

Yeah, I can definitely see the use case.

trondhindenes commented 2 months ago

yup, the idea was to have a "visibly separate" syntax for letting the database calculate the increment as apposed to do it in code, which as you mention might produce unexpected results

dantownsend commented 2 months ago

I was thinking about it, and the best solution I could come up with is having an update_self method, which just updates the object it's called on. It's more flexible than having dedicated increment / decrement methods.

trondhindenes commented 2 months ago

that would work!

dantownsend commented 2 months ago

This is done now - will be in the next release.

Thanks for raising this issue, I think it'll be a useful feature.

trondhindenes commented 2 months ago

good! Thanks for the quick feedback as always!