From 8e2f1f5ef1175d95e9c526e95552a1821618c7cb Mon Sep 17 00:00:00 2001
From: Rainer Kartmann <rainer.kartmann@kit.edu>
Date: Wed, 23 Jun 2021 08:21:46 +0200
Subject: [PATCH] Reduce includes in Reader.h, add special queries

---
 .../RobotAPI/libraries/armem/client/Query.h   |   8 +
 .../libraries/armem/client/Reader.cpp         | 144 +++++++++++++++---
 .../RobotAPI/libraries/armem/client/Reader.h  |  61 +++++++-
 3 files changed, 187 insertions(+), 26 deletions(-)

diff --git a/source/RobotAPI/libraries/armem/client/Query.h b/source/RobotAPI/libraries/armem/client/Query.h
index b22c88001..4f5a87bdc 100644
--- a/source/RobotAPI/libraries/armem/client/Query.h
+++ b/source/RobotAPI/libraries/armem/client/Query.h
@@ -9,8 +9,16 @@
 #include <RobotAPI/libraries/armem/core/workingmemory/Memory.h>
 
 
+namespace armarx::armem::client::query
+{
+    // #include <RobotAPI/libraries/armem/client/query/Builder.h>
+    class Builder;
+}
+
 namespace armarx::armem::client
 {
+    using QueryBuilder = query::Builder;
+
 
     /**
      * @brief An update of an entity for a specific point in time.
diff --git a/source/RobotAPI/libraries/armem/client/Reader.cpp b/source/RobotAPI/libraries/armem/client/Reader.cpp
index b548e7aab..a589512f1 100644
--- a/source/RobotAPI/libraries/armem/client/Reader.cpp
+++ b/source/RobotAPI/libraries/armem/client/Reader.cpp
@@ -4,6 +4,13 @@
 
 #include <ArmarXCore/core/logging/Logging.h>
 
+#include <RobotAPI/libraries/armem/core/MemoryID_operators.h>
+#include <RobotAPI/libraries/armem/core/longtermmemory/Memory.h>
+#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h>
+#include <RobotAPI/libraries/armem/core/workingmemory/visitor.h>
+#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h>
+#include <RobotAPI/libraries/armem/util/util.h>
+
 #include "query/Builder.h"
 #include "query/query_fns.h"
 
@@ -22,6 +29,7 @@ namespace armarx::armem::client
         return QueryResult::fromIce(query(input.toIce()));
     }
 
+
     armem::query::data::Result
     Reader::query(const armem::query::data::Input& input) const
     {
@@ -52,11 +60,13 @@ namespace armarx::armem::client
         return result;
     }
 
+
     QueryResult Reader::query(armem::query::data::MemoryQueryPtr query, DataMode dataMode) const
     {
         return this->query(armem::query::data::MemoryQuerySeq{query}, dataMode);
     }
 
+
     QueryResult Reader::query(const armem::query::data::MemoryQuerySeq& queries, DataMode dataMode) const
     {
         QueryInput input;
@@ -65,24 +75,10 @@ namespace armarx::armem::client
         return this->query(input);
     }
 
-    QueryResult Reader::getAll(DataMode dataMode) const
-    {
-        using namespace client::query_fns;
-
-        query::Builder qb(dataMode);
-        qb.coreSegments(all()).providerSegments(all()).entities(all()).snapshots(all());
 
-        return this->query(qb.buildQueryInput());
-    }
-
-    QueryResult Reader::getLatestSnapshots(DataMode dataMode) const
+    QueryResult Reader::query(const QueryBuilder& queryBuilder) const
     {
-        using namespace client::query_fns;
-
-        query::Builder qb(dataMode);
-        qb.coreSegments(all()).providerSegments(all()).entities(all()).snapshots(latest());
-
-        return this->query(qb.buildQueryInput());
+        return this->query(queryBuilder.buildQueryInput());
     }
 
 
@@ -104,7 +100,120 @@ namespace armarx::armem::client
                 entity.snapshots(latest());
             }
         }
-        return query(qb.buildQueryInput());
+        return query(qb);
+    }
+
+
+
+    std::optional<wm::EntitySnapshot> Reader::getLatestSnapshotOf(const std::vector<MemoryID>& _snapshotIDs) const
+    {
+        std::vector<MemoryID> snapshotIDs = _snapshotIDs;
+
+        client::QueryResult result = this->queryMemoryIDs(snapshotIDs);
+        if (result.success)
+        {
+            std::sort(snapshotIDs.begin(), snapshotIDs.end(), compareTimestampDecreasing);
+            for (const MemoryID& snapshotID : snapshotIDs)
+            {
+                try
+                {
+                    wm::EntitySnapshot& snapshot = result.memory.getEntitySnapshot(snapshotID);
+                    return snapshot;
+                }
+                catch (const armem::error::ArMemError&)
+                {
+                }
+            }
+            return std::nullopt;
+        }
+        else
+        {
+            ARMARX_INFO << "Error querying " << snapshotIDs.size() << " STT snapshots:\n"
+                        << result.errorMessage;
+            return std::nullopt;
+        }
+    }
+
+
+    QueryResult Reader::getLatestSnapshotsIn(const MemoryID& id, DataMode dataMode) const
+    {
+        using namespace client::query_fns;
+        if (!id.isWellDefined())
+        {
+            throw armem::error::InvalidMemoryID(id, "ID must be well defined, but was not.");
+        }
+
+        query::Builder qb(dataMode);
+        query::CoreSegmentSelector& core =
+            id.hasCoreSegmentName()
+            ? qb.coreSegments(withID(id))
+            : qb.coreSegments(all());
+        query::ProviderSegmentSelector& prov =
+            id.hasProviderSegmentName()
+            ? core.providerSegments(withID(id))
+            : core.providerSegments(all());
+        query::EntitySelector& entity =
+            id.hasEntityName()
+            ? prov.entities(withID(id))
+            : prov.entities(all());
+        entity.snapshots(latest());
+
+        return query(qb);
+    }
+
+
+    struct FindLatestSnapshotVisitor : public wm::Visitor
+    {
+        std::optional<wm::EntitySnapshot> latest = std::nullopt;
+
+        bool visitEnter(const wm::EntitySnapshot& snapshot) override;
+    };
+    bool FindLatestSnapshotVisitor::visitEnter(const wm::EntitySnapshot& snapshot)
+    {
+        if (not latest.has_value() or snapshot.time() < latest->time())
+        {
+            latest = snapshot;
+        }
+        return true;
+    }
+
+
+    std::optional<wm::EntitySnapshot> Reader::getLatestSnapshotIn(const MemoryID& id, DataMode dataMode) const
+    {
+        client::QueryResult result = getLatestSnapshotsIn(id, dataMode);
+        if (result.success)
+        {
+            FindLatestSnapshotVisitor visitor;
+            visitor.applyTo(result.memory);
+            return visitor.latest;
+        }
+        else
+        {
+            ARMARX_INFO << "Error querying latest snapshot in " << id;
+            return std::nullopt;
+        }
+    }
+
+
+    QueryResult Reader::getAllLatestSnapshots(DataMode dataMode) const
+    {
+        using namespace client::query_fns;
+
+        query::Builder qb(dataMode);
+        qb.coreSegments(all()).providerSegments(all()).entities(all()).snapshots(latest());
+
+        return this->query(qb);
+    }
+
+
+    QueryResult Reader::getAll(DataMode dataMode) const
+    {
+        using namespace client::query_fns;
+
+        query::Builder qb(dataMode);
+        qb.coreSegments(all()).providerSegments(all()).entities(all()).snapshots(all());
+
+        return this->query(qb);
     }
 
 
@@ -129,5 +238,4 @@ namespace armarx::armem::client
     {
         this->memoryPrx = memory;
     }
-
 }
diff --git a/source/RobotAPI/libraries/armem/client/Reader.h b/source/RobotAPI/libraries/armem/client/Reader.h
index f2bb1a883..1d69491d2 100644
--- a/source/RobotAPI/libraries/armem/client/Reader.h
+++ b/source/RobotAPI/libraries/armem/client/Reader.h
@@ -2,15 +2,14 @@
 
 
 // STD/STL
+#include <optional>
 #include <vector>
 
 // RobotAPI
 #include <RobotAPI/interface/armem/server/ReadingMemoryInterface.h>
 #include <RobotAPI/interface/armem/server/StoringMemoryInterface.h>
-#include <RobotAPI/interface/armem/client/MemoryListenerInterface.h>
-#include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h>
-#include <RobotAPI/libraries/armem/core/workingmemory/Memory.h>
-#include <RobotAPI/libraries/armem/core/longtermmemory/Memory.h>
+#include <RobotAPI/libraries/armem/core/workingmemory/EntitySnapshot.h>
+// #include <RobotAPI/libraries/armem/core/workingmemory/ice_conversions.h>
 
 #include "Query.h"
 
@@ -34,15 +33,14 @@ namespace armarx::armem::client
 
         void setReadingMemory(server::ReadingMemoryInterfacePrx memory);
 
+        /// Perform a query.
         QueryResult query(const QueryInput& input) const;
         armem::query::data::Result query(const armem::query::data::Input& input) const;
 
         QueryResult query(armem::query::data::MemoryQueryPtr query, DataMode dataMode = DataMode::WithData) const;
         QueryResult query(const armem::query::data::MemoryQuerySeq& queries, DataMode dataMode = DataMode::WithData) const;
 
-
-        QueryResult getAll(DataMode dataMode = DataMode::WithData) const;
-        QueryResult getLatestSnapshots(DataMode dataMode = DataMode::WithData) const;
+        QueryResult query(const QueryBuilder& queryBuilder) const;
 
 
         /**
@@ -60,7 +58,54 @@ namespace armarx::armem::client
          * @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;
+        QueryResult
+        queryMemoryIDs(const std::vector<MemoryID>& ids, DataMode dataMode = DataMode::WithData) const;
+
+
+        /**
+         * @brief Query the given snapshot and return the latest existing snapshot.
+         * @param snapshotIDs The snapshot (or entity) IDs.
+         * @return The latest snapshot contained in the query result, if any.
+         */
+        std::optional<wm::EntitySnapshot>
+        getLatestSnapshotOf(const std::vector<MemoryID>& snapshotIDs) const;
+
+
+        /**
+         * @brief Get the latest snapshots under the given memory ID.
+         * @param id A memory, core segment, provider segment or entity ID.
+         * @param dataMode With or without data.
+         * @return The query result.
+         */
+        QueryResult
+        getLatestSnapshotsIn(const MemoryID& id, DataMode dataMode = DataMode::WithData) const;
+
+        /**
+         * @brief Get the latest snapshot under the given memory ID.
+         * @param id A memory, core segment, provider segment or entity ID.
+         * @param dataMode With or without data.
+         * @return The latest contained snapshot, if any.
+         */
+        std::optional<wm::EntitySnapshot>
+        getLatestSnapshotIn(const MemoryID& id, DataMode dataMode = DataMode::WithData) const;
+
+
+        /**
+         * @brief Get all latest snapshots in the memory.
+         * @param dataMode With or without data.
+         * @return The query result.
+         */
+        QueryResult
+        getAllLatestSnapshots(DataMode dataMode = DataMode::WithData) const;
+
+
+        /**
+         * @brief Get the whole memory content.
+         * @param dataMode With or without data.
+         * @return The query result.
+         */
+        QueryResult
+        getAll(DataMode dataMode = DataMode::WithData) const;
 
 
         //data::StoreResult readAndStore(data::StoreInputSeq& input);
-- 
GitLab