diff --git a/benchmark/QueryBuilderTests.cpp b/benchmark/QueryBuilderTests.cpp
index 5da87889875fa1c9db4de13e2f0d41b2fbbb88be..24970008c1e8e951ea57d525574bc4a97c5535cb 100644
--- a/benchmark/QueryBuilderTests.cpp
+++ b/benchmark/QueryBuilderTests.cpp
@@ -99,8 +99,7 @@ void bmStoreDataEventQueryNoCache(benchmark::State& state)
 {
     // TEST - Testing how long it takes to build an Insert Data Event query with
     // an empty cache (this forces the full string to be built)
-    hdbpp_internal::LogConfigurator::initLoggingMetrics(false, false);
-    hdbpp_internal::LogConfigurator::setLoggingLevel(spdlog::level::err);
+    hdbpp_internal::LogConfigurator::initLogging();
 
     hdbpp_internal::AttributeTraits traits 
         {static_cast<Tango::AttrWriteType>(state.range(0)), Tango::SCALAR, Tango::DEV_DOUBLE};
@@ -109,7 +108,7 @@ void bmStoreDataEventQueryNoCache(benchmark::State& state)
     {
         // define the builder here so its cache is always fresh
         hdbpp_internal::pqxx_conn::QueryBuilder query_builder;
-        query_builder.storeDataEventQuery<T>(traits);
+        query_builder.storeDataEventStatement<T>(traits);
     }
 }
 
@@ -120,8 +119,7 @@ void bmStoreDataEventQueryCache(benchmark::State& state)
 {
     // TEST - Testing the full lookup for an Insert Data QueryEvent query when the cache
     // map is fully populated 
-    hdbpp_internal::LogConfigurator::initLoggingMetrics(false, false);
-    hdbpp_internal::LogConfigurator::setLoggingLevel(spdlog::level::err);
+    hdbpp_internal::LogConfigurator::initLogging();
 
     hdbpp_internal::AttributeTraits traits 
         {static_cast<Tango::AttrWriteType>(state.range(0)), Tango::SCALAR, Tango::DEV_DOUBLE};
@@ -149,13 +147,13 @@ void bmStoreDataEventQueryCache(benchmark::State& state)
     for (auto &type : types)
         for (auto &format : format_types)
             for (auto &write : write_types)
-                query_builder.storeDataEventQuery<T>(hdbpp_internal::AttributeTraits{write, format, type});
+                query_builder.storeDataEventStatement<T>(hdbpp_internal::AttributeTraits{write, format, type});
 
     for (auto _ : state)
-        query_builder.storeDataEventQuery<T>(traits);
+        query_builder.storeDataEventStatement<T>(traits);
 }
 
 BENCHMARK_TEMPLATE(bmStoreDataEventQueryNoCache, bool)->Apply(writeTypeArgs);
 BENCHMARK_TEMPLATE(bmStoreDataEventQueryCache, bool)->Apply(writeTypeArgs);
 
-BENCHMARK_MAIN();
\ No newline at end of file
+BENCHMARK_MAIN();
diff --git a/src/ColumnCache.hpp b/src/ColumnCache.hpp
index 44674be924839302a1a1923a56367f4554a30480..41d94724d387649dddcc1895f82b8d773bb0c6de 100644
--- a/src/ColumnCache.hpp
+++ b/src/ColumnCache.hpp
@@ -126,7 +126,7 @@ namespace pqxx_conn
                 if (!tx.prepared(_fetch_all_query_name).exists())
                 {
                     tx.conn().prepare(_fetch_all_query_name,
-                        QueryBuilder::fetchAllValuesQuery(_column_name, _table_name, _reference));
+                        QueryBuilder::fetchAllValuesStatement(_column_name, _table_name, _reference));
 
                     spdlog::trace("Created prepared statement for: {}", _fetch_all_query_name);
                 }
