Skip to content

Commit ac860bc

Browse files
authored
Merge pull request #361 from fnc12/feature/dynamic-order-by
added dynamic order by
2 parents d74604e + 67e5f2c commit ac860bc

File tree

10 files changed

+547
-261
lines changed

10 files changed

+547
-261
lines changed

dev/conditions.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <string> // std::string
44
#include <type_traits> // std::enable_if, std::is_same
5+
#include <vector> // std::vector
56

67
#include "collate_argument.h"
78
#include "constraints.h"
@@ -502,6 +503,49 @@ namespace sqlite_orm {
502503
multi_order_by_t(args_type &&args_) : args(std::move(args_)) {}
503504
};
504505

506+
/**
507+
* S - storage class
508+
*/
509+
template<class S>
510+
struct dynamic_order_by_t : order_by_string {
511+
using storage_type = S;
512+
513+
struct entry_t : order_by_base {
514+
std::string name;
515+
516+
entry_t(decltype(name) name_, int asc_desc, std::string collate_argument) :
517+
order_by_base{asc_desc, move(collate_argument)},
518+
name(move(name_))
519+
{}
520+
};
521+
522+
using const_iterator = typename std::vector<entry_t>::const_iterator;
523+
524+
dynamic_order_by_t(const storage_type &storage_): storage(storage_) {}
525+
526+
template<class O>
527+
void push_back(order_by_t<O> order_by) {
528+
auto columnName = this->storage.string_from_expression(order_by.o, true);
529+
entries.emplace_back(move(columnName), order_by.asc_desc, move(order_by._collate_argument));
530+
}
531+
532+
const_iterator begin() const {
533+
return this->entries.begin();
534+
}
535+
536+
const_iterator end() const {
537+
return this->entries.end();
538+
}
539+
540+
void clear() {
541+
this->entries.clear();
542+
}
543+
544+
protected:
545+
std::vector<entry_t> entries;
546+
const storage_type &storage;
547+
};
548+
505549
struct group_by_string {
506550
operator std::string() const {
507551
return "GROUP BY";
@@ -1110,6 +1154,11 @@ namespace sqlite_orm {
11101154
return {std::make_tuple(std::forward<Args>(args)...)};
11111155
}
11121156

1157+
template<class S>
1158+
conditions::dynamic_order_by_t<S> dynamic_order_by(const S &storage) {
1159+
return {storage};
1160+
}
1161+
11131162
template<class ...Args>
11141163
conditions::group_by_t<Args...> group_by(Args&& ...args) {
11151164
return {std::make_tuple(std::forward<Args>(args)...)};

dev/storage.h

Lines changed: 114 additions & 100 deletions
Large diffs are not rendered by default.

dev/storage_base.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,41 @@ namespace sqlite_orm {
458458
}
459459
}
460460

461+
template<class S>
462+
std::string process_order_by(const conditions::dynamic_order_by_t<S> &orderBy) const {
463+
std::vector<std::string> expressions;
464+
for(auto &entry : orderBy){
465+
std::string entryString;
466+
{
467+
std::stringstream ss;
468+
ss << entry.name << " ";
469+
if(!entry._collate_argument.empty()){
470+
ss << "COLLATE " << entry._collate_argument << " ";
471+
}
472+
switch(entry.asc_desc){
473+
case 1:
474+
ss << "ASC";
475+
break;
476+
case -1:
477+
ss << "DESC";
478+
break;
479+
}
480+
entryString = ss.str();
481+
}
482+
expressions.push_back(move(entryString));
483+
};
484+
std::stringstream ss;
485+
ss << static_cast<std::string>(orderBy) << " ";
486+
for(size_t i = 0; i < expressions.size(); ++i) {
487+
ss << expressions[i];
488+
if(i < expressions.size() - 1) {
489+
ss << ", ";
490+
}
491+
}
492+
ss << " ";
493+
return ss.str();
494+
}
495+
461496
static int collate_callback(void *arg, int leftLen, const void *lhs, int rightLen, const void *rhs) {
462497
auto &f = *(collating_function*)arg;
463498
return f(leftLen, lhs, rightLen, rhs);

dev/storage_impl.h

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -186,23 +186,23 @@ namespace sqlite_orm {
186186
* `column_name` has SFINAE check for type equality but `column_name_simple` has not.
187187
*/
188188
template<class O, class F>
189-
std::string column_name_simple(F O::*m) {
189+
std::string column_name_simple(F O::*m) const {
190190
return this->table.find_column_name(m);
191191
}
192192

193193
/**
194194
* Same thing as above for getter.
195195
*/
196196
template<class T, typename std::enable_if<is_getter<T>::value>::type>
197-
std::string column_name_simple(T g) {
197+
std::string column_name_simple(T g) const {
198198
return this->table.find_column_name(g);
199199
}
200200

201201
/**
202202
* Same thing as above for setter.
203203
*/
204204
template<class T, typename std::enable_if<is_setter<T>::value>::type>
205-
std::string column_name_simple(T s) {
205+
std::string column_name_simple(T s) const {
206206
return this->table.find_column_name(s);
207207
}
208208

@@ -211,15 +211,15 @@ namespace sqlite_orm {
211211
* skip inequal type O.
212212
*/
213213
template<class O, class F, class HH = typename H::object_type>
214-
std::string column_name(F O::*m, typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) {
214+
std::string column_name(F O::*m, typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) const {
215215
return this->table.find_column_name(m);
216216
}
217217

218218
/**
219219
* Opposite version of function defined above. Just calls same function in superclass.
220220
*/
221221
template<class O, class F, class HH = typename H::object_type>
222-
std::string column_name(F O::*m, typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) {
222+
std::string column_name(F O::*m, typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) const {
223223
return this->super::column_name(m);
224224
}
225225

@@ -228,15 +228,15 @@ namespace sqlite_orm {
228228
* skip inequal type O.
229229
*/
230230
template<class O, class F, class HH = typename H::object_type>
231-
std::string column_name(const F& (O::*g)() const, typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) {
231+
std::string column_name(const F& (O::*g)() const, typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) const {
232232
return this->table.find_column_name(g);
233233
}
234234

235235
/**
236236
* Opposite version of function defined above. Just calls same function in superclass.
237237
*/
238238
template<class O, class F, class HH = typename H::object_type>
239-
std::string column_name(const F& (O::*g)() const, typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) {
239+
std::string column_name(const F& (O::*g)() const, typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) const {
240240
return this->super::column_name(g);
241241
}
242242

@@ -245,35 +245,35 @@ namespace sqlite_orm {
245245
* skip inequal type O.
246246
*/
247247
template<class O, class F, class HH = typename H::object_type>
248-
std::string column_name(void (O::*s)(F), typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) {
248+
std::string column_name(void (O::*s)(F), typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) const {
249249
return this->table.find_column_name(s);
250250
}
251251

252252
/**
253253
* Opposite version of function defined above. Just calls same function in superclass.
254254
*/
255255
template<class O, class F, class HH = typename H::object_type>
256-
std::string column_name(void (O::*s)(F), typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) {
256+
std::string column_name(void (O::*s)(F), typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) const {
257257
return this->super::column_name(s);
258258
}
259259

260260
template<class T, class F, class HH = typename H::object_type>
261-
std::string column_name(const column_pointer<T, F> &c, typename std::enable_if<std::is_same<T, HH>::value>::type * = nullptr) {
261+
std::string column_name(const column_pointer<T, F> &c, typename std::enable_if<std::is_same<T, HH>::value>::type * = nullptr) const {
262262
return this->column_name_simple(c.field);
263263
}
264264

265265
template<class T, class F, class HH = typename H::object_type>
266-
std::string column_name(const column_pointer<T, F> &c, typename std::enable_if<!std::is_same<T, HH>::value>::type * = nullptr) {
266+
std::string column_name(const column_pointer<T, F> &c, typename std::enable_if<!std::is_same<T, HH>::value>::type * = nullptr) const {
267267
return this->super::column_name(c);
268268
}
269269

270270
template<class O, class HH = typename H::object_type>
271-
auto& get_impl(typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) {
271+
auto& get_impl(typename std::enable_if<std::is_same<O, HH>::value>::type * = nullptr) const {
272272
return *this;
273273
}
274274

275275
template<class O, class HH = typename H::object_type>
276-
auto& get_impl(typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) {
276+
auto& get_impl(typename std::enable_if<!std::is_same<O, HH>::value>::type * = nullptr) const {
277277
return this->super::template get_impl<O>();
278278
}
279279

dev/table.h

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ namespace sqlite_orm {
5353
* Function used to get field value from object by mapped member pointer/setter/getter
5454
*/
5555
template<class F, class C>
56-
const F* get_object_field_pointer(const object_type &obj, C c) {
56+
const F* get_object_field_pointer(const object_type &obj, C c) const {
5757
const F *res = nullptr;
5858
this->for_each_column_with_field_type<F>([&res, &c, &obj](auto &col){
5959
using column_type = typename std::remove_reference<decltype(col)>::type;
@@ -90,7 +90,7 @@ namespace sqlite_orm {
9090
/**
9191
* @return vector of column names of table.
9292
*/
93-
std::vector<std::string> column_names() {
93+
std::vector<std::string> column_names() const {
9494
std::vector<std::string> res;
9595
this->for_each_column([&res](auto &c){
9696
res.push_back(c.name);
@@ -102,22 +102,22 @@ namespace sqlite_orm {
102102
* Calls **l** with every primary key dedicated constraint
103103
*/
104104
template<class L>
105-
void for_each_primary_key(const L &l) {
105+
void for_each_primary_key(const L &l) const {
106106
iterate_tuple(this->columns, [&l](auto &column){
107107
using column_type = typename std::decay<decltype(column)>::type;
108108
static_if<internal::is_primary_key<column_type>{}>(l)(column);
109109
});
110110
}
111111

112-
std::vector<std::string> composite_key_columns_names() {
112+
std::vector<std::string> composite_key_columns_names() const {
113113
std::vector<std::string> res;
114114
this->for_each_primary_key([this, &res](auto &c){
115115
res = this->composite_key_columns_names(c);
116116
});
117117
return res;
118118
}
119119

120-
std::vector<std::string> primary_key_column_names() {
120+
std::vector<std::string> primary_key_column_names() const {
121121
std::vector<std::string> res;
122122
this->for_each_column_with<constraints::primary_key_t<>>([&res](auto &c){
123123
res.push_back(c.name);
@@ -129,7 +129,7 @@ namespace sqlite_orm {
129129
}
130130

131131
template<class ...Args>
132-
std::vector<std::string> composite_key_columns_names(const constraints::primary_key_t<Args...> &pk) {
132+
std::vector<std::string> composite_key_columns_names(const constraints::primary_key_t<Args...> &pk) const {
133133
std::vector<std::string> res;
134134
using pk_columns_tuple = decltype(pk.columns);
135135
res.reserve(std::tuple_size<pk_columns_tuple>::value);
@@ -147,7 +147,7 @@ namespace sqlite_orm {
147147
class F,
148148
class O,
149149
typename = typename std::enable_if<std::is_member_pointer<F O::*>::value && !std::is_member_function_pointer<F O::*>::value>::type>
150-
std::string find_column_name(F O::*m) {
150+
std::string find_column_name(F O::*m) const {
151151
std::string res;
152152
this->template for_each_column_with_field_type<F>([&res, m](auto c) {
153153
if(c.member_pointer == m) {
@@ -162,7 +162,7 @@ namespace sqlite_orm {
162162
* @return column name or empty string if nothing found.
163163
*/
164164
template<class G>
165-
std::string find_column_name(G getter, typename std::enable_if<is_getter<G>::value>::type * = nullptr) {
165+
std::string find_column_name(G getter, typename std::enable_if<is_getter<G>::value>::type * = nullptr) const {
166166
std::string res;
167167
using field_type = typename getter_traits<G>::field_type;
168168
this->template for_each_column_with_field_type<field_type>([&res, getter](auto c) {
@@ -178,7 +178,7 @@ namespace sqlite_orm {
178178
* @return column name or empty string if nothing found.
179179
*/
180180
template<class S>
181-
std::string find_column_name(S setter, typename std::enable_if<is_setter<S>::value>::type * = nullptr) {
181+
std::string find_column_name(S setter, typename std::enable_if<is_setter<S>::value>::type * = nullptr) const {
182182
std::string res;
183183
using field_type = typename setter_traits<S>::field_type;
184184
this->template for_each_column_with_field_type<field_type>([&res, setter](auto c) {
@@ -211,20 +211,20 @@ namespace sqlite_orm {
211211
* @param l Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {}
212212
*/
213213
template<class L>
214-
void for_each_column(const L &l) {
214+
void for_each_column(const L &l) const {
215215
iterate_tuple(this->columns, [&l](auto &column){
216216
using column_type = typename std::decay<decltype(column)>::type;
217217
static_if<internal::is_column<column_type>{}>(l)(column);
218218
});
219219
}
220220

221221
template<class L>
222-
void for_each_column_with_constraints(const L &l) {
222+
void for_each_column_with_constraints(const L &l) const {
223223
iterate_tuple(this->columns, l);
224224
}
225225

226226
template<class F, class L>
227-
void for_each_column_with_field_type(const L &l) {
227+
void for_each_column_with_field_type(const L &l) const {
228228
iterate_tuple(this->columns, [&l](auto &column){
229229
using column_type = typename std::decay<decltype(column)>::type;
230230
static_if<std::is_same<F, typename column_type::field_type>{}>(l)(column);
@@ -238,7 +238,7 @@ namespace sqlite_orm {
238238
* @param l Lambda to be called per column itself. Must have signature like this [] (auto col) -> void {}
239239
*/
240240
template<class Op, class L>
241-
void for_each_column_with(const L &l) {
241+
void for_each_column_with(const L &l) const {
242242
using tuple_helper::tuple_contains_type;
243243
iterate_tuple(this->columns, [&l](auto &column){
244244
using column_type = typename std::decay<decltype(column)>::type;

0 commit comments

Comments
 (0)