summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/binding.h14
-rw-r--r--lib/database.cpp14
-rw-r--r--lib/database.h18
-rw-r--r--lib/enums.h10
-rw-r--r--lib/field.cpp34
-rw-r--r--lib/lemma.cpp34
-rw-r--r--lib/lemma.h78
-rw-r--r--lib/pronunciation.cpp34
-rw-r--r--lib/query.h48
-rw-r--r--lib/role.h24
-rw-r--r--lib/selrestr.cpp102
-rw-r--r--lib/selrestr.h56
-rw-r--r--lib/statement.cpp290
-rw-r--r--lib/statement.h130
-rw-r--r--lib/util.h22
-rw-r--r--lib/word.cpp56
-rw-r--r--lib/word.h100
17 files changed, 532 insertions, 532 deletions
diff --git a/lib/binding.h b/lib/binding.h index 7fbe20e..5578a09 100644 --- a/lib/binding.h +++ b/lib/binding.h
@@ -12,9 +12,9 @@ namespace verbly {
12 integer, 12 integer,
13 string 13 string
14 }; 14 };
15 15
16 // Default constructor 16 // Default constructor
17 17
18 binding() 18 binding()
19 { 19 {
20 } 20 }
@@ -37,22 +37,22 @@ namespace verbly {
37 ~binding(); 37 ~binding();
38 38
39 // Generic accessors 39 // Generic accessors
40 40
41 type getType() const 41 type getType() const
42 { 42 {
43 return type_; 43 return type_;
44 } 44 }
45 45
46 // Integer 46 // Integer
47 47
48 binding(int arg); 48 binding(int arg);
49 49
50 int getInteger() const; 50 int getInteger() const;
51 51
52 // String 52 // String
53 53
54 binding(std::string arg); 54 binding(std::string arg);
55 55
56 std::string getString() const; 56 std::string getString() const;
57 57
58 private: 58 private:
diff --git a/lib/database.cpp b/lib/database.cpp index 351b93d..fb00ef3 100644 --- a/lib/database.cpp +++ b/lib/database.cpp
@@ -40,37 +40,37 @@ namespace verbly {
40 { 40 {
41 sqlite3_close_v2(ppdb_); 41 sqlite3_close_v2(ppdb_);
42 } 42 }
43 43
44 query<notion> database::notions(filter where, bool random, int limit) const 44 query<notion> database::notions(filter where, bool random, int limit) const
45 { 45 {
46 return query<notion>(*this, ppdb_, std::move(where), random, limit); 46 return query<notion>(*this, ppdb_, std::move(where), random, limit);
47 } 47 }
48 48
49 query<word> database::words(filter where, bool random, int limit) const 49 query<word> database::words(filter where, bool random, int limit) const
50 { 50 {
51 return query<word>(*this, ppdb_, std::move(where), random, limit); 51 return query<word>(*this, ppdb_, std::move(where), random, limit);
52 } 52 }
53 53
54 query<group> database::groups(filter where, bool random, int limit) const 54 query<group> database::groups(filter where, bool random, int limit) const
55 { 55 {
56 return query<group>(*this, ppdb_, std::move(where), random, limit); 56 return query<group>(*this, ppdb_, std::move(where), random, limit);
57 } 57 }
58 58
59 query<frame> database::frames(filter where, bool random, int limit) const 59 query<frame> database::frames(filter where, bool random, int limit) const
60 { 60 {
61 return query<frame>(*this, ppdb_, std::move(where), random, limit); 61 return query<frame>(*this, ppdb_, std::move(where), random, limit);
62 } 62 }
63 63
64 query<lemma> database::lemmas(filter where, bool random, int limit) const 64 query<lemma> database::lemmas(filter where, bool random, int limit) const
65 { 65 {
66 return query<lemma>(*this, ppdb_, std::move(where), random, limit); 66 return query<lemma>(*this, ppdb_, std::move(where), random, limit);
67 } 67 }
68 68
69 query<form> database::forms(filter where, bool random, int limit) const 69 query<form> database::forms(filter where, bool random, int limit) const
70 { 70 {
71 return query<form>(*this, ppdb_, std::move(where), random, limit); 71 return query<form>(*this, ppdb_, std::move(where), random, limit);
72 } 72 }
73 73
74 query<pronunciation> database::pronunciations(filter where, bool random, int limit) const 74 query<pronunciation> database::pronunciations(filter where, bool random, int limit) const
75 { 75 {
76 return query<pronunciation>(*this, ppdb_, std::move(where), random, limit); 76 return query<pronunciation>(*this, ppdb_, std::move(where), random, limit);
diff --git a/lib/database.h b/lib/database.h index d68c40b..ef50739 100644 --- a/lib/database.h +++ b/lib/database.h
@@ -15,7 +15,7 @@
15struct sqlite3; 15struct sqlite3;
16 16
17namespace verbly { 17namespace verbly {
18 18
19 template <typename Object> 19 template <typename Object>
20 class query; 20 class query;
21 21
@@ -43,21 +43,21 @@ namespace verbly {
43 // Destructor 43 // Destructor
44 44
45 ~database(); 45 ~database();
46 46
47 // Queries 47 // Queries
48 48
49 query<notion> notions(filter where, bool random = true, int limit = 1) const; 49 query<notion> notions(filter where, bool random = true, int limit = 1) const;
50 50
51 query<word> words(filter where, bool random = true, int limit = 1) const; 51 query<word> words(filter where, bool random = true, int limit = 1) const;
52 52
53 query<group> groups(filter where, bool random = true, int limit = 1) const; 53 query<group> groups(filter where, bool random = true, int limit = 1) const;
54 54
55 query<frame> frames(filter where, bool random = true, int limit = 1) const; 55 query<frame> frames(filter where, bool random = true, int limit = 1) const;
56 56
57 query<lemma> lemmas(filter where, bool random = true, int limit = 1) const; 57 query<lemma> lemmas(filter where, bool random = true, int limit = 1) const;
58 58
59 query<form> forms(filter where, bool random = true, int limit = 1) const; 59 query<form> forms(filter where, bool random = true, int limit = 1) const;
60 60
61 query<pronunciation> pronunciations(filter where, bool random = true, int limit = 1) const; 61 query<pronunciation> pronunciations(filter where, bool random = true, int limit = 1) const;
62 62
63 private: 63 private:
diff --git a/lib/enums.h b/lib/enums.h index b37be7b..e634959 100644 --- a/lib/enums.h +++ b/lib/enums.h
@@ -2,7 +2,7 @@
2#define ENUMS_H_260BA847 2#define ENUMS_H_260BA847
3 3
4namespace verbly { 4namespace verbly {
5 5
6 enum class part_of_speech { 6 enum class part_of_speech {
7 noun = 0, 7 noun = 0,
8 adjective = 1, 8 adjective = 1,
@@ -10,14 +10,14 @@ namespace verbly {
10 verb = 3, 10 verb = 3,
11 preposition = 4 11 preposition = 4
12 }; 12 };
13 13
14 enum class positioning { 14 enum class positioning {
15 undefined = -1, 15 undefined = -1,
16 predicate = 0, 16 predicate = 0,
17 attributive = 1, 17 attributive = 1,
18 postnominal = 2 18 postnominal = 2
19 }; 19 };
20 20
21 enum class inflection { 21 enum class inflection {
22 base = 0, 22 base = 0,
23 plural = 1, 23 plural = 1,
@@ -28,7 +28,7 @@ namespace verbly {
28 ing_form = 6, 28 ing_form = 6,
29 s_form = 7 29 s_form = 7
30 }; 30 };
31 31
32 enum class object { 32 enum class object {
33 undefined = -1, 33 undefined = -1,
34 notion = 0, 34 notion = 0,
@@ -39,7 +39,7 @@ namespace verbly {
39 form = 5, 39 form = 5,
40 pronunciation = 6 40 pronunciation = 6
41 }; 41 };
42 42
43}; 43};
44 44
45#endif /* end of include guard: ENUMS_H_260BA847 */ 45#endif /* end of include guard: ENUMS_H_260BA847 */
diff --git a/lib/field.cpp b/lib/field.cpp index 168935c..deecb06 100644 --- a/lib/field.cpp +++ b/lib/field.cpp
@@ -2,72 +2,72 @@
2#include "filter.h" 2#include "filter.h"
3 3
4namespace verbly { 4namespace verbly {
5 5
6 filter field::operator==(int value) const 6 filter field::operator==(int value) const
7 { 7 {
8 return filter(*this, filter::comparison::int_equals, value); 8 return filter(*this, filter::comparison::int_equals, value);
9 } 9 }
10 10
11 filter field::operator!=(int value) const 11 filter field::operator!=(int value) const
12 { 12 {
13 return filter(*this, filter::comparison::int_does_not_equal, value); 13 return filter(*this, filter::comparison::int_does_not_equal, value);
14 } 14 }
15 15
16 filter field::operator<(int value) const 16 filter field::operator<(int value) const
17 { 17 {
18 return filter(*this, filter::comparison::int_is_less_than, value); 18 return filter(*this, filter::comparison::int_is_less_than, value);
19 } 19 }
20 20
21 filter field::operator<=(int value) const 21 filter field::operator<=(int value) const
22 { 22 {
23 return filter(*this, filter::comparison::int_is_at_most, value); 23 return filter(*this, filter::comparison::int_is_at_most, value);
24 } 24 }
25 25
26 filter field::operator>(int value) const 26 filter field::operator>(int value) const
27 { 27 {
28 return filter(*this, filter::comparison::int_is_greater_than, value); 28 return filter(*this, filter::comparison::int_is_greater_than, value);
29 } 29 }
30 30
31 filter field::operator>=(int value) const 31 filter field::operator>=(int value) const
32 { 32 {
33 return filter(*this, filter::comparison::int_is_at_least, value); 33 return filter(*this, filter::comparison::int_is_at_least, value);
34 } 34 }
35 35
36 filter field::operator==(part_of_speech value) const 36 filter field::operator==(part_of_speech value) const
37 { 37 {
38 return filter(*this, filter::comparison::int_equals, static_cast<int>(value)); 38 return filter(*this, filter::comparison::int_equals, static_cast<int>(value));
39 } 39 }
40 40
41 filter field::operator==(positioning value) const 41 filter field::operator==(positioning value) const
42 { 42 {
43 return filter(*this, filter::comparison::int_equals, static_cast<int>(value)); 43 return filter(*this, filter::comparison::int_equals, static_cast<int>(value));
44 } 44 }
45 45
46 filter field::operator==(inflection value) const 46 filter field::operator==(inflection value) const
47 { 47 {
48 return filter(*this, filter::comparison::int_equals, static_cast<int>(value)); 48 return filter(*this, filter::comparison::int_equals, static_cast<int>(value));
49 } 49 }
50 50
51 filter field::operator==(bool value) const 51 filter field::operator==(bool value) const
52 { 52 {
53 return filter(*this, filter::comparison::boolean_equals, value); 53 return filter(*this, filter::comparison::boolean_equals, value);
54 } 54 }
55 55
56 filter field::operator==(std::string value) const 56 filter field::operator==(std::string value) const
57 { 57 {
58 return filter(*this, filter::comparison::string_equals, std::move(value)); 58 return filter(*this, filter::comparison::string_equals, std::move(value));
59 } 59 }
60 60
61 filter field::operator!=(std::string value) const 61 filter field::operator!=(std::string value) const
62 { 62 {
63 return filter(*this, filter::comparison::string_does_not_equal, std::move(value)); 63 return filter(*this, filter::comparison::string_does_not_equal, std::move(value));
64 } 64 }
65 65
66 filter field::operator%=(std::string value) const 66 filter field::operator%=(std::string value) const
67 { 67 {
68 return filter(*this, filter::comparison::string_is_like, std::move(value)); 68 return filter(*this, filter::comparison::string_is_like, std::move(value));
69 } 69 }
70 70
71 field::operator filter() const 71 field::operator filter() const
72 { 72 {
73 if (isJoin()) 73 if (isJoin())
@@ -77,7 +77,7 @@ namespace verbly {
77 return filter(*this, filter::comparison::is_not_null); 77 return filter(*this, filter::comparison::is_not_null);
78 } 78 }
79 } 79 }
80 80
81 filter field::operator!() const 81 filter field::operator!() const
82 { 82 {
83 if (isJoin()) 83 if (isJoin())
@@ -87,7 +87,7 @@ namespace verbly {
87 return filter(*this, filter::comparison::is_null); 87 return filter(*this, filter::comparison::is_null);
88 } 88 }
89 } 89 }
90 90
91 filter field::operator%=(filter joinCondition) const 91 filter field::operator%=(filter joinCondition) const
92 { 92 {
93 if (type_ == type::hierarchal_join) 93 if (type_ == type::hierarchal_join)
@@ -97,5 +97,5 @@ namespace verbly {
97 return filter(*this, filter::comparison::matches, std::move(joinCondition)); 97 return filter(*this, filter::comparison::matches, std::move(joinCondition));
98 } 98 }
99 } 99 }
100 100
101}; 101};
diff --git a/lib/lemma.cpp b/lib/lemma.cpp index 7fdc360..1601460 100644 --- a/lib/lemma.cpp +++ b/lib/lemma.cpp
@@ -4,71 +4,71 @@
4#include "query.h" 4#include "query.h"
5 5
6namespace verbly { 6namespace verbly {
7 7
8 const object lemma::objectType = object::lemma; 8 const object lemma::objectType = object::lemma;
9 9
10 const std::list<std::string> lemma::select = {"lemma_id"}; 10 const std::list<std::string> lemma::select = {"lemma_id"};
11 11
12 const field lemma::id = field::integerField(object::lemma, "lemma_id"); 12 const field lemma::id = field::integerField(object::lemma, "lemma_id");
13 13
14 const field lemma::word = field::joinField(object::lemma, "lemma_id", object::word); 14 const field lemma::word = field::joinField(object::lemma, "lemma_id", object::word);
15 15
16 const field lemma::formJoin = field::joinField(object::lemma, "form_id", object::form); 16 const field lemma::formJoin = field::joinField(object::lemma, "form_id", object::form);
17 const field lemma::inflectionCategory = field::integerField(object::lemma, "category"); 17 const field lemma::inflectionCategory = field::integerField(object::lemma, "category");
18 18
19 filter operator%=(lemma::inflection_field check, filter joinCondition) 19 filter operator%=(lemma::inflection_field check, filter joinCondition)
20 { 20 {
21 return (lemma::formJoin %= joinCondition) && (lemma::inflectionCategory == check.getCategory()); 21 return (lemma::formJoin %= joinCondition) && (lemma::inflectionCategory == check.getCategory());
22 } 22 }
23 23
24 lemma::inflection_field::operator filter() const 24 lemma::inflection_field::operator filter() const
25 { 25 {
26 return (lemma::inflectionCategory == category_); 26 return (lemma::inflectionCategory == category_);
27 } 27 }
28 28
29 lemma::lemma(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) 29 lemma::lemma(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
30 { 30 {
31 id_ = sqlite3_column_int(row, 0); 31 id_ = sqlite3_column_int(row, 0);
32 } 32 }
33 33
34 const form& lemma::getBaseForm() const 34 const form& lemma::getBaseForm() const
35 { 35 {
36 if (!valid_) 36 if (!valid_)
37 { 37 {
38 throw std::domain_error("Bad access to uninitialized lemma"); 38 throw std::domain_error("Bad access to uninitialized lemma");
39 } 39 }
40 40
41 if (!forms_.count(inflection::base)) 41 if (!forms_.count(inflection::base))
42 { 42 {
43 initializeForm(inflection::base); 43 initializeForm(inflection::base);
44 } 44 }
45 45
46 return forms_.at(inflection::base).front(); 46 return forms_.at(inflection::base).front();
47 } 47 }
48 48
49 bool lemma::hasInflection(inflection category) const 49 bool lemma::hasInflection(inflection category) const
50 { 50 {
51 return !getInflections(category).empty(); 51 return !getInflections(category).empty();
52 } 52 }
53 53
54 const std::vector<form>& lemma::getInflections(inflection category) const 54 const std::vector<form>& lemma::getInflections(inflection category) const
55 { 55 {
56 if (!valid_) 56 if (!valid_)
57 { 57 {
58 throw std::domain_error("Bad access to uninitialized lemma"); 58 throw std::domain_error("Bad access to uninitialized lemma");
59 } 59 }
60 60
61 if (!forms_.count(category)) 61 if (!forms_.count(category))
62 { 62 {
63 initializeForm(category); 63 initializeForm(category);
64 } 64 }
65 65
66 return forms_.at(category); 66 return forms_.at(category);
67 } 67 }
68 68
69 void lemma::initializeForm(inflection infl) const 69 void lemma::initializeForm(inflection infl) const
70 { 70 {
71 forms_[infl] = db_->forms(form::lemma(infl) %= *this, false, -1).all(); 71 forms_[infl] = db_->forms(form::lemma(infl) %= *this, false, -1).all();
72 } 72 }
73 73
74}; 74};
diff --git a/lib/lemma.h b/lib/lemma.h index 8c8d1c1..407fa3c 100644 --- a/lib/lemma.h +++ b/lib/lemma.h
@@ -13,110 +13,110 @@
13struct sqlite3_stmt; 13struct sqlite3_stmt;
14 14
15namespace verbly { 15namespace verbly {
16 16
17 class database; 17 class database;
18 18
19 class lemma { 19 class lemma {
20 public: 20 public:
21 21
22 // Default constructor 22 // Default constructor
23 23
24 lemma() = default; 24 lemma() = default;
25 25
26 // Construct from database 26 // Construct from database
27 27
28 lemma(const database& db, sqlite3_stmt* row); 28 lemma(const database& db, sqlite3_stmt* row);
29 29
30 // Accessors 30 // Accessors
31 31
32 operator bool() const 32 operator bool() const
33 { 33 {
34 return valid_; 34 return valid_;
35 } 35 }
36 36
37 int getId() const 37 int getId() const
38 { 38 {
39 if (!valid_) 39 if (!valid_)
40 { 40 {
41 throw std::domain_error("Bad access to uninitialized lemma"); 41 throw std::domain_error("Bad access to uninitialized lemma");
42 } 42 }
43 43
44 return id_; 44 return id_;
45 } 45 }
46 46
47 const form& getBaseForm() const; 47 const form& getBaseForm() const;
48 48
49 bool hasInflection(inflection category) const; 49 bool hasInflection(inflection category) const;
50 50
51 const std::vector<form>& getInflections(inflection category) const; 51 const std::vector<form>& getInflections(inflection category) const;
52 52
53 // Type info 53 // Type info
54 54
55 static const object objectType; 55 static const object objectType;
56 56
57 static const std::list<std::string> select; 57 static const std::list<std::string> select;
58 58
59 // Query fields 59 // Query fields
60 60
61 static const field id; 61 static const field id;
62 62
63 operator filter() const 63 operator filter() const
64 { 64 {
65 if (!valid_) 65 if (!valid_)
66 { 66 {
67 throw std::domain_error("Bad access to uninitialized lemma"); 67 throw std::domain_error("Bad access to uninitialized lemma");
68 } 68 }
69 69
70 return (id == id_); 70 return (id == id_);
71 } 71 }
72 72
73 // Relationships to other objects 73 // Relationships to other objects
74 74
75 static const field word; 75 static const field word;
76 76
77 class inflection_field { 77 class inflection_field {
78 public: 78 public:
79 79
80 inflection_field(inflection category) : category_(category) 80 inflection_field(inflection category) : category_(category)
81 { 81 {
82 } 82 }
83 83
84 const inflection getCategory() const 84 const inflection getCategory() const
85 { 85 {
86 return category_; 86 return category_;
87 } 87 }
88 88
89 operator filter() const; 89 operator filter() const;
90 90
91 private: 91 private:
92 92
93 const inflection category_; 93 const inflection category_;
94 }; 94 };
95 95
96 static const inflection_field form(inflection category) 96 static const inflection_field form(inflection category)
97 { 97 {
98 return inflection_field(category); 98 return inflection_field(category);
99 } 99 }
100 100
101 friend filter operator%=(lemma::inflection_field check, filter joinCondition); 101 friend filter operator%=(lemma::inflection_field check, filter joinCondition);
102 102
103 private: 103 private:
104 104
105 void initializeForm(inflection category) const; 105 void initializeForm(inflection category) const;
106 106
107 bool valid_ = false; 107 bool valid_ = false;
108 108
109 int id_; 109 int id_;
110 110
111 mutable std::map<inflection, std::vector<class form>> forms_; 111 mutable std::map<inflection, std::vector<class form>> forms_;
112 112
113 const database* db_; 113 const database* db_;
114 114
115 static const field formJoin; 115 static const field formJoin;
116 static const field inflectionCategory; 116 static const field inflectionCategory;
117 117
118 }; 118 };
119 119
120}; 120};
121 121
122#endif /* end of include guard: LEMMA_H_0A180D30 */ 122#endif /* end of include guard: LEMMA_H_0A180D30 */
diff --git a/lib/pronunciation.cpp b/lib/pronunciation.cpp index f5b742f..e937ba6 100644 --- a/lib/pronunciation.cpp +++ b/lib/pronunciation.cpp
@@ -6,64 +6,64 @@
6#include "util.h" 6#include "util.h"
7 7
8namespace verbly { 8namespace verbly {
9 9
10 const object pronunciation::objectType = object::pronunciation; 10 const object pronunciation::objectType = object::pronunciation;
11 11
12 const std::list<std::string> pronunciation::select = {"pronunciation_id", "phonemes", "syllables", "stress", "prerhyme", "rhyme"}; 12 const std::list<std::string> pronunciation::select = {"pronunciation_id", "phonemes", "syllables", "stress", "prerhyme", "rhyme"};
13 13
14 const field pronunciation::id = field::integerField(object::pronunciation, "pronunciation_id"); 14 const field pronunciation::id = field::integerField(object::pronunciation, "pronunciation_id");
15 const field pronunciation::numOfSyllables = field::integerField(object::pronunciation, "syllables"); 15 const field pronunciation::numOfSyllables = field::integerField(object::pronunciation, "syllables");
16 const field pronunciation::stress = field::stringField(object::pronunciation, "stress"); 16 const field pronunciation::stress = field::stringField(object::pronunciation, "stress");
17 17
18 const field pronunciation::form = field::joinThrough(object::pronunciation, "pronunciation_id", object::form, "forms_pronunciations", "form_id"); 18 const field pronunciation::form = field::joinThrough(object::pronunciation, "pronunciation_id", object::form, "forms_pronunciations", "form_id");
19 19
20 const field pronunciation::prerhyme = field::stringField(object::pronunciation, "prerhyme", true); 20 const field pronunciation::prerhyme = field::stringField(object::pronunciation, "prerhyme", true);
21 const field pronunciation::rhyme = field::stringField(object::pronunciation, "rhyme", true); 21 const field pronunciation::rhyme = field::stringField(object::pronunciation, "rhyme", true);
22 22
23 pronunciation::pronunciation(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) 23 pronunciation::pronunciation(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
24 { 24 {
25 id_ = sqlite3_column_int(row, 0); 25 id_ = sqlite3_column_int(row, 0);
26 26
27 std::string phonemesStr(reinterpret_cast<const char*>(sqlite3_column_text(row, 1))); 27 std::string phonemesStr(reinterpret_cast<const char*>(sqlite3_column_text(row, 1)));
28 phonemes_ = split<std::vector<std::string>>(phonemesStr, " "); 28 phonemes_ = split<std::vector<std::string>>(phonemesStr, " ");
29 29
30 syllables_ = sqlite3_column_int(row, 2); 30 syllables_ = sqlite3_column_int(row, 2);
31 stress_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 3))); 31 stress_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 3)));
32 32
33 if (sqlite3_column_type(row, 5) != SQLITE_NULL) 33 if (sqlite3_column_type(row, 5) != SQLITE_NULL)
34 { 34 {
35 hasRhyme_ = true; 35 hasRhyme_ = true;
36 36
37 prerhyme_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 4))); 37 prerhyme_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 4)));
38 rhyme_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 5))); 38 rhyme_ = std::string(reinterpret_cast<const char*>(sqlite3_column_text(row, 5)));
39 } 39 }
40 } 40 }
41 41
42 filter pronunciation::rhymesWith(const pronunciation& arg) 42 filter pronunciation::rhymesWith(const pronunciation& arg)
43 { 43 {
44 return (prerhyme != arg.getPrerhyme()) && (rhyme == arg.getRhyme()); 44 return (prerhyme != arg.getPrerhyme()) && (rhyme == arg.getRhyme());
45 } 45 }
46 46
47 /*filter pronunciation::rhymesWith(const class form& arg) 47 /*filter pronunciation::rhymesWith(const class form& arg)
48 { 48 {
49 filter result; 49 filter result;
50 50
51 for (const pronunciation& p : arg.getPronunciations()) 51 for (const pronunciation& p : arg.getPronunciations())
52 { 52 {
53 result |= rhymesWith(p); 53 result |= rhymesWith(p);
54 } 54 }
55 55
56 return result; 56 return result;
57 } 57 }
58 58
59 filter pronunciation::rhymesWith(const lemma& arg) 59 filter pronunciation::rhymesWith(const lemma& arg)
60 { 60 {
61 return rhymesWith(arg.getBaseForm()); 61 return rhymesWith(arg.getBaseForm());
62 } 62 }
63 63
64 filter pronunciation::rhymesWith(const word& arg) 64 filter pronunciation::rhymesWith(const word& arg)
65 { 65 {
66 return rhymesWith(arg.getLemma()); 66 return rhymesWith(arg.getLemma());
67 }*/ 67 }*/
68 68
69}; 69};
diff --git a/lib/query.h b/lib/query.h index e31be3d..352748f 100644 --- a/lib/query.h +++ b/lib/query.h
@@ -11,36 +11,36 @@
11#include "binding.h" 11#include "binding.h"
12 12
13namespace verbly { 13namespace verbly {
14 14
15 class database_error : public std::logic_error { 15 class database_error : public std::logic_error {
16 public: 16 public:
17 17
18 database_error(std::string msg, std::string sqlMsg) : std::logic_error(msg + " (" + sqlMsg + ")") 18 database_error(std::string msg, std::string sqlMsg) : std::logic_error(msg + " (" + sqlMsg + ")")
19 { 19 {
20 } 20 }
21 }; 21 };
22 22
23 template <typename Object> 23 template <typename Object>
24 class query { 24 class query {
25 public: 25 public:
26 26
27 query(const database& db, sqlite3* ppdb, filter queryFilter, bool random, int limit) : db_(&db) 27 query(const database& db, sqlite3* ppdb, filter queryFilter, bool random, int limit) : db_(&db)
28 { 28 {
29 statement stmt(Object::objectType, std::move(queryFilter)); 29 statement stmt(Object::objectType, std::move(queryFilter));
30 30
31 std::string queryString = stmt.getQueryString(Object::select, random, limit); 31 std::string queryString = stmt.getQueryString(Object::select, random, limit);
32 std::list<binding> bindings = stmt.getBindings(); 32 std::list<binding> bindings = stmt.getBindings();
33 33
34 std::cout << queryString << std::endl; 34 std::cout << queryString << std::endl;
35 35
36 if (sqlite3_prepare_v2(ppdb, queryString.c_str(), queryString.length(), &ppstmt_, NULL) != SQLITE_OK) 36 if (sqlite3_prepare_v2(ppdb, queryString.c_str(), queryString.length(), &ppstmt_, NULL) != SQLITE_OK)
37 { 37 {
38 std::string errorMsg = sqlite3_errmsg(ppdb); 38 std::string errorMsg = sqlite3_errmsg(ppdb);
39 sqlite3_finalize(ppstmt_); 39 sqlite3_finalize(ppstmt_);
40 40
41 throw database_error("Error preparing query", errorMsg); 41 throw database_error("Error preparing query", errorMsg);
42 } 42 }
43 43
44 int i = 1; 44 int i = 1;
45 for (const binding& value : bindings) 45 for (const binding& value : bindings)
46 { 46 {
@@ -52,52 +52,52 @@ namespace verbly {
52 { 52 {
53 std::string errorMsg = sqlite3_errmsg(ppdb); 53 std::string errorMsg = sqlite3_errmsg(ppdb);
54 sqlite3_finalize(ppstmt_); 54 sqlite3_finalize(ppstmt_);
55 55
56 throw database_error("Error binding value to query", errorMsg); 56 throw database_error("Error binding value to query", errorMsg);
57 } 57 }
58 58
59 break; 59 break;
60 } 60 }
61 61
62 case binding::type::string: 62 case binding::type::string:
63 { 63 {
64 if (sqlite3_bind_text(ppstmt_, i, value.getString().c_str(), value.getString().length(), SQLITE_TRANSIENT) != SQLITE_OK) 64 if (sqlite3_bind_text(ppstmt_, i, value.getString().c_str(), value.getString().length(), SQLITE_TRANSIENT) != SQLITE_OK)
65 { 65 {
66 std::string errorMsg = sqlite3_errmsg(ppdb); 66 std::string errorMsg = sqlite3_errmsg(ppdb);
67 sqlite3_finalize(ppstmt_); 67 sqlite3_finalize(ppstmt_);
68 68
69 throw database_error("Error binding value to query", errorMsg); 69 throw database_error("Error binding value to query", errorMsg);
70 } 70 }
71 71
72 break; 72 break;
73 } 73 }
74 74
75 case binding::type::invalid: 75 case binding::type::invalid:
76 { 76 {
77 throw std::logic_error("Cannot use invalid bindings"); 77 throw std::logic_error("Cannot use invalid bindings");
78 } 78 }
79 } 79 }
80 80
81 i++; 81 i++;
82 } 82 }
83 } 83 }
84 84
85 ~query() 85 ~query()
86 { 86 {
87 sqlite3_finalize(ppstmt_); 87 sqlite3_finalize(ppstmt_);
88 } 88 }
89 89
90 std::vector<Object> all() const 90 std::vector<Object> all() const
91 { 91 {
92 std::vector<Object> result; 92 std::vector<Object> result;
93 93
94 while (sqlite3_step(ppstmt_) == SQLITE_ROW) 94 while (sqlite3_step(ppstmt_) == SQLITE_ROW)
95 { 95 {
96 result.emplace_back(*db_, ppstmt_); 96 result.emplace_back(*db_, ppstmt_);
97 } 97 }
98 98
99 sqlite3_reset(ppstmt_); 99 sqlite3_reset(ppstmt_);
100 100
101 return result; 101 return result;
102 } 102 }
103 103
@@ -111,13 +111,13 @@ namespace verbly {
111 throw std::logic_error("query returned empty dataset"); 111 throw std::logic_error("query returned empty dataset");
112 } 112 }
113 } 113 }
114 114
115 private: 115 private:
116 const database* db_; 116 const database* db_;
117 sqlite3_stmt* ppstmt_; 117 sqlite3_stmt* ppstmt_;
118 118
119 }; 119 };
120 120
121}; 121};
122 122
123#endif /* end of include guard: QUERY_H_7CC5284C */ 123#endif /* end of include guard: QUERY_H_7CC5284C */
diff --git a/lib/role.h b/lib/role.h index 8653710..4884ef3 100644 --- a/lib/role.h +++ b/lib/role.h
@@ -9,13 +9,13 @@ namespace verbly {
9 9
10 class role { 10 class role {
11 public: 11 public:
12 12
13 // Default constructor 13 // Default constructor
14 14
15 role() = default; 15 role() = default;
16 16
17 // Constructor 17 // Constructor
18 18
19 role( 19 role(
20 std::string name, 20 std::string name,
21 selrestr selrestrs = {}) : 21 selrestr selrestrs = {}) :
@@ -24,35 +24,35 @@ namespace verbly {
24 selrestrs_(selrestrs) 24 selrestrs_(selrestrs)
25 { 25 {
26 } 26 }
27 27
28 // Accessors 28 // Accessors
29 29
30 const std::string& getName() const 30 const std::string& getName() const
31 { 31 {
32 if (!valid_) 32 if (!valid_)
33 { 33 {
34 throw std::domain_error("Bad access to invalid role"); 34 throw std::domain_error("Bad access to invalid role");
35 } 35 }
36 36
37 return name_; 37 return name_;
38 } 38 }
39 39
40 const selrestr& getSelrestrs() const 40 const selrestr& getSelrestrs() const
41 { 41 {
42 if (!valid_) 42 if (!valid_)
43 { 43 {
44 throw std::domain_error("Bad access to invalid role"); 44 throw std::domain_error("Bad access to invalid role");
45 } 45 }
46 46
47 return selrestrs_; 47 return selrestrs_;
48 } 48 }
49 49
50 private: 50 private:
51 51
52 bool valid_ = false; 52 bool valid_ = false;
53 std::string name_; 53 std::string name_;
54 selrestr selrestrs_; 54 selrestr selrestrs_;
55 55
56 }; 56 };
57 57
58}; 58};
diff --git a/lib/selrestr.cpp b/lib/selrestr.cpp index 74ea726..8646871 100644 --- a/lib/selrestr.cpp +++ b/lib/selrestr.cpp
@@ -1,7 +1,7 @@
1#include "selrestr.h" 1#include "selrestr.h"
2 2
3namespace verbly { 3namespace verbly {
4 4
5 selrestr::selrestr(nlohmann::json data) 5 selrestr::selrestr(nlohmann::json data)
6 { 6 {
7 if (data.find("children") != data.end()) 7 if (data.find("children") != data.end())
@@ -13,7 +13,7 @@ namespace verbly {
13 { 13 {
14 group_.children.emplace_back(child); 14 group_.children.emplace_back(child);
15 } 15 }
16 16
17 group_.orlogic = (data["logic"] == "or"); 17 group_.orlogic = (data["logic"] == "or");
18 } else if (data.find("type") != data.end()) 18 } else if (data.find("type") != data.end())
19 { 19 {
@@ -24,139 +24,139 @@ namespace verbly {
24 type_ = type::empty; 24 type_ = type::empty;
25 } 25 }
26 } 26 }
27 27
28 selrestr::selrestr(const selrestr& other) 28 selrestr::selrestr(const selrestr& other)
29 { 29 {
30 type_ = other.type_; 30 type_ = other.type_;
31 31
32 switch (type_) 32 switch (type_)
33 { 33 {
34 case type::singleton: 34 case type::singleton:
35 { 35 {
36 singleton_.pos = other.singleton_.pos; 36 singleton_.pos = other.singleton_.pos;
37 new(&singleton_.restriction) std::string(other.singleton_.restriction); 37 new(&singleton_.restriction) std::string(other.singleton_.restriction);
38 38
39 break; 39 break;
40 } 40 }
41 41
42 case type::group: 42 case type::group:
43 { 43 {
44 new(&group_.children) std::list<selrestr>(other.group_.children); 44 new(&group_.children) std::list<selrestr>(other.group_.children);
45 group_.orlogic = other.group_.orlogic; 45 group_.orlogic = other.group_.orlogic;
46 46
47 break; 47 break;
48 } 48 }
49 49
50 case type::empty: 50 case type::empty:
51 { 51 {
52 break; 52 break;
53 } 53 }
54 } 54 }
55 } 55 }
56 56
57 selrestr::selrestr(selrestr&& other) : selrestr() 57 selrestr::selrestr(selrestr&& other) : selrestr()
58 { 58 {
59 swap(*this, other); 59 swap(*this, other);
60 } 60 }
61 61
62 selrestr& selrestr::operator=(selrestr other) 62 selrestr& selrestr::operator=(selrestr other)
63 { 63 {
64 swap(*this, other); 64 swap(*this, other);
65 65
66 return *this; 66 return *this;
67 } 67 }
68 68
69 void swap(selrestr& first, selrestr& second) 69 void swap(selrestr& first, selrestr& second)
70 { 70 {
71 using type = selrestr::type; 71 using type = selrestr::type;
72 72
73 type tempType = first.type_; 73 type tempType = first.type_;
74 int tempPos; 74 int tempPos;
75 std::string tempRestriction; 75 std::string tempRestriction;
76 std::list<selrestr> tempChildren; 76 std::list<selrestr> tempChildren;
77 bool tempOrlogic; 77 bool tempOrlogic;
78 78
79 switch (tempType) 79 switch (tempType)
80 { 80 {
81 case type::singleton: 81 case type::singleton:
82 { 82 {
83 tempPos = first.singleton_.pos; 83 tempPos = first.singleton_.pos;
84 tempRestriction = std::move(first.singleton_.restriction); 84 tempRestriction = std::move(first.singleton_.restriction);
85 85
86 break; 86 break;
87 } 87 }
88 88
89 case type::group: 89 case type::group:
90 { 90 {
91 tempChildren = std::move(first.group_.children); 91 tempChildren = std::move(first.group_.children);
92 tempOrlogic = first.group_.orlogic; 92 tempOrlogic = first.group_.orlogic;
93 93
94 break; 94 break;
95 } 95 }
96 96
97 case type::empty: 97 case type::empty:
98 { 98 {
99 break; 99 break;
100 } 100 }
101 } 101 }
102 102
103 first.~selrestr(); 103 first.~selrestr();
104 104
105 first.type_ = second.type_; 105 first.type_ = second.type_;
106 106
107 switch (first.type_) 107 switch (first.type_)
108 { 108 {
109 case type::singleton: 109 case type::singleton:
110 { 110 {
111 first.singleton_.pos = second.singleton_.pos; 111 first.singleton_.pos = second.singleton_.pos;
112 new(&first.singleton_.restriction) std::string(std::move(second.singleton_.restriction)); 112 new(&first.singleton_.restriction) std::string(std::move(second.singleton_.restriction));
113 113
114 break; 114 break;
115 } 115 }
116 116
117 case type::group: 117 case type::group:
118 { 118 {
119 new(&first.group_.children) std::list<selrestr>(std::move(second.group_.children)); 119 new(&first.group_.children) std::list<selrestr>(std::move(second.group_.children));
120 first.group_.orlogic = second.group_.orlogic; 120 first.group_.orlogic = second.group_.orlogic;
121 121
122 break; 122 break;
123 } 123 }
124 124
125 case type::empty: 125 case type::empty:
126 { 126 {
127 break; 127 break;
128 } 128 }
129 } 129 }
130 130
131 second.~selrestr(); 131 second.~selrestr();
132 132
133 second.type_ = tempType; 133 second.type_ = tempType;
134 134
135 switch (second.type_) 135 switch (second.type_)
136 { 136 {
137 case type::singleton: 137 case type::singleton:
138 { 138 {
139 second.singleton_.pos = tempPos; 139 second.singleton_.pos = tempPos;
140 new(&second.singleton_.restriction) std::string(std::move(tempRestriction)); 140 new(&second.singleton_.restriction) std::string(std::move(tempRestriction));
141 141
142 break; 142 break;
143 } 143 }
144 144
145 case type::group: 145 case type::group:
146 { 146 {
147 new(&second.group_.children) std::list<selrestr>(std::move(tempChildren)); 147 new(&second.group_.children) std::list<selrestr>(std::move(tempChildren));
148 second.group_.orlogic = tempOrlogic; 148 second.group_.orlogic = tempOrlogic;
149 149
150 break; 150 break;
151 } 151 }
152 152
153 case type::empty: 153 case type::empty:
154 { 154 {
155 break; 155 break;
156 } 156 }
157 } 157 }
158 } 158 }
159 159
160 selrestr::~selrestr() 160 selrestr::~selrestr()
161 { 161 {
162 switch (type_) 162 switch (type_)
@@ -165,29 +165,29 @@ namespace verbly {
165 { 165 {
166 using string_type = std::string; 166 using string_type = std::string;
167 singleton_.restriction.~string_type(); 167 singleton_.restriction.~string_type();
168 168
169 break; 169 break;
170 } 170 }
171 171
172 case type::group: 172 case type::group:
173 { 173 {
174 using list_type = std::list<selrestr>; 174 using list_type = std::list<selrestr>;
175 group_.children.~list_type(); 175 group_.children.~list_type();
176 176
177 break; 177 break;
178 } 178 }
179 179
180 case type::empty: 180 case type::empty:
181 { 181 {
182 break; 182 break;
183 } 183 }
184 } 184 }
185 } 185 }
186 186
187 selrestr::selrestr() : type_(type::empty) 187 selrestr::selrestr() : type_(type::empty)
188 { 188 {
189 } 189 }
190 190
191 selrestr::selrestr( 191 selrestr::selrestr(
192 std::string restriction, 192 std::string restriction,
193 bool pos) : 193 bool pos) :
@@ -196,7 +196,7 @@ namespace verbly {
196 new(&singleton_.restriction) std::string(std::move(restriction)); 196 new(&singleton_.restriction) std::string(std::move(restriction));
197 singleton_.pos = pos; 197 singleton_.pos = pos;
198 } 198 }
199 199
200 std::string selrestr::getRestriction() const 200 std::string selrestr::getRestriction() const
201 { 201 {
202 if (type_ == type::singleton) 202 if (type_ == type::singleton)
@@ -206,7 +206,7 @@ namespace verbly {
206 throw std::domain_error("Only singleton selrestrs have restrictions"); 206 throw std::domain_error("Only singleton selrestrs have restrictions");
207 } 207 }
208 } 208 }
209 209
210 bool selrestr::getPos() const 210 bool selrestr::getPos() const
211 { 211 {
212 if (type_ == type::singleton) 212 if (type_ == type::singleton)
@@ -216,7 +216,7 @@ namespace verbly {
216 throw std::domain_error("Only singleton selrestrs have positivity flags"); 216 throw std::domain_error("Only singleton selrestrs have positivity flags");
217 } 217 }
218 } 218 }
219 219
220 selrestr::selrestr( 220 selrestr::selrestr(
221 std::list<selrestr> children, 221 std::list<selrestr> children,
222 bool orlogic) : 222 bool orlogic) :
@@ -225,7 +225,7 @@ namespace verbly {
225 new(&group_.children) std::list<selrestr>(std::move(children)); 225 new(&group_.children) std::list<selrestr>(std::move(children));
226 group_.orlogic = orlogic; 226 group_.orlogic = orlogic;
227 } 227 }
228 228
229 std::list<selrestr> selrestr::getChildren() const 229 std::list<selrestr> selrestr::getChildren() const
230 { 230 {
231 if (type_ == type::group) 231 if (type_ == type::group)
@@ -235,7 +235,7 @@ namespace verbly {
235 throw std::domain_error("Only group selrestrs have children"); 235 throw std::domain_error("Only group selrestrs have children");
236 } 236 }
237 } 237 }
238 238
239 std::list<selrestr>::const_iterator selrestr::begin() const 239 std::list<selrestr>::const_iterator selrestr::begin() const
240 { 240 {
241 if (type_ == type::group) 241 if (type_ == type::group)
@@ -245,7 +245,7 @@ namespace verbly {
245 throw std::domain_error("Only group selrestrs have children"); 245 throw std::domain_error("Only group selrestrs have children");
246 } 246 }
247 } 247 }
248 248
249 std::list<selrestr>::const_iterator selrestr::end() const 249 std::list<selrestr>::const_iterator selrestr::end() const
250 { 250 {
251 if (type_ == type::group) 251 if (type_ == type::group)
@@ -255,7 +255,7 @@ namespace verbly {
255 throw std::domain_error("Only group selrestrs have children"); 255 throw std::domain_error("Only group selrestrs have children");
256 } 256 }
257 } 257 }
258 258
259 bool selrestr::getOrlogic() const 259 bool selrestr::getOrlogic() const
260 { 260 {
261 if (type_ == type::group) 261 if (type_ == type::group)
@@ -265,7 +265,7 @@ namespace verbly {
265 throw std::domain_error("Only group selrestrs have logic"); 265 throw std::domain_error("Only group selrestrs have logic");
266 } 266 }
267 } 267 }
268 268
269 nlohmann::json selrestr::toJson() const 269 nlohmann::json selrestr::toJson() const
270 { 270 {
271 switch (type_) 271 switch (type_)
@@ -274,7 +274,7 @@ namespace verbly {
274 { 274 {
275 return {}; 275 return {};
276 } 276 }
277 277
278 case type::singleton: 278 case type::singleton:
279 { 279 {
280 return { 280 return {
@@ -282,7 +282,7 @@ namespace verbly {
282 {"pos", singleton_.pos} 282 {"pos", singleton_.pos}
283 }; 283 };
284 } 284 }
285 285
286 case type::group: 286 case type::group:
287 { 287 {
288 std::string logic; 288 std::string logic;
@@ -292,12 +292,12 @@ namespace verbly {
292 } else { 292 } else {
293 logic = "and"; 293 logic = "and";
294 } 294 }
295 295
296 std::list<nlohmann::json> children; 296 std::list<nlohmann::json> children;
297 std::transform(std::begin(group_.children), std::end(group_.children), std::back_inserter(children), [] (const selrestr& child) { 297 std::transform(std::begin(group_.children), std::end(group_.children), std::back_inserter(children), [] (const selrestr& child) {
298 return child.toJson(); 298 return child.toJson();
299 }); 299 });
300 300
301 return { 301 return {
302 {"logic", logic}, 302 {"logic", logic},
303 {"children", children} 303 {"children", children}
diff --git a/lib/selrestr.h b/lib/selrestr.h index 9f82e3e..a7cde0a 100644 --- a/lib/selrestr.h +++ b/lib/selrestr.h
@@ -6,7 +6,7 @@
6#include "../vendor/json/json.hpp" 6#include "../vendor/json/json.hpp"
7 7
8namespace verbly { 8namespace verbly {
9 9
10 class selrestr { 10 class selrestr {
11 public: 11 public:
12 enum class type { 12 enum class type {
@@ -14,63 +14,63 @@ namespace verbly {
14 singleton, 14 singleton,
15 group 15 group
16 }; 16 };
17 17
18 // Construct from json 18 // Construct from json
19 19
20 explicit selrestr(nlohmann::json json); 20 explicit selrestr(nlohmann::json json);
21 21
22 // Copy and move constructors 22 // Copy and move constructors
23 23
24 selrestr(const selrestr& other); 24 selrestr(const selrestr& other);
25 selrestr(selrestr&& other); 25 selrestr(selrestr&& other);
26 26
27 // Assignment 27 // Assignment
28 28
29 selrestr& operator=(selrestr other); 29 selrestr& operator=(selrestr other);
30 30
31 // Swap 31 // Swap
32 32
33 friend void swap(selrestr& first, selrestr& second); 33 friend void swap(selrestr& first, selrestr& second);
34 34
35 // Destructor 35 // Destructor
36 36
37 ~selrestr(); 37 ~selrestr();
38 38
39 // Generic accessors 39 // Generic accessors
40 40
41 type getType() const 41 type getType() const
42 { 42 {
43 return type_; 43 return type_;
44 } 44 }
45 45
46 // Empty 46 // Empty
47 47
48 selrestr(); 48 selrestr();
49 49
50 // Singleton 50 // Singleton
51 51
52 selrestr(std::string restriction, bool pos); 52 selrestr(std::string restriction, bool pos);
53 53
54 std::string getRestriction() const; 54 std::string getRestriction() const;
55 55
56 bool getPos() const; 56 bool getPos() const;
57 57
58 // Group 58 // Group
59 59
60 selrestr(std::list<selrestr> children, bool orlogic); 60 selrestr(std::list<selrestr> children, bool orlogic);
61 61
62 std::list<selrestr> getChildren() const; 62 std::list<selrestr> getChildren() const;
63 63
64 std::list<selrestr>::const_iterator begin() const; 64 std::list<selrestr>::const_iterator begin() const;
65 65
66 std::list<selrestr>::const_iterator end() const; 66 std::list<selrestr>::const_iterator end() const;
67 67
68 bool getOrlogic() const; 68 bool getOrlogic() const;
69 69
70 // Helpers 70 // Helpers
71 71
72 nlohmann::json toJson() const; 72 nlohmann::json toJson() const;
73 73
74 private: 74 private:
75 union { 75 union {
76 struct { 76 struct {
diff --git a/lib/statement.cpp b/lib/statement.cpp index 222a8eb..846b9de 100644 --- a/lib/statement.cpp +++ b/lib/statement.cpp
@@ -12,22 +12,22 @@
12#include "pronunciation.h" 12#include "pronunciation.h"
13 13
14namespace verbly { 14namespace verbly {
15 15
16 statement::statement( 16 statement::statement(
17 object context, 17 object context,
18 filter queryFilter) : 18 filter queryFilter) :
19 statement(getTableForContext(context), queryFilter.compact().normalize(context)) 19 statement(getTableForContext(context), queryFilter.compact().normalize(context))
20 { 20 {
21 } 21 }
22 22
23 std::string statement::getQueryString(std::list<std::string> select, bool random, int limit) const 23 std::string statement::getQueryString(std::list<std::string> select, bool random, int limit) const
24 { 24 {
25 std::stringstream queryStream; 25 std::stringstream queryStream;
26 26
27 if (!withs_.empty()) 27 if (!withs_.empty())
28 { 28 {
29 queryStream << "WITH RECURSIVE "; 29 queryStream << "WITH RECURSIVE ";
30 30
31 std::list<std::string> ctes; 31 std::list<std::string> ctes;
32 for (const with& cte : withs_) 32 for (const with& cte : withs_)
33 { 33 {
@@ -39,19 +39,19 @@ namespace verbly {
39 cteStream << cte.getTableForId(cte.getTopTable()); 39 cteStream << cte.getTableForId(cte.getTopTable());
40 cteStream << " AS "; 40 cteStream << " AS ";
41 cteStream << cte.getTopTable(); 41 cteStream << cte.getTopTable();
42 42
43 for (const join& j : cte.getJoins()) 43 for (const join& j : cte.getJoins())
44 { 44 {
45 cteStream << " "; 45 cteStream << " ";
46 cteStream << j; 46 cteStream << j;
47 } 47 }
48 48
49 if (cte.getCondition().getType() != condition::type::empty) 49 if (cte.getCondition().getType() != condition::type::empty)
50 { 50 {
51 cteStream << " WHERE "; 51 cteStream << " WHERE ";
52 cteStream << cte.getCondition().toSql(); 52 cteStream << cte.getCondition().toSql();
53 } 53 }
54 54
55 if (cte.isRecursive()) 55 if (cte.isRecursive())
56 { 56 {
57 cteStream << " UNION SELECT l.* FROM "; 57 cteStream << " UNION SELECT l.* FROM ";
@@ -69,59 +69,59 @@ namespace verbly {
69 cteStream << " = l."; 69 cteStream << " = l.";
70 cteStream << cte.getField().getColumn(); 70 cteStream << cte.getField().getColumn();
71 } 71 }
72 72
73 cteStream << ")"; 73 cteStream << ")";
74 74
75 ctes.push_back(cteStream.str()); 75 ctes.push_back(cteStream.str());
76 } 76 }
77 77
78 queryStream << implode(std::begin(ctes), std::end(ctes), ", "); 78 queryStream << implode(std::begin(ctes), std::end(ctes), ", ");
79 queryStream << " "; 79 queryStream << " ";
80 } 80 }
81 81
82 std::list<std::string> realSelect; 82 std::list<std::string> realSelect;
83 for (std::string& s : select) 83 for (std::string& s : select)
84 { 84 {
85 realSelect.push_back(topTable_ + "." + s); 85 realSelect.push_back(topTable_ + "." + s);
86 } 86 }
87 87
88 queryStream << "SELECT "; 88 queryStream << "SELECT ";
89 queryStream << implode(std::begin(realSelect), std::end(realSelect), ", "); 89 queryStream << implode(std::begin(realSelect), std::end(realSelect), ", ");
90 queryStream << " FROM "; 90 queryStream << " FROM ";
91 queryStream << tables_.at(topTable_); 91 queryStream << tables_.at(topTable_);
92 queryStream << " AS "; 92 queryStream << " AS ";
93 queryStream << topTable_; 93 queryStream << topTable_;
94 94
95 for (const join& j : joins_) 95 for (const join& j : joins_)
96 { 96 {
97 queryStream << " "; 97 queryStream << " ";
98 queryStream << j; 98 queryStream << j;
99 } 99 }
100 100
101 if (topCondition_.getType() != condition::type::empty) 101 if (topCondition_.getType() != condition::type::empty)
102 { 102 {
103 queryStream << " WHERE "; 103 queryStream << " WHERE ";
104 queryStream << topCondition_.toSql(); 104 queryStream << topCondition_.toSql();
105 } 105 }
106 106
107 if (random) 107 if (random)
108 { 108 {
109 queryStream << " ORDER BY RANDOM()"; 109 queryStream << " ORDER BY RANDOM()";
110 } 110 }
111 111
112 if (limit > 0) 112 if (limit > 0)
113 { 113 {
114 queryStream << " LIMIT "; 114 queryStream << " LIMIT ";
115 queryStream << limit; 115 queryStream << limit;
116 } 116 }
117 117
118 return queryStream.str(); 118 return queryStream.str();
119 } 119 }
120 120
121 std::list<binding> statement::getBindings() const 121 std::list<binding> statement::getBindings() const
122 { 122 {
123 std::list<binding> result; 123 std::list<binding> result;
124 124
125 for (const with& w : withs_) 125 for (const with& w : withs_)
126 { 126 {
127 for (binding value : w.getCondition().flattenBindings()) 127 for (binding value : w.getCondition().flattenBindings())
@@ -129,15 +129,15 @@ namespace verbly {
129 result.push_back(std::move(value)); 129 result.push_back(std::move(value));
130 } 130 }
131 } 131 }
132 132
133 for (binding value : topCondition_.flattenBindings()) 133 for (binding value : topCondition_.flattenBindings())
134 { 134 {
135 result.push_back(std::move(value)); 135 result.push_back(std::move(value));
136 } 136 }
137 137
138 return result; 138 return result;
139 } 139 }
140 140
141 statement::statement( 141 statement::statement(
142 std::string tableName, 142 std::string tableName,
143 filter clause, 143 filter clause,
@@ -149,7 +149,7 @@ namespace verbly {
149 topCondition_(parseFilter(std::move(clause))) 149 topCondition_(parseFilter(std::move(clause)))
150 { 150 {
151 } 151 }
152 152
153 /** 153 /**
154 * This function recursively parses the query's filter condition. It is not 154 * This function recursively parses the query's filter condition. It is not
155 * idempotent. It returns a condition object representing the passed filter, 155 * idempotent. It returns a condition object representing the passed filter,
@@ -165,7 +165,7 @@ namespace verbly {
165 { 165 {
166 return {}; 166 return {};
167 } 167 }
168 168
169 case filter::type::singleton: 169 case filter::type::singleton:
170 { 170 {
171 switch (clause.getField().getType()) 171 switch (clause.getField().getType())
@@ -174,7 +174,7 @@ namespace verbly {
174 { 174 {
175 return {}; 175 return {};
176 } 176 }
177 177
178 // For primitive type filters, all we need to do is translate the 178 // For primitive type filters, all we need to do is translate the
179 // filter object directly into a condition object. No joins are 179 // filter object directly into a condition object. No joins are
180 // necessary. 180 // necessary.
@@ -188,67 +188,67 @@ namespace verbly {
188 { 188 {
189 return condition(topTable_, clause.getField().getColumn(), true); 189 return condition(topTable_, clause.getField().getColumn(), true);
190 } 190 }
191 191
192 case filter::comparison::is_not_null: 192 case filter::comparison::is_not_null:
193 { 193 {
194 return condition(topTable_, clause.getField().getColumn(), false); 194 return condition(topTable_, clause.getField().getColumn(), false);
195 } 195 }
196 196
197 case filter::comparison::int_equals: 197 case filter::comparison::int_equals:
198 { 198 {
199 return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getIntegerArgument()); 199 return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getIntegerArgument());
200 } 200 }
201 201
202 case filter::comparison::int_does_not_equal: 202 case filter::comparison::int_does_not_equal:
203 { 203 {
204 return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, clause.getIntegerArgument()); 204 return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, clause.getIntegerArgument());
205 } 205 }
206 206
207 case filter::comparison::int_is_at_least: 207 case filter::comparison::int_is_at_least:
208 { 208 {
209 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_at_least, clause.getIntegerArgument()); 209 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_at_least, clause.getIntegerArgument());
210 } 210 }
211 211
212 case filter::comparison::int_is_greater_than: 212 case filter::comparison::int_is_greater_than:
213 { 213 {
214 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_greater_than, clause.getIntegerArgument()); 214 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_greater_than, clause.getIntegerArgument());
215 } 215 }
216 216
217 case filter::comparison::int_is_at_most: 217 case filter::comparison::int_is_at_most:
218 { 218 {
219 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_at_most, clause.getIntegerArgument()); 219 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_at_most, clause.getIntegerArgument());
220 } 220 }
221 221
222 case filter::comparison::int_is_less_than: 222 case filter::comparison::int_is_less_than:
223 { 223 {
224 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_less_than, clause.getIntegerArgument()); 224 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_less_than, clause.getIntegerArgument());
225 } 225 }
226 226
227 case filter::comparison::boolean_equals: 227 case filter::comparison::boolean_equals:
228 { 228 {
229 return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getBooleanArgument() ? 1 : 0); 229 return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getBooleanArgument() ? 1 : 0);
230 } 230 }
231 231
232 case filter::comparison::string_equals: 232 case filter::comparison::string_equals:
233 { 233 {
234 return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getStringArgument()); 234 return condition(topTable_, clause.getField().getColumn(), condition::comparison::equals, clause.getStringArgument());
235 } 235 }
236 236
237 case filter::comparison::string_does_not_equal: 237 case filter::comparison::string_does_not_equal:
238 { 238 {
239 return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, clause.getStringArgument()); 239 return condition(topTable_, clause.getField().getColumn(), condition::comparison::does_not_equal, clause.getStringArgument());
240 } 240 }
241 241
242 case filter::comparison::string_is_like: 242 case filter::comparison::string_is_like:
243 { 243 {
244 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_like, clause.getStringArgument()); 244 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_like, clause.getStringArgument());
245 } 245 }
246 246
247 case filter::comparison::string_is_not_like: 247 case filter::comparison::string_is_not_like:
248 { 248 {
249 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_not_like, clause.getStringArgument()); 249 return condition(topTable_, clause.getField().getColumn(), condition::comparison::is_not_like, clause.getStringArgument());
250 } 250 }
251 251
252 case filter::comparison::matches: 252 case filter::comparison::matches:
253 case filter::comparison::does_not_match: 253 case filter::comparison::does_not_match:
254 case filter::comparison::hierarchally_matches: 254 case filter::comparison::hierarchally_matches:
@@ -258,7 +258,7 @@ namespace verbly {
258 } 258 }
259 } 259 }
260 } 260 }
261 261
262 case field::type::join: 262 case field::type::join:
263 { 263 {
264 // First, figure out what table we need to join against. 264 // First, figure out what table we need to join against.
@@ -278,9 +278,9 @@ namespace verbly {
278 clause.getJoinCondition().normalize(clause.getField().getJoinObject()), 278 clause.getJoinCondition().normalize(clause.getField().getJoinObject()),
279 nextTableId_, 279 nextTableId_,
280 nextWithId_); 280 nextWithId_);
281 281
282 std::string joinTable = joinStmt.topTable_; 282 std::string joinTable = joinStmt.topTable_;
283 283
284 if (clause.getComparison() == filter::comparison::does_not_match) 284 if (clause.getComparison() == filter::comparison::does_not_match)
285 { 285 {
286 // If the comparison is actually a negative filter, we can't just 286 // If the comparison is actually a negative filter, we can't just
@@ -293,7 +293,7 @@ namespace verbly {
293 // condition on the join column being NULL as before. 293 // condition on the join column being NULL as before.
294 std::string withName = instantiateWith(clause.getField().getTable()); 294 std::string withName = instantiateWith(clause.getField().getTable());
295 std::string withInstName = instantiateTable(withName); 295 std::string withInstName = instantiateTable(withName);
296 296
297 // LEFT JOIN against the CTE. 297 // LEFT JOIN against the CTE.
298 joins_.emplace_back( 298 joins_.emplace_back(
299 true, 299 true,
@@ -310,7 +310,7 @@ namespace verbly {
310 std::map<std::string, std::string> cteTables = std::move(joinStmt.tables_); 310 std::map<std::string, std::string> cteTables = std::move(joinStmt.tables_);
311 std::list<join> cteJoins = std::move(joinStmt.joins_); 311 std::list<join> cteJoins = std::move(joinStmt.joins_);
312 condition cteCondition = integrate(std::move(joinStmt), true); 312 condition cteCondition = integrate(std::move(joinStmt), true);
313 313
314 withs_.emplace_back( 314 withs_.emplace_back(
315 std::move(withName), 315 std::move(withName),
316 clause.getField(), 316 clause.getField(),
@@ -319,7 +319,7 @@ namespace verbly {
319 std::move(cteCondition), 319 std::move(cteCondition),
320 std::move(cteJoins), 320 std::move(cteJoins),
321 false); 321 false);
322 322
323 // Condition on the join column being NULL, which causes the query 323 // Condition on the join column being NULL, which causes the query
324 // to only return results that do not match the subquery. 324 // to only return results that do not match the subquery.
325 return condition(std::move(withInstName), clause.getField().getColumn(), true); 325 return condition(std::move(withInstName), clause.getField().getColumn(), true);
@@ -332,14 +332,14 @@ namespace verbly {
332 clause.getField().getColumn(), 332 clause.getField().getColumn(),
333 std::move(joinTable), 333 std::move(joinTable),
334 clause.getField().getColumn()); 334 clause.getField().getColumn());
335 335
336 // Integrate the subquery's table mappings, joins, and CTEs into 336 // Integrate the subquery's table mappings, joins, and CTEs into
337 // this statement, and return the subquery condition as our 337 // this statement, and return the subquery condition as our
338 // condition. 338 // condition.
339 return integrate(std::move(joinStmt)); 339 return integrate(std::move(joinStmt));
340 } 340 }
341 } 341 }
342 342
343 case field::type::join_through: 343 case field::type::join_through:
344 { 344 {
345 // Recursively parse the subquery, and therefore obtain an 345 // Recursively parse the subquery, and therefore obtain an
@@ -350,9 +350,9 @@ namespace verbly {
350 clause.getJoinCondition().normalize(clause.getField().getJoinObject()), 350 clause.getJoinCondition().normalize(clause.getField().getJoinObject()),
351 nextTableId_, 351 nextTableId_,
352 nextWithId_); 352 nextWithId_);
353 353
354 std::string joinTable = joinStmt.topTable_; 354 std::string joinTable = joinStmt.topTable_;
355 355
356 if (clause.getComparison() == filter::comparison::does_not_match) 356 if (clause.getComparison() == filter::comparison::does_not_match)
357 { 357 {
358 // If the comparison is actually a negative filter, we can't just 358 // If the comparison is actually a negative filter, we can't just
@@ -366,7 +366,7 @@ namespace verbly {
366 // condition on the join column being NULL as before. 366 // condition on the join column being NULL as before.
367 std::string withName = instantiateWith(clause.getField().getTable()); 367 std::string withName = instantiateWith(clause.getField().getTable());
368 std::string withInstName = instantiateTable(withName); 368 std::string withInstName = instantiateTable(withName);
369 369
370 // LEFT JOIN against the CTE. 370 // LEFT JOIN against the CTE.
371 joins_.emplace_back( 371 joins_.emplace_back(
372 true, 372 true,
@@ -375,7 +375,7 @@ namespace verbly {
375 clause.getField().getColumn(), 375 clause.getField().getColumn(),
376 withInstName, 376 withInstName,
377 clause.getField().getJoinColumn()); 377 clause.getField().getJoinColumn());
378 378
379 // Modify the substatement such that the through table is the top 379 // Modify the substatement such that the through table is the top
380 // table, and such that it joins against the previous top table. 380 // table, and such that it joins against the previous top table.
381 std::string throughTable = joinStmt.instantiateTable(clause.getField().getTable()); 381 std::string throughTable = joinStmt.instantiateTable(clause.getField().getTable());
@@ -386,7 +386,7 @@ namespace verbly {
386 clause.getField().getForeignJoinColumn(), 386 clause.getField().getForeignJoinColumn(),
387 std::move(joinTable), 387 std::move(joinTable),
388 clause.getField().getForeignColumn()); 388 clause.getField().getForeignColumn());
389 389
390 joinStmt.topTable_ = throughTable; 390 joinStmt.topTable_ = throughTable;
391 391
392 // All CTEs have to be in the main statement, so integrate any 392 // All CTEs have to be in the main statement, so integrate any
@@ -396,7 +396,7 @@ namespace verbly {
396 std::map<std::string, std::string> cteTables = std::move(joinStmt.tables_); 396 std::map<std::string, std::string> cteTables = std::move(joinStmt.tables_);
397 std::list<join> cteJoins = std::move(joinStmt.joins_); 397 std::list<join> cteJoins = std::move(joinStmt.joins_);
398 condition cteCondition = integrate(std::move(joinStmt), true); 398 condition cteCondition = integrate(std::move(joinStmt), true);
399 399
400 withs_.emplace_back( 400 withs_.emplace_back(
401 std::move(withName), 401 std::move(withName),
402 clause.getField(), 402 clause.getField(),
@@ -405,14 +405,14 @@ namespace verbly {
405 std::move(cteCondition), 405 std::move(cteCondition),
406 std::move(cteJoins), 406 std::move(cteJoins),
407 false); 407 false);
408 408
409 // Condition on the join column being NULL, which causes the query 409 // Condition on the join column being NULL, which causes the query
410 // to only return results that do not match the subquery. 410 // to only return results that do not match the subquery.
411 return condition(std::move(withInstName), clause.getField().getJoinColumn(), true); 411 return condition(std::move(withInstName), clause.getField().getJoinColumn(), true);
412 } else { 412 } else {
413 // Instantiate the through table. 413 // Instantiate the through table.
414 std::string throughTable = instantiateTable(clause.getField().getTable()); 414 std::string throughTable = instantiateTable(clause.getField().getTable());
415 415
416 // INNER JOIN against the through table. 416 // INNER JOIN against the through table.
417 joins_.emplace_back( 417 joins_.emplace_back(
418 false, 418 false,
@@ -421,7 +421,7 @@ namespace verbly {
421 clause.getField().getColumn(), 421 clause.getField().getColumn(),
422 throughTable, 422 throughTable,
423 clause.getField().getJoinColumn()); 423 clause.getField().getJoinColumn());
424 424
425 // INNER JOIN from the through table to the top table of the subquery. 425 // INNER JOIN from the through table to the top table of the subquery.
426 joins_.emplace_back( 426 joins_.emplace_back(
427 false, 427 false,
@@ -430,20 +430,20 @@ namespace verbly {
430 clause.getField().getForeignJoinColumn(), 430 clause.getField().getForeignJoinColumn(),
431 std::move(joinTable), 431 std::move(joinTable),
432 clause.getField().getForeignColumn()); 432 clause.getField().getForeignColumn());
433 433
434 // Integrate the subquery's table mappings, joins, and CTEs into 434 // Integrate the subquery's table mappings, joins, and CTEs into
435 // this statement, and return the subquery condition as our 435 // this statement, and return the subquery condition as our
436 // condition. 436 // condition.
437 return integrate(std::move(joinStmt)); 437 return integrate(std::move(joinStmt));
438 } 438 }
439 } 439 }
440 440
441 case field::type::hierarchal_join: 441 case field::type::hierarchal_join:
442 { 442 {
443 // Create a recursive CTE that represents the results of the subquery. 443 // Create a recursive CTE that represents the results of the subquery.
444 std::string withName = instantiateWith(clause.getField().getTable()); 444 std::string withName = instantiateWith(clause.getField().getTable());
445 std::string withInstName = instantiateTable(withName); 445 std::string withInstName = instantiateTable(withName);
446 446
447 // If we are matching against the subquery, we INNER JOIN with the 447 // If we are matching against the subquery, we INNER JOIN with the
448 // CTE. If we are negatively matching the subquery, we LEFT JOIN 448 // CTE. If we are negatively matching the subquery, we LEFT JOIN
449 // with the CTE. 449 // with the CTE.
@@ -452,7 +452,7 @@ namespace verbly {
452 { 452 {
453 outer = true; 453 outer = true;
454 } 454 }
455 455
456 // Join against the CTE. 456 // Join against the CTE.
457 joins_.emplace_back( 457 joins_.emplace_back(
458 outer, 458 outer,
@@ -461,14 +461,14 @@ namespace verbly {
461 clause.getField().getColumn(), 461 clause.getField().getColumn(),
462 withInstName, 462 withInstName,
463 clause.getField().getColumn()); 463 clause.getField().getColumn());
464 464
465 // Recursively parse the subquery in order to create the CTE. 465 // Recursively parse the subquery in order to create the CTE.
466 statement withStmt( 466 statement withStmt(
467 getTableForContext(clause.getField().getObject()), 467 getTableForContext(clause.getField().getObject()),
468 clause.getJoinCondition().normalize(clause.getField().getObject()), 468 clause.getJoinCondition().normalize(clause.getField().getObject()),
469 nextTableId_, 469 nextTableId_,
470 nextWithId_); 470 nextWithId_);
471 471
472 // All CTEs have to be in the main statement, so integrate any CTEs 472 // All CTEs have to be in the main statement, so integrate any CTEs
473 // that our subquery uses. Also, retrieve the table mapping, joins 473 // that our subquery uses. Also, retrieve the table mapping, joins
474 // list, and subquery condition, and use them to create the CTE. 474 // list, and subquery condition, and use them to create the CTE.
@@ -476,7 +476,7 @@ namespace verbly {
476 std::map<std::string, std::string> cteTables = std::move(withStmt.tables_); 476 std::map<std::string, std::string> cteTables = std::move(withStmt.tables_);
477 std::list<join> cteJoins = std::move(withStmt.joins_); 477 std::list<join> cteJoins = std::move(withStmt.joins_);
478 condition cteCondition = integrate(std::move(withStmt), true); 478 condition cteCondition = integrate(std::move(withStmt), true);
479 479
480 withs_.emplace_back( 480 withs_.emplace_back(
481 std::move(withName), 481 std::move(withName),
482 clause.getField(), 482 clause.getField(),
@@ -498,11 +498,11 @@ namespace verbly {
498 } 498 }
499 } 499 }
500 } 500 }
501 501
502 case filter::type::group: 502 case filter::type::group:
503 { 503 {
504 condition grp(clause.getOrlogic()); 504 condition grp(clause.getOrlogic());
505 505
506 for (const filter& child : clause) 506 for (const filter& child : clause)
507 { 507 {
508 condition newChild = parseFilter(child); 508 condition newChild = parseFilter(child);
@@ -511,30 +511,30 @@ namespace verbly {
511 grp += std::move(newChild); 511 grp += std::move(newChild);
512 } 512 }
513 } 513 }
514 514
515 if (grp.getChildren().empty()) 515 if (grp.getChildren().empty())
516 { 516 {
517 grp = {}; 517 grp = {};
518 } 518 }
519 519
520 return grp; 520 return grp;
521 } 521 }
522 } 522 }
523 } 523 }
524 524
525 std::string statement::instantiateTable(std::string name) 525 std::string statement::instantiateTable(std::string name)
526 { 526 {
527 std::string identifier = name + "_" + std::to_string(nextTableId_++); 527 std::string identifier = name + "_" + std::to_string(nextTableId_++);
528 tables_[identifier] = name; 528 tables_[identifier] = name;
529 529
530 return identifier; 530 return identifier;
531 } 531 }
532 532
533 std::string statement::instantiateWith(std::string name) 533 std::string statement::instantiateWith(std::string name)
534 { 534 {
535 return name + "_tree_" + std::to_string(nextWithId_++); 535 return name + "_tree_" + std::to_string(nextWithId_++);
536 } 536 }
537 537
538 /** 538 /**
539 * This method integrates the parts of a recursively generated statement into 539 * This method integrates the parts of a recursively generated statement into
540 * this statement. This is used because filters are recursive objects, but 540 * this statement. This is used because filters are recursive objects, but
@@ -551,13 +551,13 @@ namespace verbly {
551 { 551 {
552 tables_[mapping.first] = mapping.second; 552 tables_[mapping.first] = mapping.second;
553 } 553 }
554 554
555 for (auto& j : subStmt.joins_) 555 for (auto& j : subStmt.joins_)
556 { 556 {
557 joins_.push_back(j); 557 joins_.push_back(j);
558 } 558 }
559 } 559 }
560 560
561 for (auto& w : subStmt.withs_) 561 for (auto& w : subStmt.withs_)
562 { 562 {
563 withs_.push_back(w); 563 withs_.push_back(w);
@@ -565,10 +565,10 @@ namespace verbly {
565 565
566 nextTableId_ = subStmt.nextTableId_; 566 nextTableId_ = subStmt.nextTableId_;
567 nextWithId_ = subStmt.nextWithId_; 567 nextWithId_ = subStmt.nextWithId_;
568 568
569 return subStmt.topCondition_; 569 return subStmt.topCondition_;
570 } 570 }
571 571
572 std::ostream& operator<<(std::ostream& oss, const statement::join& j) 572 std::ostream& operator<<(std::ostream& oss, const statement::join& j)
573 { 573 {
574 if (j.isOuterJoin()) 574 if (j.isOuterJoin())
@@ -577,7 +577,7 @@ namespace verbly {
577 } else { 577 } else {
578 oss << "INNER"; 578 oss << "INNER";
579 } 579 }
580 580
581 return oss 581 return oss
582 << " JOIN " 582 << " JOIN "
583 << j.getForeignTableName() 583 << j.getForeignTableName()
@@ -592,55 +592,55 @@ namespace verbly {
592 << "." 592 << "."
593 << j.getJoinColumn(); 593 << j.getJoinColumn();
594 } 594 }
595 595
596 statement::condition::condition(const condition& other) 596 statement::condition::condition(const condition& other)
597 { 597 {
598 type_ = other.type_; 598 type_ = other.type_;
599 599
600 switch (type_) 600 switch (type_)
601 { 601 {
602 case type::empty: 602 case type::empty:
603 { 603 {
604 break; 604 break;
605 } 605 }
606 606
607 case type::singleton: 607 case type::singleton:
608 { 608 {
609 new(&singleton_.table_) std::string(other.singleton_.table_); 609 new(&singleton_.table_) std::string(other.singleton_.table_);
610 new(&singleton_.column_) std::string(other.singleton_.column_); 610 new(&singleton_.column_) std::string(other.singleton_.column_);
611 singleton_.comparison_ = other.singleton_.comparison_; 611 singleton_.comparison_ = other.singleton_.comparison_;
612 new(&singleton_.value_) binding(other.singleton_.value_); 612 new(&singleton_.value_) binding(other.singleton_.value_);
613 613
614 break; 614 break;
615 } 615 }
616 616
617 case type::group: 617 case type::group:
618 { 618 {
619 new(&group_.children_) std::list<condition>(other.group_.children_); 619 new(&group_.children_) std::list<condition>(other.group_.children_);
620 group_.orlogic_ = other.group_.orlogic_; 620 group_.orlogic_ = other.group_.orlogic_;
621 621
622 break; 622 break;
623 } 623 }
624 } 624 }
625 } 625 }
626 626
627 statement::condition::condition(condition&& other) : condition() 627 statement::condition::condition(condition&& other) : condition()
628 { 628 {
629 swap(*this, other); 629 swap(*this, other);
630 } 630 }
631 631
632 statement::condition& statement::condition::operator=(condition other) 632 statement::condition& statement::condition::operator=(condition other)
633 { 633 {
634 swap(*this, other); 634 swap(*this, other);
635 635
636 return *this; 636 return *this;
637 } 637 }
638 638
639 void swap(statement::condition& first, statement::condition& second) 639 void swap(statement::condition& first, statement::condition& second)
640 { 640 {
641 using type = statement::condition::type; 641 using type = statement::condition::type;
642 using condition = statement::condition; 642 using condition = statement::condition;
643 643
644 type tempType = first.type_; 644 type tempType = first.type_;
645 std::string tempTable; 645 std::string tempTable;
646 std::string tempColumn; 646 std::string tempColumn;
@@ -648,94 +648,94 @@ namespace verbly {
648 binding tempBinding; 648 binding tempBinding;
649 std::list<condition> tempChildren; 649 std::list<condition> tempChildren;
650 bool tempOrlogic; 650 bool tempOrlogic;
651 651
652 switch (tempType) 652 switch (tempType)
653 { 653 {
654 case type::empty: 654 case type::empty:
655 { 655 {
656 break; 656 break;
657 } 657 }
658 658
659 case type::singleton: 659 case type::singleton:
660 { 660 {
661 tempTable = std::move(first.singleton_.table_); 661 tempTable = std::move(first.singleton_.table_);
662 tempColumn = std::move(first.singleton_.column_); 662 tempColumn = std::move(first.singleton_.column_);
663 tempComparison = first.singleton_.comparison_; 663 tempComparison = first.singleton_.comparison_;
664 tempBinding = std::move(first.singleton_.value_); 664 tempBinding = std::move(first.singleton_.value_);
665 665
666 break; 666 break;
667 } 667 }
668 668
669 case type::group: 669 case type::group:
670 { 670 {
671 tempChildren = std::move(first.group_.children_); 671 tempChildren = std::move(first.group_.children_);
672 tempOrlogic = first.group_.orlogic_; 672 tempOrlogic = first.group_.orlogic_;
673 673
674 break; 674 break;
675 } 675 }
676 } 676 }
677 677
678 first.~condition(); 678 first.~condition();
679 679
680 first.type_ = second.type_; 680 first.type_ = second.type_;
681 681
682 switch (first.type_) 682 switch (first.type_)
683 { 683 {
684 case type::empty: 684 case type::empty:
685 { 685 {
686 break; 686 break;
687 } 687 }
688 688
689 case type::singleton: 689 case type::singleton:
690 { 690 {
691 new(&first.singleton_.table_) std::string(std::move(second.singleton_.table_)); 691 new(&first.singleton_.table_) std::string(std::move(second.singleton_.table_));
692 new(&first.singleton_.column_) std::string(std::move(second.singleton_.column_)); 692 new(&first.singleton_.column_) std::string(std::move(second.singleton_.column_));
693 first.singleton_.comparison_ = second.singleton_.comparison_; 693 first.singleton_.comparison_ = second.singleton_.comparison_;
694 new(&first.singleton_.value_) binding(std::move(second.singleton_.value_)); 694 new(&first.singleton_.value_) binding(std::move(second.singleton_.value_));
695 695
696 break; 696 break;
697 } 697 }
698 698
699 case type::group: 699 case type::group:
700 { 700 {
701 new(&first.group_.children_) std::list<condition>(std::move(second.group_.children_)); 701 new(&first.group_.children_) std::list<condition>(std::move(second.group_.children_));
702 first.group_.orlogic_ = second.group_.orlogic_; 702 first.group_.orlogic_ = second.group_.orlogic_;
703 703
704 break; 704 break;
705 } 705 }
706 } 706 }
707 707
708 second.~condition(); 708 second.~condition();
709 709
710 second.type_ = tempType; 710 second.type_ = tempType;
711 711
712 switch (second.type_) 712 switch (second.type_)
713 { 713 {
714 case type::empty: 714 case type::empty:
715 { 715 {
716 break; 716 break;
717 } 717 }
718 718
719 case type::singleton: 719 case type::singleton:
720 { 720 {
721 new(&second.singleton_.table_) std::string(std::move(tempTable)); 721 new(&second.singleton_.table_) std::string(std::move(tempTable));
722 new(&second.singleton_.column_) std::string(std::move(tempColumn)); 722 new(&second.singleton_.column_) std::string(std::move(tempColumn));
723 second.singleton_.comparison_ = tempComparison; 723 second.singleton_.comparison_ = tempComparison;
724 new(&second.singleton_.value_) binding(std::move(tempBinding)); 724 new(&second.singleton_.value_) binding(std::move(tempBinding));
725 725
726 break; 726 break;
727 } 727 }
728 728
729 case type::group: 729 case type::group:
730 { 730 {
731 new(&second.group_.children_) std::list<condition>(std::move(tempChildren)); 731 new(&second.group_.children_) std::list<condition>(std::move(tempChildren));
732 second.group_.orlogic_ = tempOrlogic; 732 second.group_.orlogic_ = tempOrlogic;
733 733
734 break; 734 break;
735 } 735 }
736 } 736 }
737 } 737 }
738 738
739 statement::condition::~condition() 739 statement::condition::~condition()
740 { 740 {
741 switch (type_) 741 switch (type_)
@@ -744,33 +744,33 @@ namespace verbly {
744 { 744 {
745 break; 745 break;
746 } 746 }
747 747
748 case type::singleton: 748 case type::singleton:
749 { 749 {
750 using string_type = std::string; 750 using string_type = std::string;
751 751
752 singleton_.table_.~string_type(); 752 singleton_.table_.~string_type();
753 singleton_.column_.~string_type(); 753 singleton_.column_.~string_type();
754 singleton_.value_.~binding(); 754 singleton_.value_.~binding();
755 755
756 break; 756 break;
757 } 757 }
758 758
759 case type::group: 759 case type::group:
760 { 760 {
761 using list_type = std::list<condition>; 761 using list_type = std::list<condition>;
762 762
763 group_.children_.~list_type(); 763 group_.children_.~list_type();
764 764
765 break; 765 break;
766 } 766 }
767 } 767 }
768 } 768 }
769 769
770 statement::condition::condition() : type_(type::empty) 770 statement::condition::condition() : type_(type::empty)
771 { 771 {
772 } 772 }
773 773
774 statement::condition::condition( 774 statement::condition::condition(
775 std::string table, 775 std::string table,
776 std::string column, 776 std::string column,
@@ -779,7 +779,7 @@ namespace verbly {
779 { 779 {
780 new(&singleton_.table_) std::string(std::move(table)); 780 new(&singleton_.table_) std::string(std::move(table));
781 new(&singleton_.column_) std::string(std::move(column)); 781 new(&singleton_.column_) std::string(std::move(column));
782 782
783 if (isNull) 783 if (isNull)
784 { 784 {
785 singleton_.comparison_ = comparison::is_null; 785 singleton_.comparison_ = comparison::is_null;
@@ -787,7 +787,7 @@ namespace verbly {
787 singleton_.comparison_ = comparison::is_not_null; 787 singleton_.comparison_ = comparison::is_not_null;
788 } 788 }
789 } 789 }
790 790
791 statement::condition::condition( 791 statement::condition::condition(
792 std::string table, 792 std::string table,
793 std::string column, 793 std::string column,
@@ -800,7 +800,7 @@ namespace verbly {
800 singleton_.comparison_ = comp; 800 singleton_.comparison_ = comp;
801 new(&singleton_.value_) binding(std::move(value)); 801 new(&singleton_.value_) binding(std::move(value));
802 } 802 }
803 803
804 std::string statement::condition::toSql() const 804 std::string statement::condition::toSql() const
805 { 805 {
806 switch (type_) 806 switch (type_)
@@ -809,7 +809,7 @@ namespace verbly {
809 { 809 {
810 return ""; 810 return "";
811 } 811 }
812 812
813 case type::singleton: 813 case type::singleton:
814 { 814 {
815 switch (singleton_.comparison_) 815 switch (singleton_.comparison_)
@@ -818,54 +818,54 @@ namespace verbly {
818 { 818 {
819 return singleton_.table_ + "." + singleton_.column_ + " = ?"; 819 return singleton_.table_ + "." + singleton_.column_ + " = ?";
820 } 820 }
821 821
822 case comparison::does_not_equal: 822 case comparison::does_not_equal:
823 { 823 {
824 return singleton_.table_ + "." + singleton_.column_ + " != ?"; 824 return singleton_.table_ + "." + singleton_.column_ + " != ?";
825 } 825 }
826 826
827 case comparison::is_greater_than: 827 case comparison::is_greater_than:
828 { 828 {
829 return singleton_.table_ + "." + singleton_.column_ + " > ?"; 829 return singleton_.table_ + "." + singleton_.column_ + " > ?";
830 } 830 }
831 831
832 case comparison::is_at_most: 832 case comparison::is_at_most:
833 { 833 {
834 return singleton_.table_ + "." + singleton_.column_ + " <= ?"; 834 return singleton_.table_ + "." + singleton_.column_ + " <= ?";
835 } 835 }
836 836
837 case comparison::is_less_than: 837 case comparison::is_less_than:
838 { 838 {
839 return singleton_.table_ + "." + singleton_.column_ + " < ?"; 839 return singleton_.table_ + "." + singleton_.column_ + " < ?";
840 } 840 }
841 841
842 case comparison::is_at_least: 842 case comparison::is_at_least:
843 { 843 {
844 return singleton_.table_ + "." + singleton_.column_ + " >= ?"; 844 return singleton_.table_ + "." + singleton_.column_ + " >= ?";
845 } 845 }
846 846
847 case comparison::is_like: 847 case comparison::is_like:
848 { 848 {
849 return singleton_.table_ + "." + singleton_.column_ + " LIKE ?"; 849 return singleton_.table_ + "." + singleton_.column_ + " LIKE ?";
850 } 850 }
851 851
852 case comparison::is_not_like: 852 case comparison::is_not_like:
853 { 853 {
854 return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE ?"; 854 return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE ?";
855 } 855 }
856 856
857 case comparison::is_not_null: 857 case comparison::is_not_null:
858 { 858 {
859 return singleton_.table_ + "." + singleton_.column_ + " IS NOT NULL"; 859 return singleton_.table_ + "." + singleton_.column_ + " IS NOT NULL";
860 } 860 }
861 861
862 case comparison::is_null: 862 case comparison::is_null:
863 { 863 {
864 return singleton_.table_ + "." + singleton_.column_ + " IS NULL"; 864 return singleton_.table_ + "." + singleton_.column_ + " IS NULL";
865 } 865 }
866 } 866 }
867 } 867 }
868 868
869 case type::group: 869 case type::group:
870 { 870 {
871 std::list<std::string> clauses; 871 std::list<std::string> clauses;
@@ -873,12 +873,12 @@ namespace verbly {
873 { 873 {
874 clauses.push_back(cond.toSql()); 874 clauses.push_back(cond.toSql());
875 } 875 }
876 876
877 return implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND "); 877 return implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND ");
878 } 878 }
879 } 879 }
880 } 880 }
881 881
882 std::list<binding> statement::condition::flattenBindings() const 882 std::list<binding> statement::condition::flattenBindings() const
883 { 883 {
884 switch (type_) 884 switch (type_)
@@ -887,7 +887,7 @@ namespace verbly {
887 { 887 {
888 return {}; 888 return {};
889 } 889 }
890 890
891 case type::singleton: 891 case type::singleton:
892 { 892 {
893 switch (singleton_.comparison_) 893 switch (singleton_.comparison_)
@@ -903,7 +903,7 @@ namespace verbly {
903 { 903 {
904 return {singleton_.value_}; 904 return {singleton_.value_};
905 } 905 }
906 906
907 case comparison::is_not_null: 907 case comparison::is_not_null:
908 case comparison::is_null: 908 case comparison::is_null:
909 { 909 {
@@ -911,7 +911,7 @@ namespace verbly {
911 } 911 }
912 } 912 }
913 } 913 }
914 914
915 case type::group: 915 case type::group:
916 { 916 {
917 std::list<binding> bindings; 917 std::list<binding> bindings;
@@ -922,30 +922,30 @@ namespace verbly {
922 bindings.push_back(std::move(value)); 922 bindings.push_back(std::move(value));
923 } 923 }
924 } 924 }
925 925
926 return bindings; 926 return bindings;
927 } 927 }
928 } 928 }
929 } 929 }
930 930
931 statement::condition::condition(bool orlogic) : type_(type::group) 931 statement::condition::condition(bool orlogic) : type_(type::group)
932 { 932 {
933 new(&group_.children_) std::list<condition>(); 933 new(&group_.children_) std::list<condition>();
934 group_.orlogic_ = orlogic; 934 group_.orlogic_ = orlogic;
935 } 935 }
936 936
937 statement::condition& statement::condition::operator+=(condition n) 937 statement::condition& statement::condition::operator+=(condition n)
938 { 938 {
939 if (type_ == type::group) 939 if (type_ == type::group)
940 { 940 {
941 group_.children_.push_back(std::move(n)); 941 group_.children_.push_back(std::move(n));
942 942
943 return *this; 943 return *this;
944 } else { 944 } else {
945 throw std::domain_error("Cannot add condition to non-group condition"); 945 throw std::domain_error("Cannot add condition to non-group condition");
946 } 946 }
947 } 947 }
948 948
949 statement::condition& statement::condition::operator&=(condition n) 949 statement::condition& statement::condition::operator&=(condition n)
950 { 950 {
951 switch (type_) 951 switch (type_)
@@ -953,32 +953,32 @@ namespace verbly {
953 case type::empty: 953 case type::empty:
954 { 954 {
955 *this = std::move(n); 955 *this = std::move(n);
956 956
957 break; 957 break;
958 } 958 }
959 959
960 case type::singleton: 960 case type::singleton:
961 { 961 {
962 condition grp(false); 962 condition grp(false);
963 grp += *this; 963 grp += *this;
964 grp += std::move(n); 964 grp += std::move(n);
965 965
966 *this = grp; 966 *this = grp;
967 967
968 break; 968 break;
969 } 969 }
970 970
971 case type::group: 971 case type::group:
972 { 972 {
973 *this += std::move(n); 973 *this += std::move(n);
974 974
975 break; 975 break;
976 } 976 }
977 } 977 }
978 978
979 return *this; 979 return *this;
980 } 980 }
981 981
982 const std::list<statement::condition>& statement::condition::getChildren() const 982 const std::list<statement::condition>& statement::condition::getChildren() const
983 { 983 {
984 if (type_ == type::group) 984 if (type_ == type::group)
@@ -988,5 +988,5 @@ namespace verbly {
988 throw std::domain_error("Cannot get children of non-group condition"); 988 throw std::domain_error("Cannot get children of non-group condition");
989 } 989 }
990 } 990 }
991 991
992}; 992};
diff --git a/lib/statement.h b/lib/statement.h index 8188ec0..aa56568 100644 --- a/lib/statement.h +++ b/lib/statement.h
@@ -11,23 +11,23 @@
11#include "filter.h" 11#include "filter.h"
12 12
13namespace verbly { 13namespace verbly {
14 14
15 class filter; 15 class filter;
16 16
17 class statement { 17 class statement {
18 public: 18 public:
19 19
20 statement(object context, filter queryFilter); 20 statement(object context, filter queryFilter);
21 21
22 std::string getQueryString(std::list<std::string> select, bool random, int limit) const; 22 std::string getQueryString(std::list<std::string> select, bool random, int limit) const;
23 23
24 std::list<binding> getBindings() const; 24 std::list<binding> getBindings() const;
25 25
26 private: 26 private:
27 27
28 class join { 28 class join {
29 public: 29 public:
30 30
31 join( 31 join(
32 bool outer, 32 bool outer,
33 std::string foreignTableName, 33 std::string foreignTableName,
@@ -43,37 +43,37 @@ namespace verbly {
43 foreignColumn_(std::move(foreignColumn)) 43 foreignColumn_(std::move(foreignColumn))
44 { 44 {
45 } 45 }
46 46
47 bool isOuterJoin() const 47 bool isOuterJoin() const
48 { 48 {
49 return outer_; 49 return outer_;
50 } 50 }
51 51
52 const std::string& getForeignTableName() const 52 const std::string& getForeignTableName() const
53 { 53 {
54 return foreignTableName_; 54 return foreignTableName_;
55 } 55 }
56 56
57 const std::string& getJoinTable() const 57 const std::string& getJoinTable() const
58 { 58 {
59 return joinTable_; 59 return joinTable_;
60 } 60 }
61 61
62 const std::string& getJoinColumn() const 62 const std::string& getJoinColumn() const
63 { 63 {
64 return joinColumn_; 64 return joinColumn_;
65 } 65 }
66 66
67 const std::string& getForeignTable() const 67 const std::string& getForeignTable() const
68 { 68 {
69 return foreignTable_; 69 return foreignTable_;
70 } 70 }
71 71
72 const std::string& getForeignColumn() const 72 const std::string& getForeignColumn() const
73 { 73 {
74 return foreignColumn_; 74 return foreignColumn_;
75 } 75 }
76 76
77 private: 77 private:
78 bool outer_ = false; 78 bool outer_ = false;
79 std::string foreignTableName_; 79 std::string foreignTableName_;
@@ -81,11 +81,11 @@ namespace verbly {
81 std::string joinColumn_; 81 std::string joinColumn_;
82 std::string foreignTable_; 82 std::string foreignTable_;
83 std::string foreignColumn_; 83 std::string foreignColumn_;
84 84
85 }; 85 };
86 86
87 friend std::ostream& operator<<(std::ostream& oss, const join& j); 87 friend std::ostream& operator<<(std::ostream& oss, const join& j);
88 88
89 class condition { 89 class condition {
90 public: 90 public:
91 enum class type { 91 enum class type {
@@ -93,7 +93,7 @@ namespace verbly {
93 singleton, 93 singleton,
94 group 94 group
95 }; 95 };
96 96
97 enum class comparison { 97 enum class comparison {
98 equals, 98 equals,
99 does_not_equal, 99 does_not_equal,
@@ -106,57 +106,57 @@ namespace verbly {
106 is_not_null, 106 is_not_null,
107 is_null 107 is_null
108 }; 108 };
109 109
110 // Copy and move constructors 110 // Copy and move constructors
111 111
112 condition(const condition& other); 112 condition(const condition& other);
113 condition(condition&& other); 113 condition(condition&& other);
114 114
115 // Assignment 115 // Assignment
116 116
117 condition& operator=(condition other); 117 condition& operator=(condition other);
118 118
119 // Swap 119 // Swap
120 120
121 friend void swap(condition& first, condition& second); 121 friend void swap(condition& first, condition& second);
122 122
123 // Destructor 123 // Destructor
124 124
125 ~condition(); 125 ~condition();
126 126
127 // Accessors 127 // Accessors
128 128
129 type getType() const 129 type getType() const
130 { 130 {
131 return type_; 131 return type_;
132 } 132 }
133 133
134 // Empty 134 // Empty
135 135
136 condition(); 136 condition();
137 137
138 // Singleton 138 // Singleton
139 139
140 condition(std::string table, std::string column, bool isNull); 140 condition(std::string table, std::string column, bool isNull);
141 141
142 condition(std::string table, std::string column, comparison comp, binding value); 142 condition(std::string table, std::string column, comparison comp, binding value);
143 143
144 // Group 144 // Group
145 145
146 explicit condition(bool orlogic); 146 explicit condition(bool orlogic);
147 147
148 condition& operator+=(condition n); 148 condition& operator+=(condition n);
149 149
150 condition& operator&=(condition n); 150 condition& operator&=(condition n);
151 151
152 const std::list<condition>& getChildren() const; 152 const std::list<condition>& getChildren() const;
153 153
154 // Utility 154 // Utility
155 155
156 std::string toSql() const; 156 std::string toSql() const;
157 157
158 std::list<binding> flattenBindings() const; 158 std::list<binding> flattenBindings() const;
159 159
160 private: 160 private:
161 union { 161 union {
162 struct { 162 struct {
@@ -172,12 +172,12 @@ namespace verbly {
172 }; 172 };
173 type type_; 173 type type_;
174 }; 174 };
175 175
176 friend void swap(condition& first, condition& second); 176 friend void swap(condition& first, condition& second);
177 177
178 class with { 178 class with {
179 public: 179 public:
180 180
181 with( 181 with(
182 std::string identifier, 182 std::string identifier,
183 field f, 183 field f,
@@ -195,42 +195,42 @@ namespace verbly {
195 recursive_(recursive) 195 recursive_(recursive)
196 { 196 {
197 } 197 }
198 198
199 const std::string& getIdentifier() const 199 const std::string& getIdentifier() const
200 { 200 {
201 return identifier_; 201 return identifier_;
202 } 202 }
203 203
204 field getField() const 204 field getField() const
205 { 205 {
206 return field_; 206 return field_;
207 } 207 }
208 208
209 std::string getTableForId(std::string identifier) const 209 std::string getTableForId(std::string identifier) const
210 { 210 {
211 return tables_.at(identifier); 211 return tables_.at(identifier);
212 } 212 }
213 213
214 const std::string& getTopTable() const 214 const std::string& getTopTable() const
215 { 215 {
216 return topTable_; 216 return topTable_;
217 } 217 }
218 218
219 const condition& getCondition() const 219 const condition& getCondition() const
220 { 220 {
221 return topCondition_; 221 return topCondition_;
222 } 222 }
223 223
224 const std::list<join>& getJoins() const 224 const std::list<join>& getJoins() const
225 { 225 {
226 return joins_; 226 return joins_;
227 } 227 }
228 228
229 bool isRecursive() const 229 bool isRecursive() const
230 { 230 {
231 return recursive_; 231 return recursive_;
232 } 232 }
233 233
234 private: 234 private:
235 std::string identifier_; 235 std::string identifier_;
236 field field_; 236 field field_;
@@ -239,9 +239,9 @@ namespace verbly {
239 condition topCondition_; 239 condition topCondition_;
240 std::list<join> joins_; 240 std::list<join> joins_;
241 bool recursive_; 241 bool recursive_;
242 242
243 }; 243 };
244 244
245 static constexpr const char* getTableForContext(object context) 245 static constexpr const char* getTableForContext(object context)
246 { 246 {
247 return (context == object::notion) ? "notions" 247 return (context == object::notion) ? "notions"
@@ -253,22 +253,22 @@ namespace verbly {
253 : (context == object::pronunciation) ? "pronunciations" 253 : (context == object::pronunciation) ? "pronunciations"
254 : throw std::domain_error("Provided context has no associated table"); 254 : throw std::domain_error("Provided context has no associated table");
255 } 255 }
256 256
257 static const std::list<field> getSelectForContext(object context); 257 static const std::list<field> getSelectForContext(object context);
258 258
259 statement(std::string tableName, filter clause, int nextTableId = 0, int nextWithId = 0); 259 statement(std::string tableName, filter clause, int nextTableId = 0, int nextWithId = 0);
260 260
261 condition parseFilter(filter queryFilter); 261 condition parseFilter(filter queryFilter);
262 262
263 std::string instantiateTable(std::string name); 263 std::string instantiateTable(std::string name);
264 264
265 std::string instantiateWith(std::string name); 265 std::string instantiateWith(std::string name);
266 266
267 condition integrate(statement subStmt, bool cte = false); 267 condition integrate(statement subStmt, bool cte = false);
268 268
269 int nextTableId_; 269 int nextTableId_;
270 int nextWithId_; 270 int nextWithId_;
271 271
272 std::map<std::string, std::string> tables_; 272 std::map<std::string, std::string> tables_;
273 std::string topTable_; 273 std::string topTable_;
274 std::list<join> joins_; 274 std::list<join> joins_;
@@ -276,7 +276,7 @@ namespace verbly {
276 condition topCondition_; 276 condition topCondition_;
277 277
278 }; 278 };
279 279
280}; 280};
281 281
282#endif /* end of include guard: STATEMENT_H_29F51659 */ 282#endif /* end of include guard: STATEMENT_H_29F51659 */
diff --git a/lib/util.h b/lib/util.h index b74b050..9db8678 100644 --- a/lib/util.h +++ b/lib/util.h
@@ -6,25 +6,25 @@
6#include <iterator> 6#include <iterator>
7 7
8namespace verbly { 8namespace verbly {
9 9
10 template <class InputIterator> 10 template <class InputIterator>
11 std::string implode(InputIterator first, InputIterator last, std::string delimiter) 11 std::string implode(InputIterator first, InputIterator last, std::string delimiter)
12 { 12 {
13 std::stringstream result; 13 std::stringstream result;
14 14
15 for (InputIterator it = first; it != last; it++) 15 for (InputIterator it = first; it != last; it++)
16 { 16 {
17 if (it != first) 17 if (it != first)
18 { 18 {
19 result << delimiter; 19 result << delimiter;
20 } 20 }
21 21
22 result << *it; 22 result << *it;
23 } 23 }
24 24
25 return result.str(); 25 return result.str();
26 } 26 }
27 27
28 template <class OutputIterator> 28 template <class OutputIterator>
29 void split(std::string input, std::string delimiter, OutputIterator out) 29 void split(std::string input, std::string delimiter, OutputIterator out)
30 { 30 {
@@ -35,27 +35,27 @@ namespace verbly {
35 { 35 {
36 *out = input; 36 *out = input;
37 out++; 37 out++;
38 38
39 input = ""; 39 input = "";
40 } else { 40 } else {
41 *out = input.substr(0, divider); 41 *out = input.substr(0, divider);
42 out++; 42 out++;
43 43
44 input = input.substr(divider+delimiter.length()); 44 input = input.substr(divider+delimiter.length());
45 } 45 }
46 } 46 }
47 } 47 }
48 48
49 template <class Container> 49 template <class Container>
50 Container split(std::string input, std::string delimiter) 50 Container split(std::string input, std::string delimiter)
51 { 51 {
52 Container result; 52 Container result;
53 53
54 split(input, delimiter, std::back_inserter(result)); 54 split(input, delimiter, std::back_inserter(result));
55 55
56 return result; 56 return result;
57 } 57 }
58 58
59}; 59};
60 60
61#endif /* end of include guard: UTIL_H_15DDCA2D */ 61#endif /* end of include guard: UTIL_H_15DDCA2D */
diff --git a/lib/word.cpp b/lib/word.cpp index d13d0bc..a928659 100644 --- a/lib/word.cpp +++ b/lib/word.cpp
@@ -6,118 +6,118 @@
6#include "query.h" 6#include "query.h"
7 7
8namespace verbly { 8namespace verbly {
9 9
10 const object word::objectType = object::word; 10 const object word::objectType = object::word;
11 11
12 const std::list<std::string> word::select = {"word_id", "notion_id", "lemma_id", "tag_count", "position", "group_id"}; 12 const std::list<std::string> word::select = {"word_id", "notion_id", "lemma_id", "tag_count", "position", "group_id"};
13 13
14 const field word::id = field::integerField(object::word, "word_id"); 14 const field word::id = field::integerField(object::word, "word_id");
15 const field word::tagCount = field::integerField(object::word, "tag_count", true); 15 const field word::tagCount = field::integerField(object::word, "tag_count", true);
16 const field word::adjectivePosition = field::integerField(object::word, "position", true); 16 const field word::adjectivePosition = field::integerField(object::word, "position", true);
17 17
18 const field word::notion = field::joinField(object::word, "notion_id", object::notion); 18 const field word::notion = field::joinField(object::word, "notion_id", object::notion);
19 const field word::lemma = field::joinField(object::word, "lemma_id", object::lemma); 19 const field word::lemma = field::joinField(object::word, "lemma_id", object::lemma);
20 const field word::group = field::joinField(object::word, "group_id", object::group, true); 20 const field word::group = field::joinField(object::word, "group_id", object::group, true);
21 21
22 const field word::antonyms = field::selfJoin(object::word, "word_id", "antonymy", "antonym_2_id", "antonym_1_id"); 22 const field word::antonyms = field::selfJoin(object::word, "word_id", "antonymy", "antonym_2_id", "antonym_1_id");
23 23
24 const field word::specifications = field::selfJoin(object::word, "word_id", "specification", "general_id", "specific_id"); 24 const field word::specifications = field::selfJoin(object::word, "word_id", "specification", "general_id", "specific_id");
25 const field word::generalizations = field::selfJoin(object::word, "word_id", "specification", "specific_id", "general_id"); 25 const field word::generalizations = field::selfJoin(object::word, "word_id", "specification", "specific_id", "general_id");
26 26
27 const field word::pertainyms = field::selfJoin(object::word, "word_id", "pertainymy", "noun_id", "pertainym_id"); 27 const field word::pertainyms = field::selfJoin(object::word, "word_id", "pertainymy", "noun_id", "pertainym_id");
28 const field word::antiPertainyms = field::selfJoin(object::word, "word_id", "pertainymy", "pertainym_id", "noun_id"); 28 const field word::antiPertainyms = field::selfJoin(object::word, "word_id", "pertainymy", "pertainym_id", "noun_id");
29 29
30 const field word::mannernyms = field::selfJoin(object::word, "word_id", "mannernymy", "adjective_id", "mannernym_id"); 30 const field word::mannernyms = field::selfJoin(object::word, "word_id", "mannernymy", "adjective_id", "mannernym_id");
31 const field word::antiMannernyms = field::selfJoin(object::word, "word_id", "mannernymy", "mannernym_id", "adjective_id"); 31 const field word::antiMannernyms = field::selfJoin(object::word, "word_id", "mannernymy", "mannernym_id", "adjective_id");
32 32
33 const field word::usageTerms = field::selfJoin(object::word, "word_id", "usage", "domain_id", "term_id"); 33 const field word::usageTerms = field::selfJoin(object::word, "word_id", "usage", "domain_id", "term_id");
34 const field word::usageDomains = field::selfJoin(object::word, "word_id", "usage", "term_id", "domain_id"); 34 const field word::usageDomains = field::selfJoin(object::word, "word_id", "usage", "term_id", "domain_id");
35 35
36 const field word::topicalTerms = field::selfJoin(object::word, "word_id", "topicality", "domain_id", "term_id"); 36 const field word::topicalTerms = field::selfJoin(object::word, "word_id", "topicality", "domain_id", "term_id");
37 const field word::topicalDomains = field::selfJoin(object::word, "word_id", "topicality", "term_id", "domain_id"); 37 const field word::topicalDomains = field::selfJoin(object::word, "word_id", "topicality", "term_id", "domain_id");
38 38
39 const field word::regionalTerms = field::selfJoin(object::word, "word_id", "regionality", "domain_id", "term_id"); 39 const field word::regionalTerms = field::selfJoin(object::word, "word_id", "regionality", "domain_id", "term_id");
40 const field word::regionalDomains = field::selfJoin(object::word, "word_id", "regionality", "term_id", "domain_id"); 40 const field word::regionalDomains = field::selfJoin(object::word, "word_id", "regionality", "term_id", "domain_id");
41 41
42 word::word(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) 42 word::word(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
43 { 43 {
44 id_ = sqlite3_column_int(row, 0); 44 id_ = sqlite3_column_int(row, 0);
45 notionId_ = sqlite3_column_int(row, 1); 45 notionId_ = sqlite3_column_int(row, 1);
46 lemmaId_ = sqlite3_column_int(row, 2); 46 lemmaId_ = sqlite3_column_int(row, 2);
47 47
48 if (sqlite3_column_type(row, 3) != SQLITE_NULL) 48 if (sqlite3_column_type(row, 3) != SQLITE_NULL)
49 { 49 {
50 hasTagCount_ = true; 50 hasTagCount_ = true;
51 tagCount_ = sqlite3_column_int(row, 3); 51 tagCount_ = sqlite3_column_int(row, 3);
52 } 52 }
53 53
54 if (sqlite3_column_type(row, 4) != SQLITE_NULL) 54 if (sqlite3_column_type(row, 4) != SQLITE_NULL)
55 { 55 {
56 adjectivePosition_ = static_cast<positioning>(sqlite3_column_int(row, 4)); 56 adjectivePosition_ = static_cast<positioning>(sqlite3_column_int(row, 4));
57 } 57 }
58 58
59 if (sqlite3_column_type(row, 5) != SQLITE_NULL) 59 if (sqlite3_column_type(row, 5) != SQLITE_NULL)
60 { 60 {
61 hasGroup_ = true; 61 hasGroup_ = true;
62 groupId_ = sqlite3_column_int(row, 5); 62 groupId_ = sqlite3_column_int(row, 5);
63 } 63 }
64 } 64 }
65 65
66 const notion& word::getNotion() const 66 const notion& word::getNotion() const
67 { 67 {
68 if (!valid_) 68 if (!valid_)
69 { 69 {
70 throw std::domain_error("Bad access to uninitialized word"); 70 throw std::domain_error("Bad access to uninitialized word");
71 } 71 }
72 72
73 if (!notion_) 73 if (!notion_)
74 { 74 {
75 notion_ = db_->notions(notion::id == notionId_).first(); 75 notion_ = db_->notions(notion::id == notionId_).first();
76 } 76 }
77 77
78 return notion_; 78 return notion_;
79 } 79 }
80 80
81 const lemma& word::getLemma() const 81 const lemma& word::getLemma() const
82 { 82 {
83 if (!valid_) 83 if (!valid_)
84 { 84 {
85 throw std::domain_error("Bad access to uninitialized word"); 85 throw std::domain_error("Bad access to uninitialized word");
86 } 86 }
87 87
88 if (!lemma_) 88 if (!lemma_)
89 { 89 {
90 lemma_ = db_->lemmas(lemma::id == lemmaId_).first(); 90 lemma_ = db_->lemmas(lemma::id == lemmaId_).first();
91 } 91 }
92 92
93 return lemma_; 93 return lemma_;
94 } 94 }
95 95
96 const group& word::getGroup() const 96 const group& word::getGroup() const
97 { 97 {
98 if (!valid_) 98 if (!valid_)
99 { 99 {
100 throw std::domain_error("Bad access to uninitialized word"); 100 throw std::domain_error("Bad access to uninitialized word");
101 } 101 }
102 102
103 if (!hasGroup_) 103 if (!hasGroup_)
104 { 104 {
105 throw std::domain_error("Word does not have a group"); 105 throw std::domain_error("Word does not have a group");
106 } 106 }
107 107
108 if (!group_) 108 if (!group_)
109 { 109 {
110 group_ = db_->groups(group::id == groupId_).first(); 110 group_ = db_->groups(group::id == groupId_).first();
111 } 111 }
112 112
113 return group_; 113 return group_;
114 } 114 }
115 115
116 std::string word::getBaseForm() const 116 std::string word::getBaseForm() const
117 { 117 {
118 return getLemma().getBaseForm().getText(); 118 return getLemma().getBaseForm().getText();
119 } 119 }
120 120
121 std::vector<std::string> word::getInflections(inflection category) const 121 std::vector<std::string> word::getInflections(inflection category) const
122 { 122 {
123 std::vector<std::string> result; 123 std::vector<std::string> result;
@@ -128,5 +128,5 @@ namespace verbly {
128 128
129 return result; 129 return result;
130 } 130 }
131 131
132}; 132};
diff --git a/lib/word.h b/lib/word.h index 7b3c0f7..ddcabe4 100644 --- a/lib/word.h +++ b/lib/word.h
@@ -12,157 +12,157 @@
12struct sqlite3_stmt; 12struct sqlite3_stmt;
13 13
14namespace verbly { 14namespace verbly {
15 15
16 class database; 16 class database;
17 17
18 class word { 18 class word {
19 public: 19 public:
20 20
21 // Default constructor 21 // Default constructor
22 22
23 word() = default; 23 word() = default;
24 24
25 // Construct from database 25 // Construct from database
26 26
27 word(const database& db, sqlite3_stmt* row); 27 word(const database& db, sqlite3_stmt* row);
28 28
29 // Accessors 29 // Accessors
30 30
31 operator bool() const 31 operator bool() const
32 { 32 {
33 return valid_; 33 return valid_;
34 } 34 }
35 35
36 int getId() const 36 int getId() const
37 { 37 {
38 if (!valid_) 38 if (!valid_)
39 { 39 {
40 throw std::domain_error("Bad access to uninitialized word"); 40 throw std::domain_error("Bad access to uninitialized word");
41 } 41 }
42 42
43 return id_; 43 return id_;
44 } 44 }
45 45
46 bool hasTagCount() const 46 bool hasTagCount() const
47 { 47 {
48 if (!valid_) 48 if (!valid_)
49 { 49 {
50 throw std::domain_error("Bad access to uninitialized word"); 50 throw std::domain_error("Bad access to uninitialized word");
51 } 51 }
52 52
53 return hasTagCount_; 53 return hasTagCount_;
54 } 54 }
55 55
56 int getTagCount() const 56 int getTagCount() const
57 { 57 {
58 if (!valid_) 58 if (!valid_)
59 { 59 {
60 throw std::domain_error("Bad access to uninitialized word"); 60 throw std::domain_error("Bad access to uninitialized word");
61 } 61 }
62 62
63 if (!hasTagCount_) 63 if (!hasTagCount_)
64 { 64 {
65 throw std::domain_error("Word has no tag count"); 65 throw std::domain_error("Word has no tag count");
66 } 66 }
67 67
68 return tagCount_; 68 return tagCount_;
69 } 69 }
70 70
71 bool hasAdjectivePositioning() const 71 bool hasAdjectivePositioning() const
72 { 72 {
73 if (!valid_) 73 if (!valid_)
74 { 74 {
75 throw std::domain_error("Bad access to uninitialized word"); 75 throw std::domain_error("Bad access to uninitialized word");
76 } 76 }
77 77
78 return (adjectivePosition_ != positioning::undefined); 78 return (adjectivePosition_ != positioning::undefined);
79 } 79 }
80 80
81 positioning getAdjectivePosition() const 81 positioning getAdjectivePosition() const
82 { 82 {
83 if (!valid_) 83 if (!valid_)
84 { 84 {
85 throw std::domain_error("Bad access to uninitialized word"); 85 throw std::domain_error("Bad access to uninitialized word");
86 } 86 }
87 87
88 if (adjectivePosition_ == positioning::undefined) 88 if (adjectivePosition_ == positioning::undefined)
89 { 89 {
90 throw std::domain_error("Word has no adjective position"); 90 throw std::domain_error("Word has no adjective position");
91 } 91 }
92 92
93 return adjectivePosition_; 93 return adjectivePosition_;
94 } 94 }
95 95
96 const notion& getNotion() const; 96 const notion& getNotion() const;
97 97
98 const lemma& getLemma() const; 98 const lemma& getLemma() const;
99 99
100 bool hasGroup() const 100 bool hasGroup() const
101 { 101 {
102 if (!valid_) 102 if (!valid_)
103 { 103 {
104 throw std::domain_error("Bad access to uninitialized word"); 104 throw std::domain_error("Bad access to uninitialized word");
105 } 105 }
106 106
107 return hasGroup_; 107 return hasGroup_;
108 } 108 }
109 109
110 const group& getGroup() const; 110 const group& getGroup() const;
111 111
112 // Convenience accessors 112 // Convenience accessors
113 113
114 std::string getBaseForm() const; 114 std::string getBaseForm() const;
115 115
116 std::vector<std::string> getInflections(inflection infl) const; 116 std::vector<std::string> getInflections(inflection infl) const;
117 117
118 // Type info 118 // Type info
119 119
120 static const object objectType; 120 static const object objectType;
121 121
122 static const std::list<std::string> select; 122 static const std::list<std::string> select;
123 123
124 // Query fields 124 // Query fields
125 125
126 static const field id; 126 static const field id;
127 static const field tagCount; 127 static const field tagCount;
128 static const field adjectivePosition; 128 static const field adjectivePosition;
129 129
130 operator filter() const 130 operator filter() const
131 { 131 {
132 return (id == id_); 132 return (id == id_);
133 } 133 }
134 134
135 // Relationships with other objects 135 // Relationships with other objects
136 136
137 static const field notion; 137 static const field notion;
138 static const field lemma; 138 static const field lemma;
139 static const field group; 139 static const field group;
140 140
141 // Relationships with self 141 // Relationships with self
142 142
143 static const field antonyms; 143 static const field antonyms;
144 144
145 static const field specifications; 145 static const field specifications;
146 static const field generalizations; 146 static const field generalizations;
147 147
148 static const field pertainyms; 148 static const field pertainyms;
149 static const field antiPertainyms; 149 static const field antiPertainyms;
150 150
151 static const field mannernyms; 151 static const field mannernyms;
152 static const field antiMannernyms; 152 static const field antiMannernyms;
153 153
154 static const field usageTerms; 154 static const field usageTerms;
155 static const field usageDomains; 155 static const field usageDomains;
156 156
157 static const field topicalTerms; 157 static const field topicalTerms;
158 static const field topicalDomains; 158 static const field topicalDomains;
159 159
160 static const field regionalTerms; 160 static const field regionalTerms;
161 static const field regionalDomains; 161 static const field regionalDomains;
162 162
163 private: 163 private:
164 bool valid_ = false; 164 bool valid_ = false;
165 165
166 int id_; 166 int id_;
167 bool hasTagCount_ = false; 167 bool hasTagCount_ = false;
168 int tagCount_; 168 int tagCount_;
@@ -171,15 +171,15 @@ namespace verbly {
171 int lemmaId_; 171 int lemmaId_;
172 bool hasGroup_ = false; 172 bool hasGroup_ = false;
173 int groupId_; 173 int groupId_;
174 174
175 const database* db_; 175 const database* db_;
176 176
177 mutable class notion notion_; 177 mutable class notion notion_;
178 mutable class lemma lemma_; 178 mutable class lemma lemma_;
179 mutable class group group_; 179 mutable class group group_;
180 180
181 }; 181 };
182 182
183}; 183};
184 184
185#endif /* end of include guard: WORD_H_DF91B1B4 */ 185#endif /* end of include guard: WORD_H_DF91B1B4 */