changeset 3862:100dd30244c6

core (memory/sqla): add argument to `getPubsubNode` to auto-create a node: if the node is not in cache, the new `create` and `create_kwargs` arguments can be used to automatically call `setPubsubNode` rel 370
author Goffi <goffi@goffi.org>
date Wed, 20 Jul 2022 17:41:44 +0200
parents 37a1193d90db
children c04f5e8a3568
files sat/memory/sqla.py
diffstat 1 files changed, 37 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/sat/memory/sqla.py	Wed Jul 20 17:19:53 2022 +0200
+++ b/sat/memory/sqla.py	Wed Jul 20 17:41:44 2022 +0200
@@ -47,7 +47,7 @@
 from sat.core.log import getLogger
 from sat.core.constants import Const as C
 from sat.core.core_types import SatXMPPEntity
-from sat.tools.utils import aio
+from sat.tools.utils import aio, as_future
 from sat.tools.common import uri
 from sat.memory import migration
 from sat.memory import sqla_config
@@ -1059,8 +1059,18 @@
         name: str,
         with_items: bool = False,
         with_subscriptions: bool = False,
+        create: bool = False,
+        create_kwargs: Optional[dict] = None
     ) -> Optional[PubsubNode]:
-        """
+        """Retrieve a PubsubNode from DB
+
+        @param service: service hosting the node
+        @param name: node's name
+        @param with_items: retrieve items in the same query
+        @param with_subscriptions: retrieve subscriptions in the same query
+        @param create: if the node doesn't exist in DB, create it
+        @param create_kwargs: keyword arguments to use with ``setPubsubNode`` if the node
+            needs to be created.
         """
         async with self.session() as session:
             stmt = (
@@ -1080,7 +1090,31 @@
                     joinedload(PubsubNode.subscriptions)
                 )
             result = await session.execute(stmt)
-        return result.unique().scalar_one_or_none()
+        ret = result.unique().scalar_one_or_none()
+        if ret is None and create:
+            # we auto-create the node
+            if create_kwargs is None:
+                create_kwargs = {}
+            try:
+                return await as_future(self.setPubsubNode(
+                    client, service, name, **create_kwargs
+                ))
+            except IntegrityError as e:
+                if "unique" in str(e.orig).lower():
+                    # the node may already exist, if it has been created just after
+                    # getPubsubNode above
+                    log.debug("ignoring UNIQUE constraint error")
+                    cached_node = await as_future(self.getPubsubNode(
+                        client,
+                        service,
+                        name,
+                        with_items=with_items,
+                        with_subscriptions=with_subscriptions
+                    ))
+                else:
+                    raise e
+        else:
+            return ret
 
     @aio
     async def setPubsubNode(