From f12abb3055e632359a089bb57e3691cb5118d3c7 Mon Sep 17 00:00:00 2001
From: Rainer Kartmann <rainer.kartmann@kit.edu>
Date: Fri, 11 Jun 2021 14:50:32 +0200
Subject: [PATCH] Add resolveEntityInstance(s)

---
 .../armem/client/MemoryNameSystem.cpp         | 70 +++++++++++++++++++
 .../libraries/armem/client/MemoryNameSystem.h | 23 ++++++
 .../libraries/armem/client/Reader.cpp         | 23 ++++++
 .../RobotAPI/libraries/armem/client/Reader.h  | 20 ++++++
 4 files changed, 136 insertions(+)

diff --git a/source/RobotAPI/libraries/armem/client/MemoryNameSystem.cpp b/source/RobotAPI/libraries/armem/client/MemoryNameSystem.cpp
index 98c6f0cca..8f077e0fc 100644
--- a/source/RobotAPI/libraries/armem/client/MemoryNameSystem.cpp
+++ b/source/RobotAPI/libraries/armem/client/MemoryNameSystem.cpp
@@ -224,6 +224,76 @@ namespace armarx::armem::client
     }
 
 
+    std::optional<wm::EntityInstance> MemoryNameSystem::resolveEntityInstance(const MemoryID& id)
+    {
+        auto result = resolveEntityInstances({id});
+        if (result.size() > 0)
+        {
+            return result.begin()->second;
+        }
+        else
+        {
+            return std::nullopt;
+        }
+    }
+
+
+    std::map<MemoryID, wm::EntityInstance> MemoryNameSystem::resolveEntityInstances(const std::vector<MemoryID>& ids)
+    {
+        std::stringstream errors;
+
+        std::map<std::string, std::vector<MemoryID>> idsPerMemory;
+        for (const auto& id : ids)
+        {
+            idsPerMemory[id.memoryName].push_back(id);
+        }
+
+        std::map<MemoryID, wm::EntityInstance> result;
+        for (const auto& [memoryName, ids] : idsPerMemory)
+        {
+            Reader reader = getReader(MemoryID().withMemoryName(memoryName));
+            QueryResult queryResult = reader.queryMemoryIDs(ids);
+            if (queryResult.success)
+            {
+                for (const MemoryID& id : ids)
+                {
+                    try
+                    {
+                        if (id.hasInstanceIndex())
+                        {
+                            result[id] = queryResult.memory.getEntityInstance(id);
+                        }
+                        else if (id.hasTimestamp())
+                        {
+                            result[id] = queryResult.memory.getEntitySnapshot(id).getInstance(0);
+                        }
+                        else // must: id.hasEntityName()
+                        {
+                            result[id] = queryResult.memory.getEntity(id).getLatestSnapshot().getInstance(0);
+                        }
+                    }
+                    catch (const error::ArMemError& e)
+                    {
+                        errors << "# Failed to retrieve " << id << " from query result: \n" << e.what() << "\n";
+                    }
+                }
+            }
+            else
+            {
+                errors << "# Failed to query '" << memoryName << "': \n" << queryResult.errorMessage << "\n";
+            }
+        }
+
+        if (errors.str().size() > 0)
+        {
+            ARMARX_INFO << "MemoryNameSystem::" << __FUNCTION__ << ": The following errors may affect your result: "
+                        << "\n\n" << errors.str();
+        }
+
+        return result;
+    }
+
+
     void MemoryNameSystem::registerServer(const MemoryID& memoryID, server::MemoryInterfacePrx proxy)
     {
         data::RegisterMemoryInput input;
diff --git a/source/RobotAPI/libraries/armem/client/MemoryNameSystem.h b/source/RobotAPI/libraries/armem/client/MemoryNameSystem.h
index 0d6a3f3b6..dad7cde70 100644
--- a/source/RobotAPI/libraries/armem/client/MemoryNameSystem.h
+++ b/source/RobotAPI/libraries/armem/client/MemoryNameSystem.h
@@ -22,6 +22,9 @@
 
 #pragma once
 
+#include <map>
+#include <optional>
+
 #include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h>
 #include <RobotAPI/interface/armem/server/MemoryInterface.h>
 
@@ -38,6 +41,11 @@ namespace armarx::armem::client
     class Writer;
 }
 
