LeechCraft  0.6.70-18450-gabe19ee3b0
Modular cross-platform feature rich live environment.
oraltest_simplerecord.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * LeechCraft - modular cross-platform feature rich internet client.
3  * Copyright (C) 2006-2014 Georg Rudoy
4  *
5  * Distributed under the Boost Software License, Version 1.0.
6  * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7  **********************************************************************/
8 
10 #include "common.h"
11 #include "simplerecord.h"
12 
13 QTEST_GUILESS_MAIN (LC::Util::OralTest_SimpleRecord)
14 
15 using LC::operator""_ct;
16 
17 // Models the pagination scenario: messages with a timestamp (TS) and an
18 // auto-generated primary key (Id) that don't necessarily correlate.
19 // After history sync, a message from the past gets a high Id.
21 {
23  int TS_;
24  QString Body_;
25 
26  constexpr static auto ClassName = "MessageLikeRecord"_ct;
27 
28  auto AsTuple () const
29  {
30  return std::tuple (Id_, TS_, Body_);
31  }
32 };
33 
35  Id_,
36  TS_,
37  Body_)
38 
40 
41 namespace LC
42 {
43 namespace Util
44 {
45  namespace sph = oral::sph;
46 
47  void OralTest_SimpleRecord::testSimpleRecordInsertSelect ()
48  {
49  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
50  const auto& list = adapted->Select ();
51  QCOMPARE (list, (QList<SimpleRecord> { { 0, "0" }, { 1, "1" }, { 2, "2" } }));
52  }
53 
54  void OralTest_SimpleRecord::testSimpleRecordInsertReplaceSelect ()
55  {
56  auto db = MakeDatabase ();
57 
58  auto adapted = Util::oral::AdaptPtr<SimpleRecord, OralFactory> (db);
59  for (int i = 0; i < 3; ++i)
60  adapted->Insert (OralFactory {}, { 0, QString::number (i) }, lco::InsertAction::Replace::Whole);
61 
62  const auto& list = adapted->Select ();
63  QCOMPARE (list, (QList<SimpleRecord> { { 0, "2" } }));
64  }
65 
66  void OralTest_SimpleRecord::testSimpleRecordInsertIgnoreSelect ()
67  {
68  auto db = MakeDatabase ();
69 
70  auto adapted = Util::oral::AdaptPtr<SimpleRecord, OralFactory> (db);
71  for (int i = 0; i < 3; ++i)
72  adapted->Insert (OralFactory {}, { 0, QString::number (i) }, lco::InsertAction::Ignore);
73 
74  const auto& list = adapted->Select ();
75  QCOMPARE (list, (QList<SimpleRecord> { { 0, "0" } }));
76  }
77 
78  void OralTest_SimpleRecord::testSimpleRecordInsertSelectByPos ()
79  {
80  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
81  const auto& list = adapted->Select (sph::f<&SimpleRecord::ID_> == 1);
82  QCOMPARE (list, (QList<SimpleRecord> { { 1, "1" } }));
83  }
84 
85  void OralTest_SimpleRecord::testSimpleRecordInsertSelectByPos2 ()
86  {
87  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
88  const auto& list = adapted->Select (sph::f<&SimpleRecord::ID_> < 2);
89  QCOMPARE (list, (QList<SimpleRecord> { { 0, "0" }, { 1, "1" } }));
90  }
91 
92  void OralTest_SimpleRecord::testSimpleRecordInsertSelectByPos3 ()
93  {
94  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
95  const auto& list = adapted->Select (sph::f<&SimpleRecord::ID_> < 2 && sph::f<&SimpleRecord::Value_> == QString { "1" });
96  QCOMPARE (list, (QList<SimpleRecord> { { 1, "1" } }));
97  }
98 
99  void OralTest_SimpleRecord::testSimpleRecordInsertSelectOneByPos ()
100  {
101  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
102  const auto& single = adapted->SelectOne (sph::f<&SimpleRecord::ID_> == 1);
103  QCOMPARE (single, (std::optional<SimpleRecord> { { 1, "1" } }));
104  }
105 
106  void OralTest_SimpleRecord::testSimpleRecordInsertSelectByFields ()
107  {
108  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
109  const auto& list = adapted->Select (sph::f<&SimpleRecord::ID_> == 1);
110  QCOMPARE (list, (QList<SimpleRecord> { { 1, "1" } }));
111  }
112 
113  void OralTest_SimpleRecord::testSimpleRecordInsertSelectByFields2 ()
114  {
115  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
116  const auto& list = adapted->Select (sph::f<&SimpleRecord::ID_> < 2);
117  QCOMPARE (list, (QList<SimpleRecord> { { 0, "0" }, { 1, "1" } }));
118  }
119 
120  void OralTest_SimpleRecord::testSimpleRecordInsertSelectByFields3 ()
121  {
122  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
123  const auto& list = adapted->Select (sph::f<&SimpleRecord::ID_> < 2 && sph::f<&SimpleRecord::Value_> == QString { "1" });
124  QCOMPARE (list, (QList<SimpleRecord> { { 1, "1" } }));
125  }
126 
127  void OralTest_SimpleRecord::testSimpleRecordInsertSelectOneByFields ()
128  {
129  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
130  const auto& single = adapted->SelectOne (sph::f<&SimpleRecord::ID_> == 1);
131  QCOMPARE (single, (std::optional<SimpleRecord> { { 1, "1" } }));
132  }
133 
134  void OralTest_SimpleRecord::testSimpleRecordInsertSelectSingleFieldByFields ()
135  {
136  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
137  const auto& list = adapted->Select (sph::fields<&SimpleRecord::Value_>, sph::f<&SimpleRecord::ID_> < 2);
138  QCOMPARE (list, (QList<QString> { "0", "1" }));
139  }
140 
141  void OralTest_SimpleRecord::testSimpleRecordInsertSelectFieldsByFields ()
142  {
143  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
144  const auto& list = adapted->Select (sph::fields<&SimpleRecord::ID_, &SimpleRecord::Value_>, sph::f<&SimpleRecord::ID_> < 2);
145  QCOMPARE (list, (QList<std::tuple<int, QString>> { { 0, "0" }, { 1, "1" } }));
146  }
147 
148  void OralTest_SimpleRecord::testSimpleRecordInsertSelectFieldsByFieldsOrderAsc ()
149  {
150  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
151  const auto& list = adapted->Select (sph::fields<&SimpleRecord::ID_, &SimpleRecord::Value_>,
152  sph::f<&SimpleRecord::ID_> < 2,
153  oral::OrderBy<sph::asc<&SimpleRecord::Value_>>);
154  QCOMPARE (list, (QList<std::tuple<int, QString>> { { 0, "0" }, { 1, "1" } }));
155  }
156 
157  void OralTest_SimpleRecord::testSimpleRecordInsertSelectFieldsByFieldsOrderDesc ()
158  {
159  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
160  const auto& list = adapted->Select (sph::fields<&SimpleRecord::ID_, &SimpleRecord::Value_>,
161  sph::f<&SimpleRecord::ID_> < 2,
162  oral::OrderBy<sph::desc<&SimpleRecord::Value_>>);
163  QCOMPARE (list, (QList<std::tuple<int, QString>> { { 1, "1" }, { 0, "0" } }));
164  }
165 
166  void OralTest_SimpleRecord::testSimpleRecordInsertSelectFieldsByFieldsOrderManyAsc ()
167  {
168  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
169  const auto& list = adapted->Select (sph::fields<&SimpleRecord::ID_, &SimpleRecord::Value_>,
170  sph::f<&SimpleRecord::ID_> < 2,
171  oral::OrderBy<sph::asc<&SimpleRecord::Value_>, sph::desc<&SimpleRecord::ID_>>);
172  QCOMPARE (list, (QList<std::tuple<int, QString>> { { 0, "0" }, { 1, "1" } }));
173  }
174 
175  void OralTest_SimpleRecord::testSimpleRecordInsertSelectFieldsByFieldsOrderManyDesc ()
176  {
177  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
178  const auto& list = adapted->Select (sph::fields<&SimpleRecord::ID_, &SimpleRecord::Value_>,
179  sph::f<&SimpleRecord::ID_> < 2,
180  oral::OrderBy<sph::desc<&SimpleRecord::Value_>, sph::asc<&SimpleRecord::ID_>>);
181  QCOMPARE (list, (QList<std::tuple<int, QString>> { { 1, "1" }, { 0, "0" } }));
182  }
183 
184  void OralTest_SimpleRecord::testSimpleRecordInsertSelectNoOffsetLimit ()
185  {
186  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase (), 10);
187  const auto& list = adapted->Select.Build ().Limit (2) ();
188  QCOMPARE (list, (QList<SimpleRecord> { { 0, "0" }, { 1, "1" } }));
189  }
190 
191  /*
192  void OralTest_SimpleRecord::testSimpleRecordInsertSelectOffsetNoLimit ()
193  {
194  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase (), 10);
195  const auto& list = adapted->Select.Build ().Offset ({ 8 }) ();
196  QCOMPARE (list, (QList<SimpleRecord> { { 8, "8" }, { 9, "9" } }));
197  }
198  */
199 
200  void OralTest_SimpleRecord::testSimpleRecordInsertSelectOffsetLimit ()
201  {
202  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase (), 10);
203  const auto& list = adapted->Select.Build ().Offset (5).Limit (2) ();
204  QCOMPARE (list, (QList<SimpleRecord> { { 5, "5" }, { 6, "6" } }));
205  }
206 
207  void OralTest_SimpleRecord::testSimpleRecordInsertSelectBuilderAndWhere ()
208  {
209  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
210  const auto& list = adapted->Select.Build ()
211  .Where (sph::f<&SimpleRecord::ID_> < 2)
212  .AndWhere (sph::f<&SimpleRecord::Value_> == QString { "1" })
213  ();
214  QCOMPARE (list, (QList<SimpleRecord> { { 1, "1" } }));
215  }
216 
217  void OralTest_SimpleRecord::testSimpleRecordInsertSelectBuilderAndWhereMultiple ()
218  {
219  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase (), 10);
220  const auto& list = adapted->Select.Build ()
221  .Where (sph::f<&SimpleRecord::ID_> < 8)
222  .AndWhere (sph::f<&SimpleRecord::ID_> >= 2)
223  .AndWhere (sph::f<&SimpleRecord::Value_> == QString { "5" })
224  ();
225  QCOMPARE (list, (QList<SimpleRecord> { { 5, "5" } }));
226  }
227 
228  void OralTest_SimpleRecord::testSimpleRecordInsertSelectCount ()
229  {
230  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
231  const auto count = adapted->Select (sph::count<>);
232  QCOMPARE (count, 3);
233  }
234 
235  void OralTest_SimpleRecord::testSimpleRecordInsertSelectCountByFields ()
236  {
237  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
238  const auto count = adapted->Select (sph::count<>, sph::f<&SimpleRecord::ID_> < 2);
239  QCOMPARE (count, 2);
240  }
241 
242  void OralTest_SimpleRecord::testSimpleRecordInsertSelectMin ()
243  {
244  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
245  const auto min = adapted->Select (sph::min<&SimpleRecord::ID_>);
246  QCOMPARE (min, 0);
247  }
248 
249  void OralTest_SimpleRecord::testSimpleRecordInsertSelectMax ()
250  {
251  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
252  const auto max = adapted->Select (sph::max<&SimpleRecord::ID_>);
253  QCOMPARE (max, 2);
254  }
255 
256  void OralTest_SimpleRecord::testSimpleRecordInsertSelectMinPlusMax ()
257  {
258  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
259  const auto minMax = adapted->Select (sph::min<&SimpleRecord::ID_> + sph::max<&SimpleRecord::ID_>);
260  QCOMPARE (minMax, (std::tuple { 0, 2 }));
261  }
262 
263  void OralTest_SimpleRecord::testSimpleRecordInsertSelectMinPlusMaxEmpty ()
264  {
265  auto adapted = oral::AdaptPtr<SimpleRecord, OralFactory> (MakeDatabase ());
266  const auto minMax = adapted->Select (sph::min<&SimpleRecord::ID_> + sph::max<&SimpleRecord::ID_>);
267  QCOMPARE (minMax, (std::tuple { std::nullopt, std::nullopt }));
268  }
269 
270  void OralTest_SimpleRecord::testSimpleRecordInsertSelectValuePlusMinPlusMax ()
271  {
272  auto adapted = oral::AdaptPtr<SimpleRecord, OralFactory> (MakeDatabase ());
273  for (int i = 0; i < 3; ++i)
274  adapted->Insert ({ i, "0" });
275  for (int i = 3; i < 6; ++i)
276  adapted->Insert ({ i, "1" });
277 
278  const auto allMinMax = adapted->Select.Build ()
279  .Select (sph::fields<&SimpleRecord::Value_> + sph::min<&SimpleRecord::ID_> + sph::max<&SimpleRecord::ID_>)
280  .Group (oral::GroupBy<&SimpleRecord::Value_>)
281  ();
282  QCOMPARE (allMinMax, (QList<std::tuple<QString, std::optional<int>, std::optional<int>>>
283  {
284  { { "0" }, 0, 2 },
285  { { "1" }, 3, 5 }
286  }));
287  }
288 
289  void OralTest_SimpleRecord::testSimpleRecordInsertSelectAllPlusMinPlusMax ()
290  {
291  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase (), 2);
292  const auto allMinMax = adapted->Select.Build ()
293  .Select (sph::all + sph::min<&SimpleRecord::ID_> + sph::max<&SimpleRecord::ID_>)
295  ();
296  QCOMPARE (allMinMax, (QList<std::tuple<SimpleRecord, std::optional<int>, std::optional<int>>>
297  {
298  { { 0, "0" }, 0, 0 }, { { 1, "1" }, 1, 1 }
299  }));
300  }
301 
302  void OralTest_SimpleRecord::testSimpleRecordInsertSelectLike ()
303  {
304  using namespace oral::infix;
305 
306  auto adapted = Util::oral::AdaptPtr<SimpleRecord, OralFactory> (MakeDatabase ());
307  adapted->Insert ({ 0, "foo" });
308  adapted->Insert ({ 1, "bar" });
309  adapted->Insert ({ 2, "foobar" });
310  const auto& list = adapted->Select (sph::f<&SimpleRecord::Value_> |like| QString { "%oo%" });
311  QCOMPARE (list, (QList<SimpleRecord> { { 0, "foo" }, { 2, "foobar" } }));
312  }
313 
314  void OralTest_SimpleRecord::testSimpleRecordUpdate ()
315  {
316  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
317  adapted->Update ({ 0, "meh" });
318  const auto updated = adapted->Select (sph::f<&SimpleRecord::ID_> == 0);
319  QCOMPARE (updated, (QList<SimpleRecord> { { 0, "meh" } }));
320  }
321 
322  void OralTest_SimpleRecord::testSimpleRecordUpdateExprTree ()
323  {
324  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
325  adapted->Update (sph::f<&SimpleRecord::Value_> = QString { "meh" }, sph::f<&SimpleRecord::ID_> == 0);
326  const auto updated = adapted->Select (sph::f<&SimpleRecord::ID_> == 0);
327  QCOMPARE (updated, (QList<SimpleRecord> { { 0, "meh" } }));
328  }
329 
330  void OralTest_SimpleRecord::testSimpleRecordUpdateMultiExprTree ()
331  {
332  auto adapted = PrepareRecords<SimpleRecord> (MakeDatabase ());
333  adapted->Update ((sph::f<&SimpleRecord::Value_> = QString { "meh" }, sph::f<&SimpleRecord::ID_> = 10),
334  sph::f<&SimpleRecord::ID_> == 0);
335  const auto updated = adapted->Select (sph::f<&SimpleRecord::ID_> == 10);
336  QCOMPARE (updated, (QList<SimpleRecord> { { 10, "meh" } }));
337  }
338 
339  auto PrepareMessageLikeRecords (QSqlDatabase db)
340  {
341  using Rec = MessageLikeRecord;
342  auto adapted = oral::AdaptPtr<Rec, OralFactory> (db);
343  adapted->Insert ({ {}, 300, "c" });
344  adapted->Insert ({ {}, 400, "d" });
345  adapted->Insert ({ {}, 500, "e" });
346  adapted->Insert ({ {}, 100, "a" });
347  adapted->Insert ({ {}, 200, "b" });
348  return adapted;
349  }
350 
351  void OralTest_SimpleRecord::testTupleCompareEq ()
352  {
353  using Rec = MessageLikeRecord;
354  auto adapted = PrepareMessageLikeRecords (MakeDatabase ());
355  const auto& list = adapted->Select (sph::tuple<&Rec::TS_, &Rec::Id_> == std::tuple (300, 1));
356  QCOMPARE (list, (QList<Rec> { { 1, 300, "c" } }));
357  }
358 
359  void OralTest_SimpleRecord::testTupleCompareLt ()
360  {
361  using Rec = MessageLikeRecord;
362  auto adapted = PrepareMessageLikeRecords (MakeDatabase ());
363  const auto& list = adapted->Select.Build ()
364  .Where (sph::tuple<&Rec::TS_, &Rec::Id_> < std::tuple (300, 1))
365  .Order (oral::OrderBy<sph::asc<&Rec::TS_>, sph::asc<&Rec::Id_>>)
366  ();
367  QCOMPARE (list, (QList<Rec> { { 4, 100, "a" }, { 5, 200, "b" } }));
368  }
369 
370  void OralTest_SimpleRecord::testTupleCompareGt ()
371  {
372  using Rec = MessageLikeRecord;
373  auto adapted = PrepareMessageLikeRecords (MakeDatabase ());
374  const auto& list = adapted->Select.Build ()
375  .Where (sph::tuple<&Rec::TS_, &Rec::Id_> > std::tuple (300, 1))
376  .Order (oral::OrderBy<sph::asc<&Rec::TS_>, sph::asc<&Rec::Id_>>)
377  ();
378  QCOMPARE (list, (QList<Rec> { { 2, 400, "d" }, { 3, 500, "e" } }));
379  }
380 
381  void OralTest_SimpleRecord::testTupleCompareLte ()
382  {
383  using Rec = MessageLikeRecord;
384  auto adapted = PrepareMessageLikeRecords (MakeDatabase ());
385  const auto& list = adapted->Select.Build ()
386  .Where (sph::tuple<&Rec::TS_, &Rec::Id_> <= std::tuple (300, 1))
387  .Order (oral::OrderBy<sph::asc<&Rec::TS_>, sph::asc<&Rec::Id_>>)
388  ();
389  QCOMPARE (list, (QList<Rec> { { 4, 100, "a" }, { 5, 200, "b" }, { 1, 300, "c" } }));
390  }
391 
392  void OralTest_SimpleRecord::testTupleCompareGte ()
393  {
394  using Rec = MessageLikeRecord;
395  auto adapted = PrepareMessageLikeRecords (MakeDatabase ());
396  const auto& list = adapted->Select.Build ()
397  .Where (sph::tuple<&Rec::TS_, &Rec::Id_> >= std::tuple (300, 1))
398  .Order (oral::OrderBy<sph::asc<&Rec::TS_>, sph::asc<&Rec::Id_>>)
399  ();
400  QCOMPARE (list, (QList<Rec> { { 1, 300, "c" }, { 2, 400, "d" }, { 3, 500, "e" } }));
401  }
402 
403  void OralTest_SimpleRecord::testTupleCompareIsNotComponentwise ()
404  {
405  using Rec = MessageLikeRecord;
406  auto adapted = PrepareMessageLikeRecords (MakeDatabase ());
407  const auto& before = adapted->Select (sph::tuple<&Rec::TS_, &Rec::Id_> < std::tuple (200, 5));
408  QCOMPARE (before, (QList<Rec> { { 4, 100, "a" } }));
409 
410  const auto& after = adapted->Select.Build ()
411  .Where (sph::tuple<&Rec::TS_, &Rec::Id_> > std::tuple (200, 5))
412  .Order (oral::OrderBy<sph::asc<&Rec::TS_>, sph::asc<&Rec::Id_>>)
413  ();
414  QCOMPARE (after, (QList<Rec> { { 1, 300, "c" }, { 2, 400, "d" }, { 3, 500, "e" } }));
415  }
416 
417  void OralTest_SimpleRecord::testTupleCompareInBuilder ()
418  {
419  using Rec = MessageLikeRecord;
420  auto adapted = PrepareMessageLikeRecords (MakeDatabase ());
421  auto page = adapted->Select.Build ()
422  .Where (sph::tuple<&Rec::TS_, &Rec::Id_> < std::tuple (400, 2))
423  .Order (oral::OrderBy<sph::desc<&Rec::TS_>, sph::desc<&Rec::Id_>>)
424  .Limit (2)
425  ();
426  QCOMPARE (page, (QList<Rec> { { 1, 300, "c" }, { 5, 200, "b" } }));
427  }
428 }
429 }
lco::PKey< int, lco::NoAutogen > ID_
Definition: simplerecord.h:17
constexpr detail::AggregateType< detail::AggregateFunction::Count, Ptr > count
Definition: oral.h:1104
constexpr detail::OrderBy< Orders... > OrderBy
Definition: oral.h:1117
constexpr detail::AggregateType< detail::AggregateFunction::Max, Ptr > max
Definition: oral.h:1110
static constexpr struct LC::Util::oral::InsertAction::IgnoreTag Ignore
QString Value_
Definition: simplerecord.h:18
QSqlDatabase MakeDatabase(const QString &name=":memory:")
Definition: common.h:56
constexpr detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, detail::MemberPtrs< Ptrs... > > tuple
Definition: oral.h:1086
ORAL_ADAPT_STRUCT(MessageLikeRecord, Id_, TS_, Body_) namespace LC
static constexpr auto ClassName
constexpr detail::InfixBinary< detail::ExprType::Like > like
Definition: oral.h:969
constexpr detail::AggregateType< detail::AggregateFunction::Min, Ptr > min
Definition: oral.h:1107
constexpr detail::SelectWhole all
Definition: oral.h:1091
#define TOSTRING(n)
Definition: common.h:35