@@ -182,7 +182,7 @@ namespace pqxx_conn
                     if (!tx.prepared(_fetch_id_query_name).exists())
                     {
                         tx.conn().prepare(
-                            _fetch_id_query_name, QueryBuilder::fetchValueQuery(_column_name, _table_name, _reference));
+                            _fetch_id_query_name, QueryBuilder::fetchValueStatement(_column_name, _table_name, _reference));
 
                         spdlog::trace("Created prepared statement for: {}", _fetch_id_query_name);
                     }
diff --git a/src/DbConnection.cpp b/src/DbConnection.cpp
index 85e16048df8c92e446e2a8e762c6b888a072d2f6..fb01213246fbf07b21eb58326d185a51bf4c9c87 100644
--- a/src/DbConnection.cpp
+++ b/src/DbConnection.cpp
@@ -146,7 +146,7 @@ namespace pqxx_conn
 
                 if (!tx.prepared(StoreAttribute).exists())
                 {
-                    tx.conn().prepare(StoreAttribute, QueryBuilder::storeAttributeQuery());
+                    tx.conn().prepare(StoreAttribute, QueryBuilder::storeAttributeStatement());
                     spdlog::trace("Created prepared statement for: {}", StoreAttribute);
                 }
 
@@ -180,7 +180,7 @@ namespace pqxx_conn
         {
             handlePqxxError("The attribute [" + full_attr_name + "] was not saved.",
                 ex.base().what(),
-                QueryBuilder::storeAttributeQuery(),
+                QueryBuilder::storeAttributeStatement(),
                 LOCATION_INFO);
         }
     }
@@ -225,7 +225,7 @@ namespace pqxx_conn
 
                 if (!tx.prepared(StoreHistoryEvent).exists())
                 {
-                    tx.conn().prepare(StoreHistoryEvent, QueryBuilder::storeHistoryEventQuery());
+                    tx.conn().prepare(StoreHistoryEvent, QueryBuilder::storeHistoryEventStatement());
                     spdlog::trace("Created prepared statement for: {}", StoreHistoryEvent);
                 }
 
@@ -240,7 +240,7 @@ namespace pqxx_conn
         {
             handlePqxxError("The attribute [" + full_attr_name + "] event [" + event + "] was not saved.",
                 ex.base().what(),
-                QueryBuilder::storeHistoryEventQuery(),
+                QueryBuilder::storeHistoryEventStatement(),
                 LOCATION_INFO);
         }
     }
@@ -300,7 +300,7 @@ namespace pqxx_conn
 
                 if (!tx.prepared(StoreParameterEvent).exists())
                 {
-                    tx.conn().prepare(StoreParameterEvent, QueryBuilder::storeParameterEventQuery());
+                    tx.conn().prepare(StoreParameterEvent, QueryBuilder::storeParameterEventStatement());
                     spdlog::trace("Created prepared statement for: {}", StoreParameterEvent);
                 }
 
@@ -327,7 +327,7 @@ namespace pqxx_conn
         {
             handlePqxxError("The attribute [" + full_attr_name + "] parameter event was not saved.",
                 ex.base().what(),
-                QueryBuilder::storeParameterEventQuery(),
+                QueryBuilder::storeParameterEventStatement(),
                 LOCATION_INFO);
         }
     }
@@ -384,7 +384,7 @@ namespace pqxx_conn
                 if (!tx.prepared(_query_builder.storeDataEventErrorName(traits)).exists())
                 {
                     tx.conn().prepare(_query_builder.storeDataEventErrorName(traits),
-                        _query_builder.storeDataEventErrorQuery(traits));
+                        _query_builder.storeDataEventErrorStatement(traits));
                     spdlog::trace(
                         "Created prepared statement for: {}", _query_builder.storeDataEventErrorName(traits));
                 }
@@ -434,7 +434,7 @@ namespace pqxx_conn
                 pqxx::work tx {(*_conn), FetchLastHistoryEvent};
 
                 if (!tx.prepared(FetchLastHistoryEvent).exists())
-                    tx.conn().prepare(FetchLastHistoryEvent, QueryBuilder::fetchLastHistoryEventQuery());
+                    tx.conn().prepare(FetchLastHistoryEvent, QueryBuilder::fetchLastHistoryEventStatement());
 
                 // unless this is the first time this attribute event history has
                 // been queried, then we expect something back