+namespace armarx::armem::wm
+{
+    class EntityInstance;
+}
+
 namespace armarx::armem::client
 {
 
@@ -190,6 +198,20 @@ namespace armarx::armem::client
 
         // ToDo: commit() and query()
 
+        /**
+         * @brief Resolve a memory ID to an EntityInstance.
+         *
+         * The ID can refer to an entity, an entity snapshot, or an entity
+         * instance. When not referring to an entity instance, the latest
+         * snapshot and first instance will be queried.
+         *
+         * @param id The entity, snapshot or instance ID.
+         * @return
+         */
+        std::optional<wm::EntityInstance> resolveEntityInstance(const MemoryID& id);
+
+        std::map<MemoryID, wm::EntityInstance> resolveEntityInstances(const std::vector<MemoryID>& ids);
+
 
 
         // Registration - only for memory servers
@@ -234,6 +256,7 @@ namespace armarx::armem::client
 
         /// The MNS proxy.
         mns::MemoryNameSystemInterfacePrx mns = nullptr;
+
         /// The component to which dependencies will be added.
         ManagedIceObject* component = nullptr;
 
diff --git a/source/RobotAPI/libraries/armem/client/Reader.cpp b/source/RobotAPI/libraries/armem/client/Reader.cpp
index 011948cc2..fc4775bc3 100644
--- a/source/RobotAPI/libraries/armem/client/Reader.cpp
+++ b/source/RobotAPI/libraries/armem/client/Reader.cpp
@@ -83,6 +83,29 @@ namespace armarx::armem::client
         return this->query(qb.buildQueryInput());
     }
 
+
+    QueryResult Reader::queryMemoryIDs(const std::vector<MemoryID>& ids, DataMode dataMode) const
+    {
+        using namespace client::query_fns;
+
+        query::Builder qb(dataMode);
+        for (const auto& id : ids)
+        {
+            auto entity = qb.coreSegments(withID(id)).providerSegments(withID(id)).entities(withID(id));
+
+            if (id.hasTimestamp())
+            {
+                entity.snapshots(withID(id));
+            }
+            else
+            {
+                entity.snapshots(latest());
+            }
+        }
+        return query(qb.buildQueryInput());
+    }
+
+
     void
     Reader::updated(const std::vector<MemoryID>& updatedSnapshotIDs) const
     {
diff --git a/source/RobotAPI/libraries/armem/client/Reader.h b/source/RobotAPI/libraries/armem/client/Reader.h
index 5cbeff84a..ae2548f29 100644
--- a/source/RobotAPI/libraries/armem/client/Reader.h
+++ b/source/RobotAPI/libraries/armem/client/Reader.h
@@ -55,9 +55,29 @@ namespace armarx::armem::client
         QueryResult getAll(DataMode dataMode = DataMode::WithData) const;
         QueryResult getLatestSnapshots(DataMode dataMode = DataMode::WithData) const;
 
+
+        /**
+         * @brief Qeury a specific set of memory IDs.
+         *
+         * Each ID can refer to an entity, a snapshot or an instance. When not
+         * referring to an entity instance, the latest snapshot and first
+         * instance will be queried, respectively.
+         *
+         * All memory IDs must refer to the memory this reader is reading from.
+         * If an ID refers to another memory, the query will not find it and it
+         * will not be part of the result.
+         *
+         * @param ids The entity, snapshot or instance IDs.
+         * @param dataMode Whether to include instance data or just meta data.
+         * @return The query result.
+         */
+        QueryResult queryMemoryIDs(const std::vector<MemoryID>& ids, DataMode dataMode = DataMode::WithData) const;
+
+
         //data::StoreResult readAndStore(data::StoreInputSeq& input);
         data::StoreResult readAndStore(const data::StoreInput& input) const;
 
+
         void subscribe(const MemoryID& subscriptionID, callback callback);
         void subscribe(const MemoryID& subscriptionID, callback_updated_only callback);
         /**
-- 
GitLab