Skip to content

Commit 0b8e043

Browse files
committed
enable save with auto increment id
1 parent ff5626d commit 0b8e043

File tree

3 files changed

+121
-72
lines changed

3 files changed

+121
-72
lines changed

include/database.h

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,26 +100,34 @@ namespace sqlite_reflection {
100100
const auto max_id = query.GetMaxId();
101101
return max_id;
102102
}
103-
103+
104104
/// Saves a given record in the database.
105105
/// This corresponds to an INSERT query in the SQL syntax
106106
template <typename T>
107107
void Save(const T& model) const {
108-
const auto type_id = typeid(T).name();
109-
const auto& record = GetRecord(type_id);
110-
Save((void*)&model, record);
108+
Save(model, false);
111109
}
110+
111+
/// Saves a given record in the database and auto-increments its id.
112+
/// This corresponds to an INSERT query in the SQL syntax
113+
template <typename T>
114+
void SaveAutoIncrement(const T& model) const {
115+
Save(model, true);
116+
}
112117

113118
/// Saves multiple records iteratively in the database.
114119
/// This corresponds to an INSERT query in the SQL syntax
115120
template <typename T>
116121
void Save(const std::vector<T>& models) const {
117-
const auto type_id = typeid(T).name();
118-
const auto& record = GetRecord(type_id);
119-
for (const auto& model : models) {
120-
Save((void*)&model, record);
121-
}
122+
Save(models, false);
122123
}
124+
125+
/// Saves multiple records iteratively in the database and auto-increments their ids.
126+
/// This corresponds to an INSERT query in the SQL syntax
127+
template <typename T>
128+
void SaveAutoIncrement(const std::vector<T>& models) const {
129+
Save(models, true);
130+
}
123131

124132
/// Updates a given record in the database.
125133
/// This corresponds to an UPDATE query in the SQL syntax
@@ -195,6 +203,39 @@ namespace sqlite_reflection {
195203
}
196204
return models;
197205
}
206+
207+
/// Saves a given record in the database.
208+
/// This corresponds to an INSERT query in the SQL syntax
209+
template <typename T>
210+
void Save(const T& model, bool auto_increment_id) const {
211+
const auto type_id = typeid(T).name();
212+
const auto& record = GetRecord(type_id);
213+
T saved_model(model);
214+
if (auto_increment_id) {
215+
const auto current_max_id = GetMaxId<T>();
216+
saved_model.id = current_max_id + 1;
217+
}
218+
Save((void*)&saved_model, record);
219+
}
220+
221+
/// Saves multiple records iteratively in the database.
222+
/// This corresponds to an INSERT query in the SQL syntax
223+
template <typename T>
224+
void Save(const std::vector<T>& models, bool auto_increment_id) const {
225+
const auto type_id = typeid(T).name();
226+
const auto& record = GetRecord(type_id);
227+
const auto current_max_id = auto_increment_id ? GetMaxId<T>() : 0;
228+
for (auto i = 0; i < models.size(); ++i) {
229+
const auto& model = models[i];
230+
if (auto_increment_id) {
231+
T saved_model(model);
232+
saved_model.id = current_max_id + i + 1;
233+
Save((void*)&saved_model, record);
234+
} else {
235+
Save((void*)&model, record);
236+
}
237+
}
238+
}
198239

199240
/// Saves a single record in the database
200241
void Save(void* p, const Reflection& record) const;

include/reflection.h

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,6 @@
3535
#include <stddef.h>
3636
#endif
3737

38-
// todo: BETWEEN / IN / NOT IN predicate
39-
// todo: save with automatic id
40-
// todo: nullable types
41-
// todo: relations
42-
4338
/// The storage class in an SQLite column for a given member of a struct, for which reflection is enabled
4439
/// https://www.sqlite.org/datatype3.html
4540
enum class REFLECTION_EXPORT SqliteStorageClass
@@ -146,12 +141,10 @@ REFLECTION_EXPORT Reflection& GetRecordFromTypeId(const std::string& type_id);
146141
///
147142
/// example:
148143
/// struct Person {
149-
/// double weight; <---- corresponds to index 0
150-
/// std::wstring name; <---- corresponds to index 1
144+
/// double weight; <---- corresponds to index 0
145+
/// std::wstring name; <---- corresponds to index 1
146+
/// int64_t id;
151147
/// }
152-
///
153-
/// However, since all reflectable structs must be uniquely identified in SQLite,
154-
/// their first member is always int64_t id
155148
REFLECTION_EXPORT char* GetMemberAddress(void* p, const Reflection& record, size_t i);
156149

