Hydra 0.20
|
00001 00002 /* 00003 * Copyright (c) 2009 Aleksander B. Demko 00004 * This source code is distributed under the MIT license. 00005 * See the accompanying file LICENSE.MIT.txt for details. 00006 */ 00007 00008 #ifndef __INCLUDED_HYDRA_DB_H__ 00009 #define __INCLUDED_HYDRA_DB_H__ 00010 00011 #include <hydra/TR1.h> 00012 00013 #include <QString> 00014 00015 #include <hydra/Record.h> 00016 00017 struct sqlite3; // forward 00018 typedef struct sqlite3 sqlite3; // forward 00019 struct sqlite3_stmt; // forward 00020 typedef struct sqlite3_stmt sqlite3_stmt; // forward 00021 00022 namespace hydra 00023 { 00024 class DB; 00025 class Cursor; 00026 }; 00027 00028 /** 00029 * This represents a sqlite database table. 00030 * 00031 * This in the future, this can be abtracted away as an interface to allow 00032 * many possible backends (the old BerkleyDB one, postgresql, etc) 00033 * 00034 * Internally, this backend uses std::string and 8-bit UTF strings 00035 * for size-conservation. 00036 * 00037 * @author Aleksander Demko 00038 */ 00039 class hydra::DB 00040 { 00041 public: 00042 /** 00043 * Creates a DB (disk backed map). It will use the given sqllite db 00044 * file and prepend the given prefix/namespace to the tables. 00045 * Using different tablescope's allows you to have multiple DBs 00046 * in the same sqlite file. 00047 * 00048 * @param filename the sqlite filename on disk 00049 * @param tablescope the prefix/table name to use. Cannot be empty. 00050 * @author Aleksander Demko 00051 */ 00052 DB(const QString &filename, const QString & tablescope); 00053 /** 00054 * Creates a DB (disk backed map). It will use the given sqllite db 00055 * file and prepend the given prefix/namespace to the tables. 00056 * 00057 * This constructor allows you to reuse anoter DB instance's sqlite connection. 00058 * 00059 * @param linked_db the DB from whome this DB will share a single sqlite connection. 00060 * @param tablescope the prefix/table name to use. Cannot be empty. 00061 * @author Aleksander Demko 00062 */ 00063 DB(DB &linked_db, const QString &tablescope); 00064 /// destructor 00065 virtual ~DB(); 00066 00067 /// is this key even in the db? 00068 bool contains(const std::string &key) { return contains(key.c_str()); } 00069 /// is this key even in the db? 00070 bool contains(const QString &key) { return contains(key.toUtf8().constData()); } 00071 /// is this key even in the db? 00072 bool contains(const char *key); 00073 00074 /// removes the key from the db, returns true if anything was done 00075 bool erase(const std::string &key) { return erase(key.c_str()); } 00076 /// removes the key from the db, returns true if anything was done 00077 bool erase(const QString &key) { return erase(key.toUtf8().constData()); } 00078 /// removes the key from the db, returns true if anything was done 00079 bool erase(const char *key); 00080 00081 /// saves to the db, returns true on success, will replace if exists 00082 bool insert(const std::string &key, const std::string &value) { return insert(key.c_str(), value); } 00083 /// saves to the db, returns true on success, will replace if exists 00084 bool insert(const QString &key, const std::string &value) { return insert(key.toUtf8().constData(), value); } 00085 /// saves to the db, returns true on success, will replace if exists 00086 bool insert(const char *key, const std::string &value); 00087 00088 /// returns false on not-found or failed to load 00089 bool get(const std::string &key, std::string &value) { return get(key.c_str(), value); } 00090 /// returns false on not-found or failed to load 00091 bool get(const QString &key, std::string &value) { return get(key.toUtf8().constData(), value); } 00092 /// returns false on not-found or failed to load 00093 bool get(const char *key, std::string &value); 00094 00095 /// saves to the db, returns true on success, will replace if exists 00096 bool insert(const std::string &key, const hydra::Record &value) { return insert(key.c_str(), value); } 00097 /// saves to the db, returns true on success, will replace if exists 00098 bool insert(const QString &key, const hydra::Record &value) { return insert(key.toUtf8().constData(), value); } 00099 /// saves to the db, returns true on success, will replace if exists 00100 bool insert(const char *key, const hydra::Record &value); 00101 00102 /// returns false on not-found or failed to load 00103 bool get(const std::string &key, hydra::Record &value) { return get(key.c_str(), value); } 00104 /// returns false on not-found or failed to load 00105 bool get(const QString &key, hydra::Record &value) { return get(key.toUtf8().constData(), value); } 00106 /// returns false on not-found or failed to load 00107 bool get(const char *key, hydra::Record &value); 00108 00109 private: 00110 void initDB(void); 00111 void initPrepared(void); 00112 00113 private: 00114 class Connection 00115 { 00116 public: 00117 QString fileName; 00118 sqlite3 *handle; 00119 public: 00120 Connection(void) : handle(0) { } 00121 ~Connection(); 00122 }; 00123 class Statement 00124 { 00125 public: 00126 sqlite3_stmt *handle; 00127 public: 00128 Statement(void) : handle(0) { } 00129 ~Statement(); 00130 }; 00131 class ResetOnExit 00132 { 00133 public: 00134 ResetOnExit(sqlite3_stmt *handle) : dm_handle(handle) { } 00135 ~ResetOnExit(); 00136 private: 00137 sqlite3_stmt *dm_handle; 00138 }; 00139 00140 private: 00141 friend class hydra::Cursor; 00142 00143 std::shared_ptr<Connection> dm_connection; 00144 QString dm_table; 00145 00146 // these are for performance cacheing 00147 Statement dm_put_statement, dm_has_statement, dm_get_statement, dm_erase_statement; 00148 00149 // hot buffer used by the record-based put function 00150 QByteArray dm_put_hotbuf, dm_get_hotbuf; 00151 }; 00152 00153 /** 00154 * A iterator though a DB. 00155 * 00156 * @author Aleksander Demko 00157 */ 00158 class hydra::Cursor 00159 { 00160 public: 00161 /** 00162 * Constructor. 00163 * This will iterate though all the entries in the DB. 00164 * 00165 * The cursor will initially be inValid. You must use next() 00166 * to move to the first valid row (if any). 00167 * 00168 * @author Aleksander Demko 00169 */ 00170 Cursor(hydra::DB &db); 00171 /** 00172 * Constructor. 00173 * This will iterate though all the entries in the DB whos key has 00174 * the given prefix 00175 * 00176 * The cursor will initially be inValid. You must use next() 00177 * to move to the first valid row (if any). 00178 * 00179 * @author Aleksander Demko 00180 */ 00181 Cursor(hydra::DB &db, const QString &prefix); 00182 00183 /** 00184 * Is the cursot at a valid row? 00185 * 00186 * @author Aleksander Demko 00187 */ 00188 bool isValid(void) const { return dm_isvalid; } 00189 00190 /** 00191 * Move the cursor to the next row, returns true if this was successul 00192 * and the cursor is at the next row and is valid. 00193 * 00194 * @author Aleksander Demko 00195 */ 00196 bool next(void); 00197 00198 /** 00199 * Returns the key value at the current row. The current row must be valid. 00200 * 00201 * @author Aleksander Demko 00202 */ 00203 const char * getKey(void); 00204 00205 /** 00206 * Loads the current value. The current row must be valid. 00207 * 00208 * @author Aleksander Demko 00209 */ 00210 void get(std::string &value); 00211 00212 /** 00213 * Loads the current value. The current row must be valid. 00214 * 00215 * @author Aleksander Demko 00216 */ 00217 void get(QString &value); 00218 00219 /** 00220 * Loads the current value. The current row must be valid. 00221 * 00222 * Returns false if the record failed to deserialize (ie. it threw an exception) 00223 * 00224 * @author Aleksander Demko 00225 */ 00226 bool get(hydra::Record &value); 00227 00228 //Erase(void); 00229 00230 private: 00231 bool dm_isvalid; 00232 00233 std::shared_ptr<DB::Connection> dm_connection; 00234 00235 DB::Statement dm_select_statement; 00236 00237 QByteArray dm_put_hotbuf, dm_get_hotbuf, dm_prefix_string; 00238 }; 00239 00240 #endif 00241