Add 'commit' method to kv transaction
[archive/platform/core/system/libConfig.git] / src / config / kvstore.hpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Jan Olszak <j.olszak@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file
21  * @author Jan Olszak (j.olszak@samsung.com)
22  * @brief  Declaration of a class for key-value storage in a sqlite3 database
23  */
24
25 #ifndef COMMON_CONFIG_KVSTORE_HPP
26 #define COMMON_CONFIG_KVSTORE_HPP
27
28 #include "config/sqlite3/connection.hpp"
29 #include "config/sqlite3/statement.hpp"
30
31 #include <algorithm>
32 #include <initializer_list>
33 #include <memory>
34 #include <mutex>
35 #include <sstream>
36 #include <string>
37 #include <vector>
38 #include <atomic>
39
40 namespace config {
41
42 class KVStore {
43
44 public:
45     /**
46      * A guard struct for thread synchronization and transaction management.
47      */
48     class Transaction {
49     public:
50         Transaction(KVStore& store);
51         ~Transaction();
52
53         Transaction(const Transaction&) = delete;
54         Transaction& operator=(const Transaction&) = delete;
55
56         void commit();
57     private:
58         std::unique_lock<std::recursive_mutex> mLock;
59         KVStore& mKVStore;
60         bool mIsOuter;
61     };
62
63     /**
64      * @param path configuration database file path
65      */
66     explicit KVStore(const std::string& path);
67     ~KVStore();
68
69     KVStore(const KVStore&) = delete;
70     KVStore& operator=(const KVStore&) = delete;
71
72     /**
73      * Clears all the stored data
74      */
75     void clear();
76
77     /**
78      * @return Is there any data stored
79      */
80     bool isEmpty();
81
82     /**
83      * @param key string regexp of the stored values
84      *
85      * @return Does this key exist in the database
86      */
87     bool exists(const std::string& key);
88
89     /**
90      * Removes values corresponding to the passed key.
91      * Many values may correspond to one key, so many values may
92      * need to be deleted
93      *
94      * @param key string regexp of the stored values
95      */
96     void remove(const std::string& key);
97
98     /**
99      * Stores a single value corresponding to the passed key
100      *
101      * @param key string key of the value
102      * @param value value corresponding to the key
103      */
104     template<typename T>
105     void set(const std::string& key, const T& value)
106     {
107         return setInternal(key, value);
108     }
109
110     /**
111      * Gets the value corresponding to the key.
112      * Uses stringstreams to parse.
113      *
114      * @param key string key of the value
115      * @tparam T = std::string desired type of the return value
116      * @return value corresponding to the key
117      */
118     template<typename T = std::string>
119     T get(const std::string& key)
120     {
121         return getInternal(key, static_cast<T*>(nullptr));
122     }
123
124     /**
125      * Returns all stored keys.
126      */
127     std::vector<std::string> getKeys();
128
129 private:
130     typedef std::lock_guard<std::recursive_mutex> Lock;
131
132     std::recursive_mutex mMutex;
133     size_t mTransactionDepth;
134     bool mIsTransactionCommited;
135
136     void setInternal(const std::string& key, const std::string& value);
137     void setInternal(const std::string& key, const std::initializer_list<std::string>& values);
138     void setInternal(const std::string& key, const std::vector<std::string>& values);
139     template<typename T>
140     void setInternal(const std::string& key, const T& value);
141     template<typename T>
142     void setInternal(const std::string& key, const std::vector<T>& values);
143
144     std::string getInternal(const std::string& key, std::string*);
145     std::vector<std::string> getInternal(const std::string& key, std::vector<std::string>*);
146     template<typename T>
147     T getInternal(const std::string& key, T*);
148     template<typename T>
149     std::vector<T> getInternal(const std::string& key, std::vector<T>*);
150
151     std::string mPath;
152     sqlite3::Connection mConn;
153     std::unique_ptr<sqlite3::Statement> mGetValueStmt;
154     std::unique_ptr<sqlite3::Statement> mGetKeyExistsStmt;
155     std::unique_ptr<sqlite3::Statement> mGetIsEmptyStmt;
156     std::unique_ptr<sqlite3::Statement> mGetValueListStmt;
157     std::unique_ptr<sqlite3::Statement> mSetValueStmt;
158     std::unique_ptr<sqlite3::Statement> mRemoveValuesStmt;
159     std::unique_ptr<sqlite3::Statement> mGetKeysStmt;
160
161     void setupDb();
162     void prepareStatements();
163     void createFunctions();
164 };
165
166 namespace {
167 template<typename T>
168 std::string toString(const T& value)
169 {
170     std::ostringstream oss;
171     oss << value;
172     return oss.str();
173 }
174
175 template<typename T>
176 T fromString(const std::string& strValue)
177 {
178     std::istringstream iss(strValue);
179     T value;
180     iss >> value;
181     return value;
182 }
183
184 } // namespace
185
186 template<typename T>
187 void KVStore::setInternal(const std::string& key, const T& value)
188 {
189     setInternal(key, toString(value));
190 }
191
192 template<typename T>
193 void KVStore::setInternal(const std::string& key, const std::vector<T>& values)
194 {
195     std::vector<std::string> strValues(values.size());
196
197     std::transform(values.begin(),
198                    values.end(),
199                    strValues.begin(),
200                    toString<T>);
201
202     setInternal(key, strValues);
203 }
204
205 template<typename T>
206 T KVStore::getInternal(const std::string& key, T*)
207 {
208     return fromString<T>(getInternal(key, static_cast<std::string*>(nullptr)));
209 }
210
211 template<typename T>
212 std::vector<T> KVStore::getInternal(const std::string& key, std::vector<T>*)
213 {
214     std::vector<std::string> strValues = getInternal(key, static_cast<std::vector<std::string>*>(nullptr));
215     std::vector<T> values(strValues.size());
216
217     std::transform(strValues.begin(),
218                    strValues.end(),
219                    values.begin(),
220                    fromString<T>);
221
222     return values;
223 }
224
225 /**
226  * Concatenates all parameters into one std::string.
227  * Uses '.' to connect the terms.
228  * @param args components of the string
229  * @tparam delim optional delimiter
230  * @tparam typename ... Args any type implementing str
231  * @return string created from he args
232  */
233 template<char delim = '.', typename Arg1, typename ... Args>
234 std::string key(const Arg1& a1, const Args& ... args)
235 {
236     std::string ret = toString(a1);
237     std::initializer_list<std::string> strings {toString(args)...};
238     for (const std::string& s : strings) {
239         ret += delim + s;
240     }
241
242     return ret;
243 }
244
245 /**
246  * Function added for key function completeness.
247  *
248  * @tparam delim = '.' parameter not used, added for consistency
249  * @return empty string
250  */
251 template<char delim = '.'>
252 std::string key()
253 {
254     return std::string();
255 }
256
257 } // namespace config
258
259 #endif // COMMON_CONFIG_KVSTORE_HPP
260
261