@@ -452,7 +452,7 @@ namespace pqxx_conn
         {
             handlePqxxError("Can not return last event for attribute [" + full_attr_name + "].",
                 ex.base().what(),
-                QueryBuilder::fetchLastHistoryEventQuery(),
+                QueryBuilder::fetchLastHistoryEventStatement(),
                 LOCATION_INFO);
         }
 
@@ -504,7 +504,7 @@ namespace pqxx_conn
                 pqxx::work tx {(*_conn), FetchAttributeTraits};
 
                 if (!tx.prepared(FetchAttributeTraits).exists())
-                    tx.conn().prepare(FetchAttributeTraits, QueryBuilder::fetchAttributeTraitsQuery());
+                    tx.conn().prepare(FetchAttributeTraits, QueryBuilder::fetchAttributeTraitsStatement());
 
                 // always expect a result, the type info for the attribute
                 auto row = tx.exec_prepared1(FetchAttributeTraits, full_attr_name);
@@ -519,7 +519,7 @@ namespace pqxx_conn
         {
             handlePqxxError("Can not return the type traits for attribute [" + full_attr_name + "].",
                 ex.base().what(),
-                QueryBuilder::fetchAttributeTraitsQuery(),
+                QueryBuilder::fetchAttributeTraitsStatement(),
                 LOCATION_INFO);
         }
 
@@ -541,7 +541,7 @@ namespace pqxx_conn
 
                 if (!tx.prepared(StoreHistoryString).exists())
                 {
-                    tx.conn().prepare(StoreHistoryString, QueryBuilder::storeHistoryStringQuery());
+                    tx.conn().prepare(StoreHistoryString, QueryBuilder::storeHistoryStringStatement());
                     spdlog::trace("Created prepared statement for: {}", StoreHistoryString);
                 }
 
@@ -562,7 +562,7 @@ namespace pqxx_conn
         {
             handlePqxxError("The event [" + event + "] for attribute [" + full_attr_name + "] was not saved.",
                 ex.base().what(),
-                QueryBuilder::storeHistoryStringQuery(),
+                QueryBuilder::storeHistoryStringStatement(),
                 LOCATION_INFO);
         }
     }
@@ -582,7 +582,7 @@ namespace pqxx_conn
 
                 if (!tx.prepared(StoreErrorString).exists())
                 {
-                    tx.conn().prepare(StoreErrorString, QueryBuilder::storeErrorQuery());
+                    tx.conn().prepare(StoreErrorString, QueryBuilder::storeErrorStatement());
                     spdlog::trace("Created prepared statement for: {}", StoreErrorString);
                 }
 
@@ -606,7 +606,7 @@ namespace pqxx_conn
         {
             handlePqxxError("The error string [" + error_msg + "] for attribute [" + full_attr_name + "] was not saved",
                 ex.base().what(),
-                QueryBuilder::storeErrorQuery(),
+                QueryBuilder::storeErrorStatement(),
                 LOCATION_INFO);
         }
     }
