BeanieODM / beanie

Asynchronous Python ODM for MongoDB
http://beanie-odm.dev/
Apache License 2.0
2.04k stars 215 forks source link

[BUG] `save_changes()` doesn't throw an error when document doesn't exists #470

Closed Luc1412 closed 1 year ago

Luc1412 commented 1 year ago

Describe the bug In 1.11.9 state was changed and always defaults being not None, instead it got a dict with the default values. This causes check_if_state_saved to never throw an error.

save_changes on a new created document that isn't saved in the database silently does nothing.

To Reproduce

user_data = UserEntry(...)
user_data.x = ...
await user_data.save_changes()

Expected behavior StateNotSaved("No state was saved") Additional context https://github.com/roman-right/beanie/compare/1.11.8...1.11.9 https://canary.discord.com/channels/822196934973456394/822196935435747332/1042243293662158970

roman-right commented 1 year ago

Hi. I'll check this and fix it this week. Thank you for the issue.

Luc1412 commented 1 year ago

@roman-right Any news regarding this?

roman-right commented 1 year ago

Hi,

Could you pls re-check this with the newest version?

I'm trying this:

import asyncio

import motor.motor_asyncio

from beanie import Document
from beanie import init_beanie

class User(Document):
    s: str = "TEST"

    class Settings:
        use_state_management = True

async def main():
    cli = motor.motor_asyncio.AsyncIOMotorClient(
        "mongodb://beanie:beanie@localhost:27017")
    db = cli["test_id"]
    await init_beanie(db, document_models=[User])

    user = User()
    user.s = "SMTH"
    await user.save_changes()

asyncio.run(main())

And it raises the error

Luc1412 commented 1 year ago

I tried 1.17.0, 1.18.0b0 and master. In all cases I got no error

Luc1412 commented 1 year ago

The problem is Document._saved_state is not None, instead it got the default values on init.

The exception is raised when _saved_state is None which is never the case

Luc1412 commented 1 year ago

@roman-right Do you where able to reproduce the issue?

roman-right commented 1 year ago

No, I didn't.

Could you pls run this and tell me what was printed for you:

import asyncio

import motor.motor_asyncio

from beanie import Document
from beanie import init_beanie

class User(Document):
    s: str = "TEST"

    class Settings:
        use_state_management = True

async def main():
    cli = motor.motor_asyncio.AsyncIOMotorClient(
        "mongodb://beanie:beanie@localhost:27017")
    db = cli["test_id"]
    await init_beanie(db, document_models=[User])

    user = User()
    user.s = "SMTH"
    print(user._saved_state)
    # await user.save_changes()

asyncio.run(main())
Luc1412 commented 1 year ago

@roman-right My bad. I simplified the reproduction code too much. It seems it's connected with changing the _id type. Here my repro code:

import asyncio

import beanie
import motor.motor_asyncio

from beanie import init_beanie

class User(beanie.Document):
    id: int
    s: str = "TEST"

    class Settings:
        use_state_management = True

async def main():
    cli = motor.motor_asyncio.AsyncIOMotorClient(
        "mongodb://beanie:beanie@localhost:27017"
    )
    await init_beanie(cli.get_default_database(), document_models=[User])

    print(beanie.__version__)

    user = User(id=1999)
    user.s = "SMTH"
    print(user._saved_state)
    # await user.save_changes()

if __name__ == "__main__":
    asyncio.run(main())

Print result:

1.11.9
{'_id': 1999, 's': 'TEST'}

in Document._save_state there is a condition if self.use_state_management() and self.id is not None:. As ID got a value, the state gets set

roman-right commented 1 year ago

Yes, I confirm. It is reproducible now. Thank you. It will be fixed shortly