EntitiesDb.upsert should return a deep copy of the upserted entities.

Not the upserted entities themselves, no matter if expunged or made transient.

Reminder to my future self: returning the flushed entities and then using them
outside of the session or in another thread opens a big can of worms when using
SQLAlchemy.
This commit is contained in:
Fabio Manganiello 2023-03-10 12:06:36 +01:00
parent f45e47363d
commit 31552963c4
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774

View file

@ -3,7 +3,6 @@ from dataclasses import dataclass
from typing import Dict, Iterable, List, Tuple from typing import Dict, Iterable, List, Tuple
from sqlalchemy import and_, or_ from sqlalchemy import and_, or_
from sqlalchemy.exc import InvalidRequestError
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from platypush.context import get_plugin from platypush.context import get_plugin
@ -179,18 +178,12 @@ class EntitiesDb:
session.commit() session.commit()
all_entities = list( # Make a copy of the entities in the batch, so they can be used outside
# of this session/thread without the DetachedInstanceError pain
return list(
{ {
entity.entity_key: entity for batch in batches for entity in batch entity.entity_key: entity.copy()
for batch in batches
for entity in batch
}.values() }.values()
) )
# Remove all the entities from the existing session, so they can be
# accessed outside of this context
for e in all_entities:
try:
session.expunge(e)
except InvalidRequestError:
pass
return all_entities