diff --git a/src/DbConnection.tpp b/src/DbConnection.tpp
index 8c71da326167988670f43790152e7ab01f59b7bc..a31b01d46e1a0ba690d3708264816639f823b112 100644
--- a/src/DbConnection.tpp
+++ b/src/DbConnection.tpp
@@ -103,43 +103,13 @@ namespace pqxx_conn
                 // to avoid the quoting. Its likely we will need more for DevEncoded and DevEnum
                 if (traits.isArray() && traits.type() == Tango::DEV_STRING)
                 {
-                    auto prepare_array = [](auto &value) {
-                        auto iter = value->begin();
-                        std::string result = "ARRAY[";
-
-                        result = "$$" + pqxx::to_string((*iter)) + "$$";
-
-                        for (++iter; iter != value->end(); ++iter)
-                        {
-                            result += ",";
-                            result += "$$" + pqxx::to_string((*iter)) + "$$";
-                        }
-
-                        result += "]";
-                        return result;
-                    };
-
-                    auto query = "INSERT INTO " + QueryBuilder::tableName(traits) + " (" + DAT_COL_ID + "," + DAT_COL_DATA_TIME;
-
-                    if (traits.hasReadData())
-                        query = query + "," + DAT_COL_VALUE_R;
-
-                    if (traits.hasWriteData())
-                        query = query + "," + DAT_COL_VALUE_W;
-
-                    // split to ensure increments are in the correct order
-                    query = query + "," + DAT_COL_QUALITY + ") VALUES (" + pqxx::to_string(full_attr_name);
-                    query = query + ",TO_TIMESTAMP(" + pqxx::to_string(event_time) + ")";
-
-                    // add the read parameter with cast
-                    if (traits.hasReadData())
-                        query = query + "," + prepare_array(value_r);
-
-                    // add the write parameter with cast
-                    if (traits.hasWriteData())
-                        query = query + "," + prepare_array(value_w);
-
-                    query = query + "," + pqxx::to_string(quality) + ")";
+                    auto query = _query_builder.storeDataEventString<T>(
+                        pqxx::to_string(full_attr_name),
+                        pqxx::to_string(event_time),
+                        pqxx::to_string(quality),
+                        value_r,
+                        value_w,
+                        traits);
 
                     tx.exec0(query);
                 }
@@ -150,7 +120,7 @@ namespace pqxx_conn
                     if (!tx.prepared(_query_builder.storeDataEventName(traits)).exists())
                     {
                         tx.conn().prepare(
-                            _query_builder.storeDataEventName(traits), _query_builder.storeDataEventQuery<T>(traits));
+                            _query_builder.storeDataEventName(traits), _query_builder.storeDataEventStatement<T>(traits));
                     }
 
                     // get the pqxx prepared statement invocation object to allow us to
@@ -200,7 +170,7 @@ namespace pqxx_conn
         {
             handlePqxxError("The attribute [" + full_attr_name + "] data event was not saved.",
                 ex.base().what(),
-                _query_builder.storeDataEventQuery<T>(traits),
+                _query_builder.storeDataEventStatement<T>(traits),
                 LOCATION_INFO);
         }
     }
