`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: blacklight
GPG Key ID: D90FBA7F76362774
1 changed files with 6 additions and 13 deletions

View File

@ -3,7 +3,6 @@ from dataclasses import dataclass
from typing import Dict, Iterable, List, Tuple
from sqlalchemy import and_, or_
from sqlalchemy.exc import InvalidRequestError
from sqlalchemy.orm import Session
from platypush.context import get_plugin
@ -179,18 +178,12 @@ class EntitiesDb:
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()
)
# 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