载入中...
搜索中...
未找到
Database.h
浏览该文件的文档.
1#pragma once
2
3#include "common/Module.h"
4
5#include <cstdint>
6#include <functional>
7#include <memory>
8#include <stdexcept>
9#include <string>
10#include <unordered_map>
11#include <utility>
12#include <variant>
13#include <vector>
14
15namespace Poco::Data {
16class Session;
17}
18
19namespace eve::database {
20
21class Model;
22class Query;
23
24using Value = std::variant<std::monostate, std::int64_t, double, std::string, bool>;
25using Row = std::unordered_map<std::string, Value>;
26
28template <class T>
29struct Field {
30 std::string name;
31 std::function<Value(const T&)> read;
32 std::function<void(T&, const Value&)> write;
33 std::string sqlType = "TEXT";
34 bool primaryKey = false;
35};
36
37template <class T>
38struct Mapping {
39 std::string table;
40 std::vector<Field<T>> fields;
41
42 Row toRow(const T& object) const {
43 Row row;
44 for (const auto& field : fields) row[field.name] = field.read(object);
45 return row;
46 }
47
48 T fromRow(const Row& row) const {
49 T object{};
50 for (const auto& field : fields) {
51 auto it = row.find(field.name);
52 if (it != row.end()) field.write(object, it->second);
53 }
54 return object;
55 }
56};
57
63public:
65 Connection(std::string connector, std::string connectionString);
67
68 Connection(const Connection&) = delete;
69 Connection& operator=(const Connection&) = delete;
70
72 bool isConnected() const;
74 void close();
76 int execute(const std::string& sql);
78 std::vector<Row> query(const std::string& sql);
80 std::string queryJson(const std::string& sql);
82 int insert(const std::string& table, const Row& values);
84 int update(const std::string& table, const Row& values, const std::string& whereClause);
86 int remove(const std::string& table, const std::string& whereClause);
87
89 int insertJson(const std::string& table, const std::string& json);
91 int updateJson(const std::string& table, const std::string& json, const std::string& whereClause);
92
94 int updateByKey(const std::string& table, const Row& values, const std::string& key, const Value& id);
96 int removeByKey(const std::string& table, const std::string& key, const Value& id);
98 std::vector<Row> queryByKey(const std::string& table, const std::string& key, const Value& id);
100 Model* model(std::string table, std::string primaryKey = "id");
102 Query* from(std::string table);
103
105 template <class T>
106 int save(const Mapping<T>& mapping, const T& object) {
107 return insert(mapping.table, mapping.toRow(object));
108 }
109
111 template <class Range, class Mapper>
112 int exportECS(const std::string& table, const Range& entities, Mapper mapper) {
113 int count = 0;
114 execute("BEGIN");
115 try {
116 for (const auto& entity : entities) count += insert(table, mapper(entity));
117 execute("COMMIT");
118 } catch (...) {
119 try {
120 execute("ROLLBACK");
121 } catch (...) {
122 }
123 throw;
124 }
125 return count;
126 }
127
128private:
129 std::unique_ptr<Poco::Data::Session> session_;
130};
131
133class Query {
134public:
135 Query(Connection* connection, std::string table);
136 Query* where(const std::string& column, const std::string& op, Value value);
137 Query* whereJson(const std::string& column, const std::string& op, const std::string& valueJson);
138 Query* orderBy(const std::string& column, bool ascending = true);
139 Query* limit(int count);
140 Query* offset(int count);
141 std::vector<Row> all();
142 std::string allJson();
143 std::string firstJson();
144 int count();
145
146private:
147 std::string selectSql(bool countOnly, int forcedLimit = -1) const;
148 Connection* connection_;
149 std::string table_;
150 std::vector<std::string> predicates_;
151 std::vector<std::string> ordering_;
152 int limit_ = -1;
153 int offset_ = 0;
154};
155
157template <class T>
159public:
160 Repository(Connection& connection, Mapping<T> mapping) : connection_(connection), mapping_(std::move(mapping)) {}
161
162 void createTable(bool ifNotExists = true) {
163 if (mapping_.fields.empty()) throw std::invalid_argument("ORM mapping has no fields");
164 std::string sql = "CREATE TABLE ";
165 if (ifNotExists) sql += "IF NOT EXISTS ";
166 sql += mapping_.table + " (";
167 for (std::size_t i = 0; i < mapping_.fields.size(); ++i) {
168 const auto& field = mapping_.fields[i];
169 if (i) sql += ',';
170 sql += field.name + " " + field.sqlType;
171 if (field.primaryKey) sql += " PRIMARY KEY";
172 }
173 connection_.execute(sql + ")");
174 }
175
176 int insert(const T& object) { return connection_.insert(mapping_.table, mapping_.toRow(object)); }
177
178 std::vector<T> all() {
179 std::vector<T> objects;
180 for (const auto& row : connection_.query("SELECT * FROM " + mapping_.table))
181 objects.push_back(mapping_.fromRow(row));
182 return objects;
183 }
184
185 bool find(const Value& id, T& object) {
186 auto rows = connection_.queryByKey(mapping_.table, primaryKey().name, id);
187 if (rows.empty()) return false;
188 object = mapping_.fromRow(rows.front());
189 return true;
190 }
191
192 int update(const T& object) {
193 const auto& key = primaryKey();
194 Row values = mapping_.toRow(object);
195 Value id = values.at(key.name);
196 values.erase(key.name);
197 return connection_.updateByKey(mapping_.table, values, key.name, id);
198 }
199
200 int remove(const Value& id) { return connection_.removeByKey(mapping_.table, primaryKey().name, id); }
201
202 std::vector<T> select(const std::function<void(Query&)>& configure) {
203 Query query(&connection_, mapping_.table);
204 configure(query);
205 std::vector<T> objects;
206 for (const auto& row : query.all()) objects.push_back(mapping_.fromRow(row));
207 return objects;
208 }
209
210private:
211 const Field<T>& primaryKey() const {
212 for (const auto& field : mapping_.fields)
213 if (field.primaryKey) return field;
214 throw std::logic_error("ORM mapping requires one primary key field");
215 }
216
217 Connection& connection_;
218 Mapping<T> mapping_;
219};
220
222class Model {
223public:
224 Model(Connection* connection, std::string table, std::string primaryKey);
225 int insertJson(const std::string& json);
226 std::string allJson();
227 std::string findJson(const std::string& idJson);
228 int updateJson(const std::string& idJson, const std::string& json);
229 int remove(const std::string& idJson);
230 Query* query();
231
232private:
233 Connection* connection_;
234 std::string table_;
235 std::string primaryKey_;
236};
237
242class Database : public Module {
243public:
245 Database() = default;
246 ~Database() override = default;
247
249 Connection* connect(std::string connector, std::string connectionString);
251 Connection* connectSQLite(std::string path);
252};
253
254} // namespace eve::database
std::string value
std::map< std::string, Var > values
glm::mat4 model
const char * name
Definition RockMesh.cpp:21
SQLite connection with a small ORM layer on top of Poco::Data. Tables/columns are quoted identifiers;...
Definition Database.h:62
int save(const Mapping< T > &mapping, const T &object)
ORM helper: persists one mapped object.
Definition Database.h:106
std::string queryJson(const std::string &sql)
Runs query() and serializes the rows to a JSON array.
Definition Database.cpp:119
std::vector< Row > query(const std::string &sql)
Runs a SELECT and returns every row as name/value maps.
Definition Database.cpp:103
Connection & operator=(const Connection &)=delete
void close()
Closes the session (idempotent).
Definition Database.cpp:94
Query * from(std::string table)
Builds a fluent Query builder for a table.
Definition Database.cpp:173
std::vector< Row > queryByKey(const std::string &table, const std::string &key, const Value &id)
Selects rows where key == id.
Definition Database.cpp:165
int update(const std::string &table, const Row &values, const std::string &whereClause)
Updates rows matching whereClause; returns the affected row count.
Definition Database.cpp:135
int insert(const std::string &table, const Row &values)
Inserts a row map; returns the affected row count.
Definition Database.cpp:121
Connection(const Connection &)=delete
int remove(const std::string &table, const std::string &whereClause)
Deletes rows matching whereClause; returns the affected row count.
Definition Database.cpp:146
int removeByKey(const std::string &table, const std::string &key, const Value &id)
Deletes a single row by primary key value.
Definition Database.cpp:161
bool isConnected() const
True while the underlying session is open.
Definition Database.cpp:93
int exportECS(const std::string &table, const Range &entities, Mapper mapper)
ORM helper: persists a range of mapped entities in one transaction.
Definition Database.h:112
int execute(const std::string &sql)
Executes a statement; returns the affected row count.
Definition Database.cpp:98
int updateJson(const std::string &table, const std::string &json, const std::string &whereClause)
Script-friendly update; whereClause is raw SQL.
Definition Database.cpp:153
int insertJson(const std::string &table, const std::string &json)
Script-friendly insert: JSON must be an object of column/value pairs.
Definition Database.cpp:150
int updateByKey(const std::string &table, const Row &values, const std::string &key, const Value &id)
Updates a single row by primary key value.
Definition Database.cpp:157
Database module (eve.Database): SQLite connection factory. Script: db <- eve.Database(); conn <- db....
Definition Database.h:242
Connection * connectSQLite(std::string path)
Opens a SQLite database file (":memory:" is supported).
Definition Database.cpp:260
~Database() override=default
Connection * connect(std::string connector, std::string connectionString)
Opens a connection with an explicit Poco connector name.
Definition Database.cpp:257
Runtime ORM model exposed to Squirrel.
Definition Database.h:222
std::string allJson()
Definition Database.cpp:244
int updateJson(const std::string &idJson, const std::string &json)
Definition Database.cpp:248
int insertJson(const std::string &json)
Definition Database.cpp:243
int remove(const std::string &idJson)
Definition Database.cpp:251
std::string findJson(const std::string &idJson)
Definition Database.cpp:245
Composable filtered/sorted/paged query shared by C++ and scripts.
Definition Database.h:133
std::string firstJson()
Definition Database.cpp:227
std::vector< Row > all()
Definition Database.cpp:225
Query * limit(int count)
Definition Database.cpp:196
Query * offset(int count)
Definition Database.cpp:202
Query * orderBy(const std::string &column, bool ascending=true)
Definition Database.cpp:191
Query * where(const std::string &column, const std::string &op, Value value)
Definition Database.cpp:179
Query * whereJson(const std::string &column, const std::string &op, const std::string &valueJson)
Definition Database.cpp:187
std::string allJson()
Definition Database.cpp:226
Typed active-record repository built from a Mapping<T>.
Definition Database.h:158
std::vector< T > all()
Definition Database.h:178
std::vector< T > select(const std::function< void(Query &)> &configure)
Definition Database.h:202
int update(const T &object)
Definition Database.h:192
int insert(const T &object)
Definition Database.h:176
bool find(const Value &id, T &object)
Definition Database.h:185
void createTable(bool ifNotExists=true)
Definition Database.h:162
Repository(Connection &connection, Mapping< T > mapping)
Definition Database.h:160
int remove(const Value &id)
Definition Database.h:200
std::unordered_map< std::string, Value > Row
Definition Database.h:25
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
Definition Database.h:24
A named field used by the small, explicit ORM mapping layer.
Definition Database.h:29
std::function< void(T &, const Value &)> write
Definition Database.h:32
std::string sqlType
Definition Database.h:33
std::string name
Definition Database.h:30
std::function< Value(const T &)> read
Definition Database.h:31
T fromRow(const Row &row) const
Definition Database.h:48
std::string table
Definition Database.h:39
std::vector< Field< T > > fields
Definition Database.h:40
Row toRow(const T &object) const
Definition Database.h:42