diff --git a/src/QueryBuilder.cpp b/src/QueryBuilder.cpp
index 32208b8e2973ddadb8f11823a69b439450e87f72..f928ed28c1a4b6d1e3cefacdfa9f24b97826cb1c 100644
--- a/src/QueryBuilder.cpp
+++ b/src/QueryBuilder.cpp
@@ -130,7 +130,7 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    const string &QueryBuilder::storeAttributeQuery()
+    const string &QueryBuilder::storeAttributeStatement()
     {
         // clang-format off
         static string query =
@@ -167,7 +167,7 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    const string &QueryBuilder::storeHistoryStringQuery()
+    const string &QueryBuilder::storeHistoryStringStatement()
     {
         // clang-format off
         static string query = 
@@ -181,7 +181,7 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    const string &QueryBuilder::storeHistoryEventQuery()
+    const string &QueryBuilder::storeHistoryEventStatement()
     {
         // clang-format off
         static string query =
@@ -200,7 +200,7 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    const string &QueryBuilder::storeParameterEventQuery()
+    const string &QueryBuilder::storeParameterEventStatement()
     {
         // clang-format off
         static string query =
@@ -225,7 +225,7 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    const string &QueryBuilder::storeDataEventErrorQuery(const AttributeTraits &traits)
+    const string &QueryBuilder::storeDataEventErrorStatement(const AttributeTraits &traits)
     {
         // search the cache for a previous entry
         auto result = _data_event_error_queries.find(traits);
@@ -260,7 +260,7 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    const string &QueryBuilder::storeErrorQuery()
+    const string &QueryBuilder::storeErrorStatement()
     {
         // clang-format off
         static string query = 
@@ -273,7 +273,7 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    const string QueryBuilder::fetchAllValuesQuery(
+    const string QueryBuilder::fetchAllValuesStatement(
         const string &column_name, const string &table_name, const string &reference)
     {
         return "SELECT " + column_name + ", " + reference + " " + "FROM " + table_name;
@@ -281,7 +281,7 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    const string QueryBuilder::fetchValueQuery(
+    const string QueryBuilder::fetchValueStatement(
         const string &column_name, const string &table_name, const string &reference)
     {
         return "SELECT " + column_name + " " + "FROM " + table_name + " WHERE " + reference + "=$1";
@@ -289,7 +289,7 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    const string &QueryBuilder::fetchLastHistoryEventQuery()
+    const string &QueryBuilder::fetchLastHistoryEventStatement()
     {
         // clang-format off
         static string query = 
@@ -307,7 +307,7 @@ namespace pqxx_conn
 
     //=============================================================================
     //=============================================================================
-    const std::string &QueryBuilder::fetchAttributeTraitsQuery()
+    const std::string &QueryBuilder::fetchAttributeTraitsStatement()
     {
         // clang-format off
         static string query = 
diff --git a/src/QueryBuilder.hpp b/src/QueryBuilder.hpp
index 82bc533694190a73327d71138a7f6df59187cc4f..502a815ec642efb43a67d46696ca7baeb07d888e 100644
--- a/src/QueryBuilder.hpp
+++ b/src/QueryBuilder.hpp
@@ -23,6 +23,8 @@
 #include "AttributeTraits.hpp"
 #include "HdbppDefines.hpp"
 #include "TimescaleSchema.hpp"
+#include "PqxxExtension.hpp"
+
 #include "spdlog/spdlog.h"
 
 #include <iostream>
@@ -59,6 +61,71 @@ namespace pqxx_conn
         // queries, it is specialized for all possible tango types in the source file
         template<typename T>
         std::string postgresCast(bool is_array);
+
+        //=============================================================================
+        //=============================================================================
+        template<typename T>
+        struct ToString
+        {
+            static std::string run(std::unique_ptr<std::vector<T>> &value, const AttributeTraits&)
+            {
+                return pqxx::to_string(value);
+            }
+        };
+
+        //=============================================================================
+        //=============================================================================
+        template<>
+        struct ToString<bool>
+        {
+            static std::string run(std::unique_ptr<std::vector<bool>> &value, const AttributeTraits &traits)
+            {
+                // a vector<bool> is not actually a vector<bool>, rather its some kind of bitfield. When
+                // trying to return an element, we appear to get some kind of bitfield reference (?),
+                // so we return the value to a local variable to remove the referene to the bitfield and
+                // this ensure its actually a bool passed into the conversion framework
+                if (traits.isScalar())
+                {
+                    bool v = (*value)[0];
+                    return pqxx::to_string(v);
+                }
+
+                // handled by our own extensions
+                pqxx::to_string(value);
+            }
+        };
+
+        //=============================================================================
+        //=============================================================================
+        template<>
+        struct ToString<std::string>
+        {
+            static std::string run(std::unique_ptr<std::vector<std::string>> &value, const AttributeTraits &traits)
+            {
+                // arrays of strings need both the ARRAY keywords and dollar escaping, this is so we
+                // do not have to rely on the postgres escape functions that double and then store 
+                // escaped characters. This is a mess when extracting the array of strings.
+                if (traits.isScalar())
+                {
+                    // no special case needed for a scalar string
+                    return pqxx::to_string((*value)[0]);
+                }
+
+                auto iter = value->begin();
+                std::string result = "ARRAY[";
+
+                result = "$$" + pqxx::to_string((*iter)) + "$$";
+
+                for (++iter; iter != value->end(); ++iter)
+                {
+                    result += ",";
+                    result += "$$" + pqxx::to_string((*iter)) + "$$";
+                }
+
+                result += "]";
+                return result;
+            }
+        };
     }; // namespace query_utils
 
     // these are used as transactions names for pqxx, some are used to as prepared
@@ -82,41 +149,53 @@ namespace pqxx_conn
     {
     public:
 
-        // Non-static methods
+        // Static Prepared statement strings
+        // these builder functions require no caching, so can be simple static
+        // functions
+
+        static std::string tableName(const AttributeTraits &traits);
+        static const std::string &storeAttributeStatement();
+        static const std::string &storeHistoryEventStatement();
+        static const std::string &storeHistoryStringStatement();
+        static const std::string &storeParameterEventStatement();
+        static const std::string &storeErrorStatement();
+        static const std::string &fetchLastHistoryEventStatement();
+        static const std::string &fetchAttributeTraitsStatement();
+
+        static const std::string fetchValueStatement(
+            const std::string &column_name, const std::string &table_name, const std::string &reference);
+
+        static const std::string fetchAllValuesStatement(
+            const std::string &column_name, const std::string &table_name, const std::string &reference);
+
+        // Non-static prepared statements
+        // these builder functions cache the built queries, therefore they
+        // are not static like the others sincethey require data storage
 
-        // these builder functions cache the built query names, therefore they
-        // are not static like the others
         const std::string &storeDataEventName(const AttributeTraits &traits);
         const std::string &storeDataEventErrorName(const AttributeTraits &traits);
 
-        // like the query name functions, these cache data internally to speed up the
-        // process of putting data int the db
+        // builds a prepared statement for the given traits
         template<typename T>
-        const std::string &storeDataEventQuery(const AttributeTraits &traits);
-
-        const std::string &storeDataEventErrorQuery(const AttributeTraits &traits);
+        const std::string &storeDataEventStatement(const AttributeTraits &traits);
 
+        // A varient of storeDataEventStatement that builds a string based on the
+        // parameters, this is then executed. Does not benfit from caching
+        template<typename T>
+        const std::string storeDataEventString(
+            const std::string &full_attr_name, 
+            const std::string &event_time, 
+            const std::string &quality, 
+            std::unique_ptr<vector<T>> &value_r,
+            std::unique_ptr<vector<T>> &value_w,
+            const AttributeTraits &traits);
+
+        // Builds a prepared statement for data event errors 
+        const std::string &storeDataEventErrorStatement(const AttributeTraits &traits);
+
+        // Utility
         void print(std::ostream &os) const noexcept;
 
-        // Static methods
-
-        static std::string tableName(const AttributeTraits &traits);
-        static const std::string &storeAttributeQuery();
-        static const std::string &storeHistoryEventQuery();
-        static const std::string &storeHistoryStringQuery();
-        static const std::string &storeParameterEventQuery();
-        static const std::string &storeErrorQuery();
-        static const std::string &fetchLastHistoryEventQuery();
-        static const std::string &fetchAttributeTraitsQuery();
-
-        // these query strings are built each call, so are cached in the class
-        // that requests them
-        static const std::string fetchValueQuery(
-            const std::string &column_name, const std::string &table_name, const std::string &reference);
-
-        static const std::string fetchAllValuesQuery(
-            const std::string &column_name, const std::string &table_name, const std::string &reference);
-
     private:
         // generic function to handle caching items into the cache maps
         const string &handleCache(
@@ -134,7 +213,7 @@ namespace pqxx_conn
     //=============================================================================
     //=============================================================================
     template<typename T>
-    const string &QueryBuilder::storeDataEventQuery(const AttributeTraits &traits)
+    const string &QueryBuilder::storeDataEventStatement(const AttributeTraits &traits)
     {
         // search the cache for a previous entry
         auto result = _data_event_queries.find(traits);
@@ -182,6 +261,43 @@ namespace pqxx_conn
         // return the previously cached example
         return result->second;
     }
+
+    template<typename T>
+    const std::string QueryBuilder::storeDataEventString(const std::string &full_attr_name, 
+        const std::string &event_time, 
+        const std::string &quality, 
+        std::unique_ptr<vector<T>> &value_r,
+        std::unique_ptr<vector<T>> &value_w,
+        const AttributeTraits &traits)
+    {
+        auto query = "INSERT INTO " + QueryBuilder::tableName(traits) + " (" + DAT_COL_ID + "," + DAT_COL_DATA_TIME;
+
+        if (traits.hasReadData())
+            query = query + "," + DAT_COL_VALUE_R;
+
+        if (traits.hasWriteData())
+            query = query + "," + DAT_COL_VALUE_W;
+
+        // split to ensure increments are in the correct order
+        query = query + "," + DAT_COL_QUALITY + ") VALUES (" + full_attr_name;
+        query = query + ",TO_TIMESTAMP(" + event_time + ")";
+
+        // add the read parameter with cast
+        if (traits.hasReadData())
+            query = query + "," + query_utils::ToString<T>::run(value_r, traits) + 
+                "::" + query_utils::postgresCast<T>(traits.isArray());
+
+        // add the write parameter with cast
+        if (traits.hasWriteData())
+            query = query + "," + query_utils::ToString<T>::run(value_w, traits) + 
+                "::" + query_utils::postgresCast<T>(traits.isArray());
+
+        query = query + "," + quality + ")";
+
+        // now return the built query
+        return query;
+    }
+
 } // namespace pqxx_conn
 } // namespace hdbpp_internal
 #endif // _QUERY_BUILDER_HPP
diff --git a/test/QueryBuilderTests.cpp b/test/QueryBuilderTests.cpp
index 16feaf0b956023b1f3589f0b6cd522d353efd984..793f5c1bff988c43dd19e04eb48d75d396a51a76 100644
--- a/test/QueryBuilderTests.cpp
+++ b/test/QueryBuilderTests.cpp
@@ -19,14 +19,107 @@
 
 #include "QueryBuilder.hpp"
 #include "TimescaleSchema.hpp"
+#include "TestHelpers.hpp"
 #include "catch2/catch.hpp"
 
 using namespace std;
 using namespace hdbpp_internal;
 using namespace hdbpp_internal::pqxx_conn;
+using namespace hdbpp_test::attr_name;
 using namespace Catch::Matchers;
 
-SCENARIO("storeDataEventQuery() returns the correct Value fields for the given traits", "[query-string]")
+SCENARIO("storeDataEventString() returns the correct Value fields for the given traits", "[query-string]")
+{
+    GIVEN("A query builder object with nothing cached")
+    {
+        QueryBuilder query_builder;
+        auto value_r = make_unique<vector<double>>(1.1, 2.2);
+        auto value_r_empty = make_unique<vector<double>>();
+        auto value_w = make_unique<vector<double>>(3.3, 4.4);
+        auto value_w_empty = make_unique<vector<double>>();
+
+        WHEN("Requesting a query string for traits configured for Tango::READ")
+        {
+           AttributeTraits traits {Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE};
+
+            auto result = query_builder.storeDataEventString<double>(
+                TestAttrFQDName,
+                string("0"),
+                string("1"),
+                value_r,
+                value_w_empty,
+                traits);
+
+            THEN("The result must include the DAT_COL_VALUE_R field only")
+            {
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_R));
+                REQUIRE_THAT(result, !Contains(DAT_COL_VALUE_W));
+                REQUIRE_THAT(result, Contains(query_utils::ToString<double>::run(value_r, traits)));
+            }
+        }
+        WHEN("Requesting a query string for traits configured for Tango::WRITE")
+        {
+            AttributeTraits traits {Tango::WRITE, Tango::SCALAR, Tango::DEV_DOUBLE};
+
+            auto result = query_builder.storeDataEventString<double>(
+                TestAttrFQDName,
+                string("0"),
+                string("1"),
+                value_r_empty,
+                value_w,
+                traits);
+
+            THEN("The result must include the DAT_COL_VALUE_W field only")
+            {
+                REQUIRE_THAT(result, !Contains(DAT_COL_VALUE_R));
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_W));
+                REQUIRE_THAT(result, Contains(query_utils::ToString<double>::run(value_w, traits)));
+            }
+        }
+        WHEN("Requesting a query string for traits configured for Tango::READ_WRITE")
+        {
+            AttributeTraits traits {Tango::READ_WRITE, Tango::SCALAR, Tango::DEV_DOUBLE};
+
+            auto result = query_builder.storeDataEventString<double>(
+                TestAttrFQDName,
+                string("0"),
+                string("1"),
+                value_r,
+                value_w,
+                traits);
+
+            THEN("The result must include both the DAT_COL_VALUE_R and DAT_COL_VALUE_W field")
+            {
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_R));
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_W));
+                REQUIRE_THAT(result, Contains(query_utils::ToString<double>::run(value_r, traits)));
+                REQUIRE_THAT(result, Contains(query_utils::ToString<double>::run(value_w, traits)));
+            }
+        }
+        WHEN("Requesting a query string for traits configured for Tango::READ_WITH_WRITE")
+        {
+            AttributeTraits traits {Tango::READ_WITH_WRITE, Tango::SCALAR, Tango::DEV_DOUBLE};
+
+            auto result = query_builder.storeDataEventString<double>(
+                TestAttrFQDName,
+                string("0"),
+                string("1"),
+                value_r,
+                value_w,
+                traits);
+
+            THEN("The result must include both the DAT_COL_VALUE_R and DAT_COL_VALUE_W field")
+            {
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_R));
+                REQUIRE_THAT(result, Contains(DAT_COL_VALUE_W));
+                REQUIRE_THAT(result, Contains(query_utils::ToString<double>::run(value_r, traits)));
+                REQUIRE_THAT(result, Contains(query_utils::ToString<double>::run(value_w, traits)));
+            }
+        }
+    }
+}
+
+SCENARIO("storeDataEventStatement() returns the correct Value fields for the given traits", "[query-string]")
 {
     GIVEN("A query builder object with nothing cached")
     {
@@ -35,7 +128,7 @@ SCENARIO("storeDataEventQuery() returns the correct Value fields for the given t
         WHEN("Requesting a query string for traits configured for Tango::READ")
         {
             AttributeTraits traits {Tango::READ, Tango::SCALAR, Tango::DEV_DOUBLE};
-            auto result = query_builder.storeDataEventQuery<double>(traits);
+            auto result = query_builder.storeDataEventStatement<double>(traits);
 
             THEN("The result must include the DAT_COL_VALUE_R field only")
             {
@@ -48,7 +141,7 @@ SCENARIO("storeDataEventQuery() returns the correct Value fields for the given t
         WHEN("Requesting a query string for traits configured for Tango::WRITE")
         {
             AttributeTraits traits {Tango::WRITE, Tango::SCALAR, Tango::DEV_DOUBLE};
-            auto result = query_builder.storeDataEventQuery<double>(traits);
+            auto result = query_builder.storeDataEventStatement<double>(traits);
 
             THEN("The result must include the DAT_COL_VALUE_W field only")
             {
@@ -61,7 +154,7 @@ SCENARIO("storeDataEventQuery() returns the correct Value fields for the given t
         WHEN("Requesting a query string for traits configured for Tango::READ_WRITE")
         {
             AttributeTraits traits {Tango::READ_WRITE, Tango::SCALAR, Tango::DEV_DOUBLE};
-            auto result = query_builder.storeDataEventQuery<double>(traits);
+            auto result = query_builder.storeDataEventStatement<double>(traits);
 
             THEN("The result must include both the DAT_COL_VALUE_R and DAT_COL_VALUE_W field")
             {
@@ -74,7 +167,7 @@ SCENARIO("storeDataEventQuery() returns the correct Value fields for the given t
         WHEN("Requesting a query string for traits configured for Tango::READ_WITH_WRITE")
         {
             AttributeTraits traits {Tango::READ_WITH_WRITE, Tango::SCALAR, Tango::DEV_DOUBLE};
-            auto result = query_builder.storeDataEventQuery<double>(traits);
+            auto result = query_builder.storeDataEventStatement<double>(traits);
 
             THEN("The result must include both the DAT_COL_VALUE_R and DAT_COL_VALUE_W field")
             {
@@ -163,4 +256,4 @@ TEST_CASE("Creating valid database table names for types", "[query-string]")
             }
         }
     }
-}
\ No newline at end of file
+}