diff --git a/README.md b/README.md
index da30c2b55..012f9c62d 100644
--- a/README.md
+++ b/README.md
@@ -95,8 +95,9 @@ your browser.
 [![Linux](https://img.shields.io/badge/Linux-Docker-FCC624?style=for-the-badge&logo=linux&logoColor=black)](https://memgraph.com/docs/memgraph/install-memgraph-on-linux-docker)
 [![Debian](https://img.shields.io/badge/Debian-D70A53?style=for-the-badge&logo=debian&logoColor=white)](https://memgraph.com/docs/memgraph/install-memgraph-on-debian)
 [![Ubuntu](https://img.shields.io/badge/Ubuntu-E95420?style=for-the-badge&logo=ubuntu&logoColor=white)](https://memgraph.com/docs/memgraph/install-memgraph-on-ubuntu)
-[![Cent
-OS](https://img.shields.io/badge/cent%20os-002260?style=for-the-badge&logo=centos&logoColor=F0F0F0)](https://memgraph.com/docs/memgraph/install-memgraph-from-rpm)
+[![Cent OS](https://img.shields.io/badge/cent%20os-002260?style=for-the-badge&logo=centos&logoColor=F0F0F0)](https://memgraph.com/docs/memgraph/install-memgraph-from-rpm)
+[![Fedora](https://img.shields.io/badge/fedora-0B57A4?style=for-the-badge&logo=fedora&logoColor=F0F0F0)](https://memgraph.com/docs/memgraph/install-memgraph-from-rpm)
+[![RedHat](https://img.shields.io/badge/redhat-EE0000?style=for-the-badge&logo=redhat&logoColor=F0F0F0)](https://memgraph.com/docs/memgraph/install-memgraph-from-rpm)
 
 You can find the binaries and Docker images on the [Download
 Hub](https://memgraph.com/download) and the installation instructions in the
diff --git a/src/query/frontend/ast/ast.lcp b/src/query/frontend/ast/ast.lcp
index 577d15113..a1f3c8ef5 100644
--- a/src/query/frontend/ast/ast.lcp
+++ b/src/query/frontend/ast/ast.lcp
@@ -301,6 +301,7 @@ cpp<#
 
 (lcp:define-class expression (tree "::utils::Visitable<HierarchicalTreeVisitor>"
                                    "::utils::Visitable<ExpressionVisitor<TypedValue>>"
+                                   "::utils::Visitable<ExpressionVisitor<TypedValue*>>"
                                    "::utils::Visitable<ExpressionVisitor<void>>")
   ()
   (:abstractp t)
@@ -308,6 +309,7 @@ cpp<#
     #>cpp
     using utils::Visitable<HierarchicalTreeVisitor>::Accept;
     using utils::Visitable<ExpressionVisitor<TypedValue>>::Accept;
+    using utils::Visitable<ExpressionVisitor<TypedValue*>>::Accept;
     using utils::Visitable<ExpressionVisitor<void>>::Accept;
 
     Expression() = default;
@@ -407,6 +409,7 @@ cpp<#
                           (:public
                             #>cpp
                             DEFVISITABLE(ExpressionVisitor<TypedValue>);
+                            DEFVISITABLE(ExpressionVisitor<TypedValue*>);
                             DEFVISITABLE(ExpressionVisitor<void>);
                             bool Accept(HierarchicalTreeVisitor &visitor) override {
                               if (visitor.PreVisit(*this)) {
@@ -438,6 +441,7 @@ cpp<#
                           (:public
                             #>cpp
                             DEFVISITABLE(ExpressionVisitor<TypedValue>);
+                            DEFVISITABLE(ExpressionVisitor<TypedValue*>);
                             DEFVISITABLE(ExpressionVisitor<void>);
                             bool Accept(HierarchicalTreeVisitor &visitor) override {
                               if (visitor.PreVisit(*this)) {
@@ -485,6 +489,7 @@ cpp<#
     }
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -538,6 +543,7 @@ cpp<#
     ListSlicingOperator() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -581,6 +587,7 @@ cpp<#
     IfOperator() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -628,6 +635,7 @@ cpp<#
     PrimitiveLiteral() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     DEFVISITABLE(HierarchicalTreeVisitor);
     cpp<#)
@@ -656,6 +664,7 @@ cpp<#
     ListLiteral() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -688,6 +697,7 @@ cpp<#
     MapLiteral() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -720,6 +730,7 @@ cpp<#
     Identifier() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     DEFVISITABLE(HierarchicalTreeVisitor);
 
@@ -757,6 +768,7 @@ cpp<#
     PropertyLookup() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -797,6 +809,7 @@ cpp<#
     LabelsTest() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -837,6 +850,7 @@ cpp<#
     Function() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -892,6 +906,7 @@ cpp<#
     Reduce() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -930,6 +945,7 @@ cpp<#
    Coalesce() = default;
 
    DEFVISITABLE(ExpressionVisitor<TypedValue>);
+   DEFVISITABLE(ExpressionVisitor<TypedValue*>);
    DEFVISITABLE(ExpressionVisitor<void>);
    bool Accept(HierarchicalTreeVisitor &visitor) override {
      if (visitor.PreVisit(*this)) {
@@ -969,6 +985,7 @@ cpp<#
     Extract() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -1005,6 +1022,7 @@ cpp<#
     All() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -1046,6 +1064,7 @@ cpp<#
     Single() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -1087,6 +1106,7 @@ cpp<#
     Any() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -1128,6 +1148,7 @@ cpp<#
     None() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -1159,6 +1180,7 @@ cpp<#
     ParameterLookup() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     DEFVISITABLE(HierarchicalTreeVisitor);
     cpp<#)
@@ -1186,6 +1208,7 @@ cpp<#
     RegexMatch() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
@@ -1205,6 +1228,7 @@ cpp<#
 
 (lcp:define-class named-expression (tree "::utils::Visitable<HierarchicalTreeVisitor>"
                                          "::utils::Visitable<ExpressionVisitor<TypedValue>>"
+                                         "::utils::Visitable<ExpressionVisitor<TypedValue*>>"
                                          "::utils::Visitable<ExpressionVisitor<void>>")
   ((name "std::string" :scope :public)
    (expression "Expression *" :initval "nullptr" :scope :public
@@ -1223,6 +1247,7 @@ cpp<#
     NamedExpression() = default;
 
     DEFVISITABLE(ExpressionVisitor<TypedValue>);
+    DEFVISITABLE(ExpressionVisitor<TypedValue*>);
     DEFVISITABLE(ExpressionVisitor<void>);
     bool Accept(HierarchicalTreeVisitor &visitor) override {
       if (visitor.PreVisit(*this)) {
diff --git a/src/query/interpret/eval.hpp b/src/query/interpret/eval.hpp
index 1ea20846d..74df223a5 100644
--- a/src/query/interpret/eval.hpp
+++ b/src/query/interpret/eval.hpp
@@ -1,4 +1,4 @@
-// Copyright 2022 Memgraph Ltd.
+// Copyright 2023 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -31,6 +31,71 @@
 
 namespace memgraph::query {
 
+class ReferenceExpressionEvaluator : public ExpressionVisitor<TypedValue *> {
+ public:
+  ReferenceExpressionEvaluator(Frame *frame, const SymbolTable *symbol_table, const EvaluationContext *ctx)
+      : frame_(frame), symbol_table_(symbol_table), ctx_(ctx) {}
+
+  using ExpressionVisitor<TypedValue *>::Visit;
+
+  utils::MemoryResource *GetMemoryResource() const { return ctx_->memory; }
+
+#define UNSUCCESSFUL_VISIT(expr_name) \
+  TypedValue *Visit(expr_name &expr) override { return nullptr; }
+
+  TypedValue *Visit(Identifier &ident) override { return &frame_->at(symbol_table_->at(ident)); }
+
+  UNSUCCESSFUL_VISIT(NamedExpression);
+  UNSUCCESSFUL_VISIT(OrOperator);
+  UNSUCCESSFUL_VISIT(XorOperator);
+  UNSUCCESSFUL_VISIT(AdditionOperator);
+  UNSUCCESSFUL_VISIT(SubtractionOperator);
+  UNSUCCESSFUL_VISIT(MultiplicationOperator);
+  UNSUCCESSFUL_VISIT(DivisionOperator);
+  UNSUCCESSFUL_VISIT(ModOperator);
+  UNSUCCESSFUL_VISIT(NotEqualOperator);
+  UNSUCCESSFUL_VISIT(EqualOperator);
+  UNSUCCESSFUL_VISIT(LessOperator);
+  UNSUCCESSFUL_VISIT(GreaterOperator);
+  UNSUCCESSFUL_VISIT(LessEqualOperator);
+  UNSUCCESSFUL_VISIT(GreaterEqualOperator);
+
+  UNSUCCESSFUL_VISIT(NotOperator);
+  UNSUCCESSFUL_VISIT(UnaryPlusOperator);
+  UNSUCCESSFUL_VISIT(UnaryMinusOperator);
+
+  UNSUCCESSFUL_VISIT(AndOperator);
+  UNSUCCESSFUL_VISIT(IfOperator);
+  UNSUCCESSFUL_VISIT(InListOperator);
+
+  UNSUCCESSFUL_VISIT(SubscriptOperator);
+
+  UNSUCCESSFUL_VISIT(ListSlicingOperator);
+  UNSUCCESSFUL_VISIT(IsNullOperator);
+  UNSUCCESSFUL_VISIT(PropertyLookup);
+  UNSUCCESSFUL_VISIT(LabelsTest);
+
+  UNSUCCESSFUL_VISIT(PrimitiveLiteral);
+  UNSUCCESSFUL_VISIT(ListLiteral);
+  UNSUCCESSFUL_VISIT(MapLiteral);
+  UNSUCCESSFUL_VISIT(Aggregation);
+  UNSUCCESSFUL_VISIT(Coalesce);
+  UNSUCCESSFUL_VISIT(Function);
+  UNSUCCESSFUL_VISIT(Reduce);
+  UNSUCCESSFUL_VISIT(Extract);
+  UNSUCCESSFUL_VISIT(All);
+  UNSUCCESSFUL_VISIT(Single);
+  UNSUCCESSFUL_VISIT(Any);
+  UNSUCCESSFUL_VISIT(None);
+  UNSUCCESSFUL_VISIT(ParameterLookup);
+  UNSUCCESSFUL_VISIT(RegexMatch);
+
+ private:
+  Frame *frame_;
+  const SymbolTable *symbol_table_;
+  const EvaluationContext *ctx_;
+};
+
 class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
  public:
   ExpressionEvaluator(Frame *frame, const SymbolTable &symbol_table, const EvaluationContext &ctx, DbAccessor *dba,
@@ -159,50 +224,53 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
   }
 
   TypedValue Visit(SubscriptOperator &list_indexing) override {
-    auto lhs = list_indexing.expression1_->Accept(*this);
+    ReferenceExpressionEvaluator referenceExpressionEvaluator(frame_, symbol_table_, ctx_);
+
+    TypedValue *lhs_ptr = list_indexing.expression1_->Accept(referenceExpressionEvaluator);
+    TypedValue lhs;
+    const auto referenced = nullptr != lhs_ptr;
+    if (!referenced) {
+      lhs = list_indexing.expression1_->Accept(*this);
+      lhs_ptr = &lhs;
+    }
     auto index = list_indexing.expression2_->Accept(*this);
-    if (!lhs.IsList() && !lhs.IsMap() && !lhs.IsVertex() && !lhs.IsEdge() && !lhs.IsNull())
+    if (!lhs_ptr->IsList() && !lhs_ptr->IsMap() && !lhs_ptr->IsVertex() && !lhs_ptr->IsEdge() && !lhs_ptr->IsNull())
       throw QueryRuntimeException(
           "Expected a list, a map, a node or an edge to index with '[]', got "
           "{}.",
-          lhs.type());
-    if (lhs.IsNull() || index.IsNull()) return TypedValue(ctx_->memory);
-    if (lhs.IsList()) {
+          lhs_ptr->type());
+    if (lhs_ptr->IsNull() || index.IsNull()) return TypedValue(ctx_->memory);
+    if (lhs_ptr->IsList()) {
       if (!index.IsInt()) throw QueryRuntimeException("Expected an integer as a list index, got {}.", index.type());
       auto index_int = index.ValueInt();
-      // NOTE: Take non-const reference to list, so that we can move out the
-      // indexed element as the result.
-      auto &list = lhs.ValueList();
+      auto &list = lhs_ptr->ValueList();
       if (index_int < 0) {
         index_int += static_cast<int64_t>(list.size());
       }
       if (index_int >= static_cast<int64_t>(list.size()) || index_int < 0) return TypedValue(ctx_->memory);
-      // NOTE: Explicit move is needed, so that we return the move constructed
-      // value and preserve the correct MemoryResource.
-      return std::move(list[index_int]);
+      return referenced ? TypedValue(list[index_int], ctx_->memory)
+                        : TypedValue(std::move(list[index_int]), ctx_->memory);
     }
 
-    if (lhs.IsMap()) {
+    if (lhs_ptr->IsMap()) {
       if (!index.IsString()) throw QueryRuntimeException("Expected a string as a map index, got {}.", index.type());
       // NOTE: Take non-const reference to map, so that we can move out the
       // looked-up element as the result.
-      auto &map = lhs.ValueMap();
+      auto &map = lhs_ptr->ValueMap();
       auto found = map.find(index.ValueString());
       if (found == map.end()) return TypedValue(ctx_->memory);
-      // NOTE: Explicit move is needed, so that we return the move constructed
-      // value and preserve the correct MemoryResource.
-      return std::move(found->second);
+      return referenced ? TypedValue(found->second, ctx_->memory) : TypedValue(std::move(found->second), ctx_->memory);
     }
 
-    if (lhs.IsVertex()) {
+    if (lhs_ptr->IsVertex()) {
       if (!index.IsString()) throw QueryRuntimeException("Expected a string as a property name, got {}.", index.type());
-      return TypedValue(GetProperty(lhs.ValueVertex(), index.ValueString()), ctx_->memory);
+      return {GetProperty(lhs_ptr->ValueVertex(), index.ValueString()), ctx_->memory};
     }
 
-    if (lhs.IsEdge()) {
+    if (lhs_ptr->IsEdge()) {
       if (!index.IsString()) throw QueryRuntimeException("Expected a string as a property name, got {}.", index.type());
-      return TypedValue(GetProperty(lhs.ValueEdge(), index.ValueString()), ctx_->memory);
-    }
+      return {GetProperty(lhs_ptr->ValueEdge(), index.ValueString()), ctx_->memory};
+    };
 
     // lhs is Null
     return TypedValue(ctx_->memory);
@@ -258,7 +326,15 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
   }
 
   TypedValue Visit(PropertyLookup &property_lookup) override {
-    auto expression_result = property_lookup.expression_->Accept(*this);
+    ReferenceExpressionEvaluator referenceExpressionEvaluator(frame_, symbol_table_, ctx_);
+
+    TypedValue *expression_result_ptr = property_lookup.expression_->Accept(referenceExpressionEvaluator);
+    TypedValue expression_result;
+
+    if (nullptr == expression_result_ptr) {
+      expression_result = property_lookup.expression_->Accept(*this);
+      expression_result_ptr = &expression_result;
+    }
     auto maybe_date = [this](const auto &date, const auto &prop_name) -> std::optional<TypedValue> {
       if (prop_name == "year") {
         return TypedValue(date.year, ctx_->memory);
@@ -332,42 +408,38 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
       }
       return std::nullopt;
     };
-    switch (expression_result.type()) {
+    switch (expression_result_ptr->type()) {
       case TypedValue::Type::Null:
         return TypedValue(ctx_->memory);
       case TypedValue::Type::Vertex:
-        return TypedValue(GetProperty(expression_result.ValueVertex(), property_lookup.property_), ctx_->memory);
+        return TypedValue(GetProperty(expression_result_ptr->ValueVertex(), property_lookup.property_), ctx_->memory);
       case TypedValue::Type::Edge:
-        return TypedValue(GetProperty(expression_result.ValueEdge(), property_lookup.property_), ctx_->memory);
+        return TypedValue(GetProperty(expression_result_ptr->ValueEdge(), property_lookup.property_), ctx_->memory);
       case TypedValue::Type::Map: {
-        // NOTE: Take non-const reference to map, so that we can move out the
-        // looked-up element as the result.
-        auto &map = expression_result.ValueMap();
+        auto &map = expression_result_ptr->ValueMap();
         auto found = map.find(property_lookup.property_.name.c_str());
         if (found == map.end()) return TypedValue(ctx_->memory);
-        // NOTE: Explicit move is needed, so that we return the move constructed
-        // value and preserve the correct MemoryResource.
-        return std::move(found->second);
+        return TypedValue(found->second, ctx_->memory);
       }
       case TypedValue::Type::Duration: {
         const auto &prop_name = property_lookup.property_.name;
-        const auto &dur = expression_result.ValueDuration();
+        const auto &dur = expression_result_ptr->ValueDuration();
         if (auto dur_field = maybe_duration(dur, prop_name); dur_field) {
-          return std::move(*dur_field);
+          return TypedValue(*dur_field, ctx_->memory);
         }
         throw QueryRuntimeException("Invalid property name {} for Duration", prop_name);
       }
       case TypedValue::Type::Date: {
         const auto &prop_name = property_lookup.property_.name;
-        const auto &date = expression_result.ValueDate();
+        const auto &date = expression_result_ptr->ValueDate();
         if (auto date_field = maybe_date(date, prop_name); date_field) {
-          return std::move(*date_field);
+          return TypedValue(*date_field, ctx_->memory);
         }
         throw QueryRuntimeException("Invalid property name {} for Date", prop_name);
       }
       case TypedValue::Type::LocalTime: {
         const auto &prop_name = property_lookup.property_.name;
-        const auto &lt = expression_result.ValueLocalTime();
+        const auto &lt = expression_result_ptr->ValueLocalTime();
         if (auto lt_field = maybe_local_time(lt, prop_name); lt_field) {
           return std::move(*lt_field);
         }
@@ -375,20 +447,20 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
       }
       case TypedValue::Type::LocalDateTime: {
         const auto &prop_name = property_lookup.property_.name;
-        const auto &ldt = expression_result.ValueLocalDateTime();
+        const auto &ldt = expression_result_ptr->ValueLocalDateTime();
         if (auto date_field = maybe_date(ldt.date, prop_name); date_field) {
           return std::move(*date_field);
         }
         if (auto lt_field = maybe_local_time(ldt.local_time, prop_name); lt_field) {
-          return std::move(*lt_field);
+          return TypedValue(*lt_field, ctx_->memory);
         }
         throw QueryRuntimeException("Invalid property name {} for LocalDateTime", prop_name);
       }
       case TypedValue::Type::Graph: {
         const auto &prop_name = property_lookup.property_.name;
-        const auto &graph = expression_result.ValueGraph();
+        const auto &graph = expression_result_ptr->ValueGraph();
         if (auto graph_field = maybe_graph(graph, prop_name); graph_field) {
-          return std::move(*graph_field);
+          return TypedValue(*graph_field, ctx_->memory);
         }
         throw QueryRuntimeException("Invalid property name {} for Graph", prop_name);
       }
diff --git a/tests/mgbench/client.cpp b/tests/mgbench/client.cpp
index 87bdda6c9..c7e002df6 100644
--- a/tests/mgbench/client.cpp
+++ b/tests/mgbench/client.cpp
@@ -1,4 +1,4 @@
-// Copyright 2022 Memgraph Ltd.
+// Copyright 2023 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -16,17 +16,23 @@
 #include <fstream>
 #include <limits>
 #include <map>
+#include <numeric>
+#include <ostream>
 #include <string>
 #include <thread>
 #include <vector>
 
 #include <gflags/gflags.h>
+#include <math.h>
 #include <json/json.hpp>
 
 #include "communication/bolt/client.hpp"
 #include "communication/bolt/v1/value.hpp"
 #include "communication/init.hpp"
+#include "spdlog/formatter.h"
+#include "spdlog/spdlog.h"
 #include "utils/exceptions.hpp"
+#include "utils/logging.hpp"
 #include "utils/string.hpp"
 #include "utils/timer.hpp"
 
@@ -48,6 +54,10 @@ DEFINE_bool(queries_json, false,
 
 DEFINE_string(input, "", "Input file. By default stdin is used.");
 DEFINE_string(output, "", "Output file. By default stdout is used.");
+DEFINE_bool(validation, false,
+            "Set to true to run client in validation mode."
+            "Validation mode works for singe query and returns results for validation"
+            "with metadata");
 
 std::pair<std::map<std::string, memgraph::communication::bolt::Value>, uint64_t> ExecuteNTimesTillSuccess(
     memgraph::communication::bolt::Client *client, const std::string &query,
@@ -55,6 +65,7 @@ std::pair<std::map<std::string, memgraph::communication::bolt::Value>, uint64_t>
   for (uint64_t i = 0; i < max_attempts; ++i) {
     try {
       auto ret = client->Execute(query, params);
+
       return {std::move(ret.metadata), i};
     } catch (const memgraph::utils::BasicException &e) {
       if (i == max_attempts - 1) {
@@ -67,6 +78,28 @@ std::pair<std::map<std::string, memgraph::communication::bolt::Value>, uint64_t>
   LOG_FATAL("Could not execute query '{}' {} times!", query, max_attempts);
 }
 
+// Validation returns results and metadata
+std::pair<std::map<std::string, memgraph::communication::bolt::Value>,
+          std::vector<std::vector<memgraph::communication::bolt::Value>>>
+ExecuteValidationNTimesTillSuccess(memgraph::communication::bolt::Client *client, const std::string &query,
+                                   const std::map<std::string, memgraph::communication::bolt::Value> &params,
+                                   int max_attempts) {
+  for (uint64_t i = 0; i < max_attempts; ++i) {
+    try {
+      auto ret = client->Execute(query, params);
+
+      return {std::move(ret.metadata), std::move(ret.records)};
+    } catch (const memgraph::utils::BasicException &e) {
+      if (i == max_attempts - 1) {
+        LOG_FATAL("Could not execute query '{}' {} times! Error message: {}", query, max_attempts, e.what());
+      } else {
+        continue;
+      }
+    }
+  }
+  LOG_FATAL("Could not execute query '{}' {} times!", query, max_attempts);
+}
+
 memgraph::communication::bolt::Value JsonToBoltValue(const nlohmann::json &data) {
   switch (data.type()) {
     case nlohmann::json::value_t::null:
@@ -158,6 +191,35 @@ class Metadata final {
   std::map<std::string, Record> storage_;
 };
 
+nlohmann::json LatencyStatistics(std::vector<std::vector<double>> &worker_query_latency) {
+  nlohmann::json statistics = nlohmann::json::object();
+  std::vector<double> query_latency;
+  for (int i = 0; i < FLAGS_num_workers; i++) {
+    for (auto &e : worker_query_latency[i]) {
+      query_latency.push_back(e);
+    }
+  }
+  auto iterations = query_latency.size();
+  const int lower_bound = 10;
+  if (iterations > lower_bound) {
+    std::sort(query_latency.begin(), query_latency.end());
+    statistics["iterations"] = iterations;
+    statistics["min"] = query_latency.front();
+    statistics["max"] = query_latency.back();
+    statistics["mean"] = std::accumulate(query_latency.begin(), query_latency.end(), 0.0) / iterations;
+    statistics["p99"] = query_latency[floor(iterations * 0.99)];
+    statistics["p95"] = query_latency[floor(iterations * 0.95)];
+    statistics["p90"] = query_latency[floor(iterations * 0.90)];
+    statistics["p75"] = query_latency[floor(iterations * 0.75)];
+    statistics["p50"] = query_latency[floor(iterations * 0.50)];
+
+  } else {
+    spdlog::info("To few iterations to calculate latency values!");
+    statistics["iterations"] = iterations;
+  }
+  return statistics;
+}
+
 void Execute(
     const std::vector<std::pair<std::string, std::map<std::string, memgraph::communication::bolt::Value>>> &queries,
     std::ostream *stream) {
@@ -167,6 +229,7 @@ void Execute(
   std::vector<uint64_t> worker_retries(FLAGS_num_workers, 0);
   std::vector<Metadata> worker_metadata(FLAGS_num_workers, Metadata());
   std::vector<double> worker_duration(FLAGS_num_workers, 0.0);
+  std::vector<std::vector<double>> worker_query_durations(FLAGS_num_workers);
 
   // Start workers and execute queries.
   auto size = queries.size();
@@ -187,16 +250,20 @@ void Execute(
       auto &retries = worker_retries[worker];
       auto &metadata = worker_metadata[worker];
       auto &duration = worker_duration[worker];
-      memgraph::utils::Timer timer;
+      auto &query_duration = worker_query_durations[worker];
+
+      memgraph::utils::Timer worker_timer;
       while (true) {
         auto pos = position.fetch_add(1, std::memory_order_acq_rel);
         if (pos >= size) break;
         const auto &query = queries[pos];
+        memgraph::utils::Timer query_timer;
         auto ret = ExecuteNTimesTillSuccess(&client, query.first, query.second, FLAGS_max_retries);
+        query_duration.push_back(query_timer.Elapsed().count());
         retries += ret.second;
         metadata.Append(ret.first);
       }
-      duration = timer.Elapsed().count();
+      duration = worker_timer.Elapsed().count();
       client.Close();
     }));
   }
@@ -218,6 +285,7 @@ void Execute(
     final_retries += worker_retries[i];
     final_duration += worker_duration[i];
   }
+
   final_duration /= FLAGS_num_workers;
   nlohmann::json summary = nlohmann::json::object();
   summary["count"] = queries.size();
@@ -226,12 +294,76 @@ void Execute(
   summary["retries"] = final_retries;
   summary["metadata"] = final_metadata.Export();
   summary["num_workers"] = FLAGS_num_workers;
+  summary["latency_stats"] = LatencyStatistics(worker_query_durations);
+  (*stream) << summary.dump() << std::endl;
+}
+
+nlohmann::json BoltRecordsToJSONStrings(std::vector<std::vector<memgraph::communication::bolt::Value>> &results) {
+  nlohmann::json res = nlohmann::json::object();
+  std::ostringstream oss;
+  for (int i = 0; i < results.size(); i++) {
+    oss << results[i];
+    res[std::to_string(i)] = oss.str();
+  }
+  return res;
+}
+
+/// Validation mode works on single thread with 1 query.
+void ExecuteValidation(
+    const std::vector<std::pair<std::string, std::map<std::string, memgraph::communication::bolt::Value>>> &queries,
+    std::ostream *stream) {
+  spdlog::info("Running validation mode, number of workers forced to 1");
+  FLAGS_num_workers = 1;
+
+  Metadata metadata = Metadata();
+  double duration = 0.0;
+  std::vector<std::vector<memgraph::communication::bolt::Value>> results;
+
+  auto size = queries.size();
+
+  memgraph::io::network::Endpoint endpoint(FLAGS_address, FLAGS_port);
+  memgraph::communication::ClientContext context(FLAGS_use_ssl);
+  memgraph::communication::bolt::Client client(context);
+  client.Connect(endpoint, FLAGS_username, FLAGS_password);
+
+  memgraph::utils::Timer timer;
+  if (size == 1) {
+    const auto &query = queries[0];
+    auto ret = ExecuteValidationNTimesTillSuccess(&client, query.first, query.second, FLAGS_max_retries);
+    metadata.Append(ret.first);
+    results = ret.second;
+    duration = timer.Elapsed().count();
+    client.Close();
+  } else {
+    spdlog::info("Validation works with single query, pass just one query!");
+  }
+
+  nlohmann::json summary = nlohmann::json::object();
+  summary["count"] = 1;
+  summary["duration"] = duration;
+  summary["metadata"] = metadata.Export();
+  summary["results"] = BoltRecordsToJSONStrings(results);
+  summary["num_workers"] = FLAGS_num_workers;
+
   (*stream) << summary.dump() << std::endl;
 }
 
 int main(int argc, char **argv) {
   gflags::ParseCommandLineFlags(&argc, &argv, true);
 
+  spdlog::info("Running a bolt client with following settings:");
+  spdlog::info("Adress: {} ", FLAGS_address);
+  spdlog::info("Port: {} ", FLAGS_port);
+  spdlog::info("Username: {} ", FLAGS_username);
+  spdlog::info("Password: {} ", FLAGS_password);
+  spdlog::info("Usessl: {} ", FLAGS_use_ssl);
+  spdlog::info("Num of worker: {}", FLAGS_num_workers);
+  spdlog::info("Max retries: {}", FLAGS_max_retries);
+  spdlog::info("Query JSON: {}", FLAGS_queries_json);
+  spdlog::info("Input: {}", FLAGS_input);
+  spdlog::info("Output: {}", FLAGS_output);
+  spdlog::info("Validation: {}", FLAGS_validation);
+
   memgraph::communication::SSLInit sslInit;
 
   std::ifstream ifile;
@@ -291,7 +423,12 @@ int main(int argc, char **argv) {
       queries.emplace_back(query, std::move(bolt_param.ValueMap()));
     }
   }
-  Execute(queries, ostream);
+
+  if (!FLAGS_validation) {
+    Execute(queries, ostream);
+  } else {
+    ExecuteValidation(queries, ostream);
+  }
 
   return 0;
 }
diff --git a/tests/mgbench/runners.py b/tests/mgbench/runners.py
index 5eb2f84b3..3d3aa966e 100644
--- a/tests/mgbench/runners.py
+++ b/tests/mgbench/runners.py
@@ -398,7 +398,13 @@ class Client:
             password=self._password,
             port=self._bolt_port,
         )
+
         ret = subprocess.run(args, capture_output=True, check=True)
+        error = ret.stderr.decode("utf-8").strip().split("\n")
+        if error and error[0] != "":
+            print("Reported errros from client")
+            print(error)
+
         data = ret.stdout.decode("utf-8").strip().split("\n")
-        # data = [x for x in data if not x.startswith("[")]
+        data = [x for x in data if not x.startswith("[")]
         return list(map(json.loads, data))
diff --git a/tests/unit/query_expression_evaluator.cpp b/tests/unit/query_expression_evaluator.cpp
index 6e61e07d6..f1ae0d652 100644
--- a/tests/unit/query_expression_evaluator.cpp
+++ b/tests/unit/query_expression_evaluator.cpp
@@ -1,4 +1,4 @@
-// Copyright 2022 Memgraph Ltd.
+// Copyright 2023 Memgraph Ltd.
 //
 // Use of this software is governed by the Business Source License
 // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -26,6 +26,7 @@
 #include "query/interpret/eval.hpp"
 #include "query/interpret/frame.hpp"
 #include "query/path.hpp"
+#include "query/typed_value.hpp"
 #include "storage/v2/storage.hpp"
 #include "utils/exceptions.hpp"
 #include "utils/string.hpp"
@@ -426,6 +427,47 @@ TEST_F(ExpressionEvaluatorTest, VertexAndEdgeIndexing) {
   }
 }
 
+TEST_F(ExpressionEvaluatorTest, TypedValueListIndexing) {
+  auto list_vector = memgraph::utils::pmr::vector<TypedValue>(ctx.memory);
+  list_vector.emplace_back("string1");
+  list_vector.emplace_back(TypedValue("string2"));
+
+  auto *identifier = storage.Create<Identifier>("n");
+  auto node_symbol = symbol_table.CreateSymbol("n", true);
+  identifier->MapTo(node_symbol);
+  frame[node_symbol] = TypedValue(list_vector, ctx.memory);
+
+  {
+    // Legal indexing.
+    auto *op = storage.Create<SubscriptOperator>(identifier, storage.Create<PrimitiveLiteral>(0));
+    auto value = Eval(op);
+    EXPECT_EQ(value.ValueString(), "string1");
+  }
+  {
+    // Out of bounds indexing
+    auto *op = storage.Create<SubscriptOperator>(identifier, storage.Create<PrimitiveLiteral>(3));
+    auto value = Eval(op);
+    EXPECT_TRUE(value.IsNull());
+  }
+  {
+    // Out of bounds indexing with negative bound.
+    auto *op = storage.Create<SubscriptOperator>(identifier, storage.Create<PrimitiveLiteral>(-100));
+    auto value = Eval(op);
+    EXPECT_TRUE(value.IsNull());
+  }
+  {
+    // Legal indexing with negative index.
+    auto *op = storage.Create<SubscriptOperator>(identifier, storage.Create<PrimitiveLiteral>(-2));
+    auto value = Eval(op);
+    EXPECT_EQ(value.ValueString(), "string1");
+  }
+  {
+    // Indexing with incompatible type.
+    auto *op = storage.Create<SubscriptOperator>(identifier, storage.Create<PrimitiveLiteral>("bla"));
+    EXPECT_THROW(Eval(op), QueryRuntimeException);
+  }
+}
+
 TEST_F(ExpressionEvaluatorTest, ListSlicingOperator) {
   auto *list_literal = storage.Create<ListLiteral>(
       std::vector<Expression *>{storage.Create<PrimitiveLiteral>(1), storage.Create<PrimitiveLiteral>(2),