157150
#endif // REFLECTION_INTERNAL
@@ -170,7 +163,6 @@ REFLECTION_EXPORT char* GetMemberAddress(void* p, const Reflection& record, size
170163
struct REFLECTABLE_DLL_EXPORT REFLECTABLE {
171164
// member declaration according to the order given in source code
172165
#define MEMBER_DECLARE(L, R) L R;
173-
MEMBER_DECLARE(int64_t, id)
174166
#define MEMBER_INT(R) MEMBER_DECLARE(int64_t, R)
175167
#define MEMBER_REAL(R) MEMBER_DECLARE(double, R)
176168
#define MEMBER_TEXT(R) MEMBER_DECLARE(std::wstring, R)
@@ -185,6 +177,7 @@ REFLECTION_EXPORT char* GetMemberAddress(void* p, const Reflection& record, size
185177
#undef MEMBER_DATETIME
186178
#undef MEMBER_BOOL
187179
#undef FUNC
180+
int64_t id;
188181

189182
// custom function declaration
190183
#define MEMBER_INT(R)

tests/database_test.cc

Lines changed: 67 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ TEST_F(DatabaseTest, Initialization) {
5353
TEST_F(DatabaseTest, SingleInsertion) {
5454
const auto& db = Database::Instance();
5555

56-
const Person p{1, L"παναγιώτης", L"ανδριανόπουλος", 39};
56+
const Person p{L"παναγιώτης", L"ανδριανόπουλος", 39, 1};
5757
db.Save(p);
5858

5959
const auto all_persons = db.FetchAll<Person>();
@@ -65,13 +65,28 @@ TEST_F(DatabaseTest, SingleInsertion) {
6565
EXPECT_EQ(p.id, all_persons[0].id);
6666
}
6767

68+
TEST_F(DatabaseTest, SingleInsertionWithAutoIdIncrement) {
69+
const auto& db = Database::Instance();
70+
71+
const Person p{L"παναγιώτης", L"ανδριανόπουλος", 39};
72+
db.SaveAutoIncrement(p);
73+
74+
const auto all_persons = db.FetchAll<Person>();
75+
EXPECT_EQ(1, all_persons.size());
76+
77+
EXPECT_EQ(p.first_name, all_persons[0].first_name);
78+
EXPECT_EQ(p.last_name, all_persons[0].last_name);
79+
EXPECT_EQ(p.age, all_persons[0].age);
80+
EXPECT_EQ(1, all_persons[0].id);
81+
}
82+
6883
TEST_F(DatabaseTest, MultipleInsertions) {
6984
const auto& db = Database::Instance();
7085

7186
std::vector<Person> persons;
7287

73-
persons.push_back({3, L"παναγιώτης", L"ανδριανόπουλος", 28, false});
74-
persons.push_back({5, L"peter", L"meier", 32, true});
88+
persons.push_back({L"παναγιώτης", L"ανδριανόπουλος", 28, false, 3});
89+
persons.push_back({L"peter", L"meier", 32, true, 5});
7590

7691
db.Save(persons);
7792

@@ -90,7 +105,7 @@ TEST_F(DatabaseTest, MultipleInsertions) {
90105
TEST_F(DatabaseTest, InsertionOnOneTypeDoesNotAffectOtherType) {
91106
const auto& db = Database::Instance();
92107

93-
const Person p{1, L"παναγιώτης", L"ανδριανόπουλος", 39};
108+
const Person p{L"παναγιώτης", L"ανδριανόπουλος", 39, 1};
94109
db.Save(p);
95110

96111
const auto all_pets = db.FetchAll<Pet>();
@@ -100,7 +115,7 @@ TEST_F(DatabaseTest, InsertionOnOneTypeDoesNotAffectOtherType) {
100115
TEST_F(DatabaseTest, SingleUpdate) {
101116
const auto& db = Database::Instance();
102117

103-
Person p{1, L"παναγιώτης", L"ανδριανόπουλος", 39};
118+
Person p{L"παναγιώτης", L"ανδριανόπουλος", 39, 1};
104119
db.Save(p);
105120

106121
p.age = 23;
@@ -122,8 +137,8 @@ TEST_F(DatabaseTest, MultipleUpdates) {
122137

123138
std::vector<Person> persons;
124139

125-
persons.push_back({3, L"john", L"doe", 28});
126-
persons.push_back({5, L"mary", L"poppins", 20});
140+
persons.push_back({L"john", L"doe", 28, false, 3});
141+
persons.push_back({L"mary", L"poppins", 20, false, 5});
127142

128143
db.Save(persons);
129144

@@ -148,9 +163,9 @@ TEST_F(DatabaseTest, DeleteWithRecord) {
148163

149164
std::vector<Person> persons;
150165

151-
persons.push_back({3, L"παναγιώτης", L"ανδριανόπουλος", 28});
152-
persons.push_back({5, L"peter", L"meier", 32});
153-
persons.push_back({13, L"mary", L"poppins", 20});
166+
persons.push_back({L"παναγιώτης", L"ανδριανόπουλος", 28, false, 3});
167+
persons.push_back({L"peter", L"meier", 32, false, 5});
168+
persons.push_back({L"mary", L"poppins", 20, false, 13});
154169

155170
db.Save(persons);
156171

@@ -179,9 +194,9 @@ TEST_F(DatabaseTest, DeleteWithId) {
179194

180195
std::vector<Person> persons;
181196

182-
persons.push_back({3, L"παναγιώτης", L"ανδριανόπουλος", 28});
183-
persons.push_back({5, L"peter", L"meier", 32});
184-
persons.push_back({13, L"mary", L"poppins", 20});
197+
persons.push_back({L"παναγιώτης", L"ανδριανόπουλος", 28, false, 3});
198+
persons.push_back({L"peter", L"meier", 32, false, 5});
199+
persons.push_back({L"mary", L"poppins", 20, false, 13});
185200

186201
db.Save(persons);
187202

@@ -210,9 +225,9 @@ TEST_F(DatabaseTest, DeleteWithPredicate) {
210225

211226
std::vector<Person> persons;
212227

213-
persons.push_back({3, L"παναγιώτης", L"ανδριανόπουλος", 28, true});
214-
persons.push_back({5, L"peter", L"meier", 32, false});
215-
persons.push_back({13, L"mary", L"poppins", 20, true});
228+
persons.push_back({L"παναγιώτης", L"ανδριανόπουλος", 28, true, 3});
229+
persons.push_back({L"peter", L"meier", 32, false, 5});
230+
persons.push_back({L"mary", L"poppins", 20, true, 13});
216231

217232
db.Save(persons);
218233

@@ -235,9 +250,9 @@ TEST_F(DatabaseTest, SingleFetch) {
235250

236251
std::vector<Person> persons;
237252

238-
persons.push_back({3, L"παναγιώτης", L"ανδριανόπουλος", 28});
239-
persons.push_back({5, L"peter", L"meier", 32});
240-
persons.push_back({13, L"mary", L"poppins", 20});
253+
persons.push_back({L"παναγιώτης", L"ανδριανόπουλος", 28, false, 3});
254+
persons.push_back({L"peter", L"meier", 32, false, 5});
255+
persons.push_back({L"mary", L"poppins", 20, false, 13});
241256

242257
db.Save(persons);
243258

@@ -253,9 +268,9 @@ TEST_F(DatabaseTest, SingleFetchWithoutExistingRecordExpectingException) {
253268

254269
std::vector<Person> persons;
255270

256-
persons.push_back({3, L"παναγιώτης", L"ανδριανόπουλος", 28});
257-
persons.push_back({5, L"peter", L"meier", 32});
258-
persons.push_back({13, L"mary", L"poppins", 20});
271+
persons.push_back({L"παναγιώτης", L"ανδριανόπουλος", 28, false, 3});
272+
persons.push_back({L"peter", L"meier", 32, false, 5});
273+
persons.push_back({L"mary", L"poppins", 20, false});
259274

260275
db.Save(persons);
261276

@@ -267,13 +282,13 @@ TEST_F(DatabaseTest, FetchWithSimilarPredicateString) {
267282

268283
std::vector<Company> company;
269284

270-
company.push_back({1, L"Paul", 32, L"California", 20000.0});
271-
company.push_back({2, L"Allen", 25, L"Texas", 15000.0});
272-
company.push_back({3, L"Teddy", 23, L"Norway", 20000.0});
273-
company.push_back({4, L"Mark", 25, L"Rich-Mond", 65000.0});
274-
company.push_back({5, L"David", 27, L"Texas", 85000.0});
275-
company.push_back({6, L"Kim", 22, L"South-Hall", 45000.0});
276-
company.push_back({7, L"Janes", 24, L"Houston", 10000.0});
285+
company.push_back({L"Paul", 32, L"California", 20000.0, 1});
286+
company.push_back({L"Allen", 25, L"Texas", 15000.0, 2});
287+
company.push_back({L"Teddy", 23, L"Norway", 20000.0, 3});
288+
company.push_back({L"Mark", 25, L"Rich-Mond", 65000.0, 4});
289+
company.push_back({L"David", 27, L"Texas", 85000.0, 5});
290+
company.push_back({L"Kim", 22, L"South-Hall", 45000.0, 6});
291+
company.push_back({L"Janes", 24, L"Houston", 10000.0, 7});
277292

278293
db.Save(company);
279294

@@ -300,13 +315,13 @@ TEST_F(DatabaseTest, FetchWithSimilarPredicateDouble) {
300315

301316
std::vector<Company> company;
302317

303-
company.push_back({1, L"Paul", 32, L"California", 20000.0});
304-
company.push_back({2, L"Allen", 25, L"Texas", 15000.0});
305-
company.push_back({3, L"Teddy", 23, L"Norway", 20000.0});
306-
company.push_back({4, L"Mark", 25, L"Rich-Mond", 65000.0});
307-
company.push_back({5, L"David", 27, L"Texas", 85000.0});
308-
company.push_back({6, L"Kim", 22, L"South-Hall", 45000.0});
309-
company.push_back({7, L"Janes", 24, L"Houston", 10000.0});
318+
company.push_back({L"Paul", 32, L"California", 20000.0, 1});
319+
company.push_back({L"Allen", 25, L"Texas", 15000.0, 2});
320+
company.push_back({L"Teddy", 23, L"Norway", 20000.0, 3});
321+
company.push_back({L"Mark", 25, L"Rich-Mond", 65000.0, 4});
322+
company.push_back({L"David", 27, L"Texas", 85000.0, 5});
323+
company.push_back({L"Kim", 22, L"South-Hall", 45000.0, 6});
324+
company.push_back({L"Janes", 24, L"Houston", 10000.0, 7});
310325

311326
db.Save(company);
312327

@@ -345,13 +360,13 @@ TEST_F(DatabaseTest, FetchWithSimilarPredicateInt) {
345360

346361
std::vector<Company> company;
347362

348-
company.push_back({1, L"Paul", 32, L"California", 20000.0});
349-
company.push_back({2, L"Allen", 25, L"Texas", 15000.0});
350-
company.push_back({3, L"Teddy", 23, L"Norway", 20000.0});
351-
company.push_back({4, L"Mark", 25, L"Rich-Mond", 65000.0});
352-
company.push_back({5, L"David", 27, L"Texas", 85000.0});
353-
company.push_back({6, L"Kim", 22, L"South-Hall", 45000.0});
354-
company.push_back({7, L"Janes", 24, L"Houston", 10000.0});
363+
company.push_back({L"Paul", 32, L"California", 20000.0, 1});
364+
company.push_back({L"Allen", 25, L"Texas", 15000.0, 2});
365+
company.push_back({L"Teddy", 23, L"Norway", 20000.0, 3});
366+
company.push_back({L"Mark", 25, L"Rich-Mond", 65000.0, 4});
367+
company.push_back({L"David", 27, L"Texas", 85000.0, 5});
368+
company.push_back({L"Kim", 22, L"South-Hall", 45000.0, 6});
369+
company.push_back({L"Janes", 24, L"Houston", 10000.0, 7});
355370

356371
db.Save(company);
357372

@@ -372,11 +387,11 @@ TEST_F(DatabaseTest, FetchWithPredicateChaining) {
372387

373388
std::vector<Person> persons;
374389

375-
persons.push_back({1, L"name1", L"surname1", 13});
376-
persons.push_back({2, L"john", L"surname2", 25});
377-
persons.push_back({3, L"john", L"surname3", 37});
378-
persons.push_back({4, L"jame", L"surname4", 45});
379-
persons.push_back({5, L"name5", L"surname5", 56});
390+
persons.push_back({L"name1", L"surname1", 13, false, 1});
391+
persons.push_back({L"john", L"surname2", 25, false, 2});
392+
persons.push_back({L"john", L"surname3", 37, false, 3});
393+
persons.push_back({L"jame", L"surname4", 45, false, 4});
394+
persons.push_back({L"name5", L"surname5", 56, false, 5});
380395

381396
db.Save(persons);
382397

@@ -403,8 +418,8 @@ TEST_F(DatabaseTest, ReadMaxId) {
403418

404419
std::vector<Person> persons;
405420

406-
persons.push_back({52, L"john", L"appleseed", 28});
407-
persons.push_back({156, L"mary", L"poppins", 20});
421+
persons.push_back({L"john", L"appleseed", 28, false, 54});
422+
persons.push_back({L"mary", L"poppins", 20, false, 156});
408423

409424
db.Save(persons);
410425

@@ -420,8 +435,8 @@ TEST_F(DatabaseTest, RawSqlQueryForPersistedRecord) {
420435

421436
std::vector<Person> persons;
422437

423-
persons.push_back({52, L"johnie", L"appleseed", 28});
424-
persons.push_back({156, L"mary", L"poppins", 20});
438+
persons.push_back({L"johnie", L"appleseed", 28, false, 52});
439+
persons.push_back({L"mary", L"poppins", 20, false, 156});
425440

426441
db.Save(persons);
427442
db.Sql("DELETE FROM Person WHERE length(first_name) <= 4");

0 commit comments

Comments
 (0)