-
Notifications
You must be signed in to change notification settings - Fork 0
/
DatabaseRecord.h
148 lines (117 loc) · 3.54 KB
/
DatabaseRecord.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//
// DatabaseRecord class using sqlite3
// Karl Kosack, 2005
//
#ifndef DATABASERECORD_H
#define DATABASERECORD_H
#include <map>
#include <string>
#include <vector>
#include <sqlite3.h>
#include <stdexcept>
enum DatabaseFieldType {FIELD_INT, FIELD_DOUBLE, FIELD_STRING};
struct DatabaseField {
void *ptr;
DatabaseFieldType type;
bool primary_key;
};
typedef sqlite3* database_t ;
/**
* Wrapper class for the database; eventually, this should encapsulate
* all calls to sqlite3, so the other stuff is independent, and the
* database engine can be changed.
*/
class Database {
public:
Database( std::string filename ) {
if (sqlite3_open( filename.c_str(), &_db )) {
throw std::runtime_error("Couldn't open database '"+filename
+"' because: "+sqlite3_errmsg(_db));
}
}
~Database() {
if (sqlite3_close(_db))
std::cout << "CLOSE: "<<sqlite3_errmsg(_db)<<std::endl;
}
database_t getHandle() {return _db;}
private:
database_t _db;
};
/**
* DatabaseRecord is a base class for generating "smart" structs which
* can be written and read automatically from an sqlite3 database. To
* use it, you should create your own subclass containing any public
* variables you want. In the constructor, you should call
* DatabaseRecord::addField() for each variable, and specify the
* type and a pointer to the data. You should also call
* DatabaseRecord::setTableName() to set the name of the table to
* read/write from in the database. Then, you can call the
* DatabaseRecord methods from your new class to write and read the
* data.
*
* Before doing anything with your subclass of DatabaseRecord, you
* must call the setDatabaseHandle() function and pass it a pointer to
* an open database, otherwise the read and write functions will fail.
*
* example:
*/
class DatabaseRecord {
public:
DatabaseRecord(): _write_in_progress(false),_read_in_progress(false),
_writecount(0), _db(NULL),_tablename("unnamed_table"),
_badcount(0){;}
~DatabaseRecord(){ finish();}
void prepareToRead( std::string where_clause="" );
int readFromDatabase();
void writeToDatabase();
void setDatabaseHandle( database_t db ){
_db=db;
if(!tableExists()) createTable();
}
int getNumFields() { return _fieldmap.size();}
void clearTable();
void finish();
int count(std::string where="");
std::ostream& print(std::ostream&);
void zero();
friend std::ostream& operator<<( std::ostream &stream,DatabaseRecord &rec );
protected:
void setTableName(std::string name){_tablename=name;}
void addField( std::string name, int &variable ) {
DatabaseField f;
f.ptr = (void*) &variable;
f.type = FIELD_INT;
f.primary_key = false;
_fieldmap[name] = f;
}
void addField( std::string name, double &variable ) {
DatabaseField f;
f.ptr = (void*) &variable;
f.type = FIELD_DOUBLE;
f.primary_key = false;
_fieldmap[name] = f;
}
void addField( std::string name, std::string &variable ) {
DatabaseField f;
f.ptr = (void*) &variable;
f.type = FIELD_STRING;
f.primary_key = false;
_fieldmap[name] = f;
}
private:
void createTable();
bool tableExists();
std::string getSchema();
std::string getFieldList();
void prepareToWrite();
database_t _db;
sqlite3_stmt *_rdstmt, *_wrstmt;
std::string _tablename;
std::map< std::string, DatabaseField > _fieldmap;
bool _write_in_progress;
bool _read_in_progress;
int _writecount;
int _badcount;
};
std::string join( std::string delim, std::vector< std::string > &strvect );
#endif