Add 'commit' method to kv transaction
[archive/platform/core/system/libConfig.git] / src / config / kvstore.hpp
index 991625b..0717665 100644 (file)
 #ifndef COMMON_CONFIG_KVSTORE_HPP
 #define COMMON_CONFIG_KVSTORE_HPP
 
-#include "config/sqlite3/statement.hpp"
 #include "config/sqlite3/connection.hpp"
+#include "config/sqlite3/statement.hpp"
 
-#include <sqlite3.h>
-#include <vector>
-#include <string>
-#include <memory>
+#include <algorithm>
 #include <initializer_list>
+#include <memory>
 #include <mutex>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <atomic>
 
 namespace config {
 
 class KVStore {
 
 public:
+    /**
+     * A guard struct for thread synchronization and transaction management.
+     */
+    class Transaction {
+    public:
+        Transaction(KVStore& store);
+        ~Transaction();
+
+        Transaction(const Transaction&) = delete;
+        Transaction& operator=(const Transaction&) = delete;
+
+        void commit();
+    private:
+        std::unique_lock<std::recursive_mutex> mLock;
+        KVStore& mKVStore;
+        bool mIsOuter;
+    };
 
     /**
      * @param path configuration database file path
      */
-    KVStore(const std::string& path);
+    explicit KVStore(const std::string& path);
     ~KVStore();
 
+    KVStore(const KVStore&) = delete;
+    KVStore& operator=(const KVStore&) = delete;
+
     /**
      * Clears all the stored data
      */
     void clear();
 
-
     /**
-     * @return Number of all stored values
+     * @return Is there any data stored
      */
-    unsigned int size();
+    bool isEmpty();
 
     /**
      * @param key string regexp of the stored values
      *
-     * @return Number of values corresponding to the passed key
+     * @return Does this key exist in the database
      */
-    unsigned int count(const std::string& key);
+    bool exists(const std::string& key);
 
     /**
      * Removes values corresponding to the passed key.
@@ -76,62 +97,162 @@ public:
 
     /**
      * Stores a single value corresponding to the passed key
-     * @param key string key of the value
-     * @param value string value
-     */
-    void set(const std::string& key, const std::string& value);
-
-    /**
-     * Stores a vector of values.
-     * Generates new keys using appending a '.' and consecutive integers.
-     * Removes values corresponding to this key before anything is added.
      *
      * @param key string key of the value
-     * @param value string value
+     * @param value value corresponding to the key
      */
-    void set(const std::string& key, const std::vector<std::string>& values);
+    template<typename T>
+    void set(const std::string& key, const T& value)
+    {
+        return setInternal(key, value);
+    }
 
     /**
-     * Stores values from the list.
+     * Gets the value corresponding to the key.
+     * Uses stringstreams to parse.
      *
-     * @see KVStore::set(const std::string& key, const std::vector<std::string>& values)
-     * @param key string key of the value
-     * @param values [description]
-     */
-    void set(const std::string& key, const std::initializer_list<std::string>& values);
-
-    /**
      * @param key string key of the value
-     * @return string value corresponding to this particular key
+     * @tparam T = std::string desired type of the return value
+     * @return value corresponding to the key
      */
-    std::string get(const std::string& key);
+    template<typename T = std::string>
+    T get(const std::string& key)
+    {
+        return getInternal(key, static_cast<T*>(nullptr));
+    }
 
     /**
-     * @param key string key of the value
-     * @return vector of values corresponding to the key
+     * Returns all stored keys.
      */
-    std::vector<std::string> list(const std::string& key);
+    std::vector<std::string> getKeys();
 
 private:
-    typedef std::lock_guard<std::mutex> Lock;
+    typedef std::lock_guard<std::recursive_mutex> Lock;
+
+    std::recursive_mutex mMutex;
+    size_t mTransactionDepth;
+    bool mIsTransactionCommited;
+
+    void setInternal(const std::string& key, const std::string& value);
+    void setInternal(const std::string& key, const std::initializer_list<std::string>& values);
+    void setInternal(const std::string& key, const std::vector<std::string>& values);
+    template<typename T>
+    void setInternal(const std::string& key, const T& value);
+    template<typename T>
+    void setInternal(const std::string& key, const std::vector<T>& values);
 
-    std::mutex mConnMtx;
+    std::string getInternal(const std::string& key, std::string*);
+    std::vector<std::string> getInternal(const std::string& key, std::vector<std::string>*);
+    template<typename T>
+    T getInternal(const std::string& key, T*);
+    template<typename T>
+    std::vector<T> getInternal(const std::string& key, std::vector<T>*);
 
+    std::string mPath;
     sqlite3::Connection mConn;
     std::unique_ptr<sqlite3::Statement> mGetValueStmt;
-    std::unique_ptr<sqlite3::Statement> mGetValueCountStmt;
-    std::unique_ptr<sqlite3::Statement> mGetSizeStmt;
+    std::unique_ptr<sqlite3::Statement> mGetKeyExistsStmt;
+    std::unique_ptr<sqlite3::Statement> mGetIsEmptyStmt;
     std::unique_ptr<sqlite3::Statement> mGetValueListStmt;
     std::unique_ptr<sqlite3::Statement> mSetValueStmt;
     std::unique_ptr<sqlite3::Statement> mRemoveValuesStmt;
+    std::unique_ptr<sqlite3::Statement> mGetKeysStmt;
 
     void setupDb();
     void prepareStatements();
+    void createFunctions();
+};
 
-    void removeInternal(const std::string& key);
-    unsigned int countInternal(const std::string& key);
+namespace {
+template<typename T>
+std::string toString(const T& value)
+{
+    std::ostringstream oss;
+    oss << value;
+    return oss.str();
+}
 
-};
+template<typename T>
+T fromString(const std::string& strValue)
+{
+    std::istringstream iss(strValue);
+    T value;
+    iss >> value;
+    return value;
+}
+
+} // namespace
+
+template<typename T>
+void KVStore::setInternal(const std::string& key, const T& value)
+{
+    setInternal(key, toString(value));
+}
+
+template<typename T>
+void KVStore::setInternal(const std::string& key, const std::vector<T>& values)
+{
+    std::vector<std::string> strValues(values.size());
+
+    std::transform(values.begin(),
+                   values.end(),
+                   strValues.begin(),
+                   toString<T>);
+
+    setInternal(key, strValues);
+}
+
+template<typename T>
+T KVStore::getInternal(const std::string& key, T*)
+{
+    return fromString<T>(getInternal(key, static_cast<std::string*>(nullptr)));
+}
+
+template<typename T>
+std::vector<T> KVStore::getInternal(const std::string& key, std::vector<T>*)
+{
+    std::vector<std::string> strValues = getInternal(key, static_cast<std::vector<std::string>*>(nullptr));
+    std::vector<T> values(strValues.size());
+
+    std::transform(strValues.begin(),
+                   strValues.end(),
+                   values.begin(),
+                   fromString<T>);
+
+    return values;
+}
+
+/**
+ * Concatenates all parameters into one std::string.
+ * Uses '.' to connect the terms.
+ * @param args components of the string
+ * @tparam delim optional delimiter
+ * @tparam typename ... Args any type implementing str
+ * @return string created from he args
+ */
+template<char delim = '.', typename Arg1, typename ... Args>
+std::string key(const Arg1& a1, const Args& ... args)
+{
+    std::string ret = toString(a1);
+    std::initializer_list<std::string> strings {toString(args)...};
+    for (const std::string& s : strings) {
+        ret += delim + s;
+    }
+
+    return ret;
+}
+
+/**
+ * Function added for key function completeness.
+ *
+ * @tparam delim = '.' parameter not used, added for consistency
+ * @return empty string
+ */
+template<char delim = '.'>
+std::string key()
+{
+    return std::string();
+}
 
 } // namespace config