summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2017-01-28 12:59:42 -0500
committerKelly Rauchenberger <fefferburbia@gmail.com>2017-01-28 12:59:42 -0500
commita7645346293ed6a912c26d0c50b6f7943f1f3072 (patch)
treed4d144e03a5e2dfcebbad2692fa71e790719d8fd
parent6ba8989bbbd497f949a3e8b17abed1d0bd048347 (diff)
downloadverbly-a7645346293ed6a912c26d0c50b6f7943f1f3072.tar.gz
verbly-a7645346293ed6a912c26d0c50b6f7943f1f3072.tar.bz2
verbly-a7645346293ed6a912c26d0c50b6f7943f1f3072.zip
Restructured verb frame schema to be more queryable
Groups are much less significant now, and they no longer have a database
table, nor are they considered a top level object anymore. Instead of
containing their own role data, that data is folded into the frames so
that it's easier to query; as a result, each group has its own copy of
the frames that it contains. Additionally, parts are considered top
level objects now, and you can query for frames based on attributes of
their indexed parts. Synrestrs are also contained in their own table
now, so that parts can be filtered against their synrestrs; they are
however not considered top level objects.

Created a new type of field, the "join where" or "condition join" field,
which is a normal join field that has a built in condition on a
specified field. This is used to allow creating multiple distinct join
fields from one object to another. This is required for the lemma::form
and frame::part joins, because filters for forms of separate inflections
should not be coalesced; similarly, filters on differently indexed frame
parts should not be coalesced.

Queries can now be ordered, ascending or descending, by a field, in
addition to randomly as before. This is necessary for accessing the
parts of a verb frame in the correct order, but may be useful to an end
user as well.

Fixed a bug with statement generation in that condition groups were not
being surrounded in parentheses, which made mixing OR groups and AND
groups generate inaccurate statements. This has been fixed;
additionally, parentheses are not placed around the top level condition,
and nested condition groups with the same logic type are coalesced, to
make query strings as easy to read as possible.

Also simplified the form::lemma field; it no longer conditions on the
inflection of the form like the lemma::form field does.

Also added a debug flag to statement::getQueryString that makes it
return a query string with all of the bindings filled in, for debug use
only.
-rw-r--r--CMakeLists.txt2
-rw-r--r--generator/frame.cpp69
-rw-r--r--generator/frame.h20
-rw-r--r--generator/generator.cpp39
-rw-r--r--generator/generator.h3
-rw-r--r--generator/group.cpp166
-rw-r--r--generator/group.h30
-rw-r--r--generator/part.cpp48
-rw-r--r--generator/part.h30
-rw-r--r--generator/role.h (renamed from lib/role.h)0
-rw-r--r--generator/schema.sql33
-rw-r--r--generator/word.h1
-rw-r--r--lib/database.cpp60
-rw-r--r--lib/database.h20
-rw-r--r--lib/enums.h14
-rw-r--r--lib/field.cpp20
-rw-r--r--lib/field.h78
-rw-r--r--lib/filter.cpp35
-rw-r--r--lib/form.cpp16
-rw-r--r--lib/form.h31
-rw-r--r--lib/frame.cpp95
-rw-r--r--lib/frame.h21
-rw-r--r--lib/group.cpp61
-rw-r--r--lib/group.h91
-rw-r--r--lib/lemma.cpp15
-rw-r--r--lib/lemma.h27
-rw-r--r--lib/order.h69
-rw-r--r--lib/part.cpp128
-rw-r--r--lib/part.h64
-rw-r--r--lib/query.h11
-rw-r--r--lib/statement.cpp164
-rw-r--r--lib/statement.h9
-rw-r--r--lib/verbly.h5
-rw-r--r--lib/word.cpp36
-rw-r--r--lib/word.h23
35 files changed, 885 insertions, 649 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c15e79..32c73c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -7,7 +7,7 @@ pkg_check_modules(sqlite3 sqlite3>=3.8.3 REQUIRED)
7set(CMAKE_BUILD_TYPE Debug) 7set(CMAKE_BUILD_TYPE Debug)
8 8
9include_directories(vendor/json) 9include_directories(vendor/json)
10add_library(verbly lib/filter.cpp lib/field.cpp lib/notion.cpp lib/word.cpp lib/group.cpp lib/frame.cpp lib/lemma.cpp lib/form.cpp lib/pronunciation.cpp lib/statement.cpp lib/binding.cpp lib/database.cpp lib/token.cpp lib/selrestr.cpp lib/part.cpp) 10add_library(verbly lib/filter.cpp lib/field.cpp lib/notion.cpp lib/word.cpp lib/frame.cpp lib/part.cpp lib/lemma.cpp lib/form.cpp lib/pronunciation.cpp lib/statement.cpp lib/binding.cpp lib/database.cpp lib/token.cpp lib/selrestr.cpp lib/part.cpp)
11set_property(TARGET verbly PROPERTY CXX_STANDARD 11) 11set_property(TARGET verbly PROPERTY CXX_STANDARD 11)
12set_property(TARGET verbly PROPERTY CXX_STANDARD_REQUIRED ON) 12set_property(TARGET verbly PROPERTY CXX_STANDARD_REQUIRED ON)
13target_link_libraries(verbly ${sqlite3_LIBRARIES}) 13target_link_libraries(verbly ${sqlite3_LIBRARIES})
diff --git a/generator/frame.cpp b/generator/frame.cpp index f75e3ba..4e4ac5f 100644 --- a/generator/frame.cpp +++ b/generator/frame.cpp
@@ -11,72 +11,21 @@ namespace verbly {
11 { 11 {
12 } 12 }
13 13
14 void frame::push_back(part fp) 14 frame frame::duplicate(const frame& other)
15 {
16 parts_.push_back(std::move(fp));
17 }
18
19 database& operator<<(database& db, const frame& arg)
20 { 15 {
21 std::list<field> fields; 16 frame result;
22 fields.emplace_back("frame_id", arg.getId());
23 17
24 nlohmann::json jsonParts; 18 for (const part& p : other.parts_)
25 for (const part& p : arg)
26 { 19 {
27 nlohmann::json jsonPart; 20 result.push_back(part::duplicate(p));
28 jsonPart["type"] = static_cast<int>(p.getType());
29
30 switch (p.getType())
31 {
32 case part::type::noun_phrase:
33 {
34 jsonPart["role"] = p.getNounRole();
35 jsonPart["selrestrs"] = p.getNounSelrestrs().toJson();
36 jsonPart["synrestrs"] = p.getNounSynrestrs();
37
38 break;
39 }
40
41 case part::type::preposition:
42 {
43 jsonPart["choices"] = p.getPrepositionChoices();
44 jsonPart["literal"] = p.isPrepositionLiteral();
45
46 break;
47 }
48
49 case part::type::literal:
50 {
51 jsonPart["value"] = p.getLiteralValue();
52
53 break;
54 }
55
56 case part::type::verb:
57 case part::type::adjective:
58 case part::type::adverb:
59 {
60 break;
61 }
62
63 case part::type::invalid:
64 {
65 // Invalid parts should not be serialized.
66 assert(false);
67
68 break;
69 }
70 }
71
72 jsonParts.push_back(std::move(jsonPart));
73 } 21 }
74 22
75 fields.emplace_back("data", jsonParts.dump()); 23 return result;
76 24 }
77 db.insertIntoTable("frames", std::move(fields));
78 25
79 return db; 26 void frame::push_back(part fp)
27 {
28 parts_.push_back(std::move(fp));
80 } 29 }
81 30
82 }; 31 };
diff --git a/generator/frame.h b/generator/frame.h index 764564d..ba266f0 100644 --- a/generator/frame.h +++ b/generator/frame.h
@@ -19,6 +19,10 @@ namespace verbly {
19 // Constructor 19 // Constructor
20 20
21 frame(); 21 frame();
22
23 // Duplication
24
25 static frame duplicate(const frame& other);
22 26
23 // Mutators 27 // Mutators
24 28
@@ -30,15 +34,15 @@ namespace verbly {
30 { 34 {
31 return id_; 35 return id_;
32 } 36 }
33 37
34 const_iterator begin() const 38 int getLength() const
35 { 39 {
36 return std::begin(parts_); 40 return parts_.size();
37 } 41 }
38 42
39 const_iterator end() const 43 const part& operator[](int index) const
40 { 44 {
41 return std::end(parts_); 45 return parts_.at(index);
42 } 46 }
43 47
44 private: 48 private:
@@ -47,12 +51,10 @@ namespace verbly {
47 51
48 const int id_; 52 const int id_;
49 53
50 std::list<part> parts_; 54 std::vector<part> parts_;
51 55
52 }; 56 };
53 57
54 database& operator<<(database& db, const frame& arg);
55
56 }; 58 };
57}; 59};
58 60
diff --git a/generator/generator.cpp b/generator/generator.cpp index 610a602..4cc9f64 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp
@@ -8,7 +8,7 @@
8#include "../lib/enums.h" 8#include "../lib/enums.h"
9#include "progress.h" 9#include "progress.h"
10#include "../lib/selrestr.h" 10#include "../lib/selrestr.h"
11#include "../lib/role.h" 11#include "role.h"
12#include "part.h" 12#include "part.h"
13#include "field.h" 13#include "field.h"
14#include "../lib/util.h" 14#include "../lib/util.h"
@@ -640,7 +640,7 @@ namespace verbly {
640 } 640 }
641 641
642 { 642 {
643 progress ppgs("Writing verb groups...", groups_.size()); 643 progress ppgs("Writing verb frames...", groups_.size());
644 644
645 for (group& g : groups_) 645 for (group& g : groups_)
646 { 646 {
@@ -649,17 +649,6 @@ namespace verbly {
649 ppgs.update(); 649 ppgs.update();
650 } 650 }
651 } 651 }
652
653 {
654 progress ppgs("Writing verb frames...", frames_.size());
655
656 for (frame& f : frames_)
657 {
658 db_ << f;
659
660 ppgs.update();
661 }
662 }
663 } 652 }
664 653
665 void generator::readWordNetAntonymy() 654 void generator::readWordNetAntonymy()
@@ -1212,9 +1201,15 @@ namespace verbly {
1212 return w; 1201 return w;
1213 } 1202 }
1214 1203
1215 group& generator::createGroup(xmlNodePtr top) 1204 void generator::createGroup(xmlNodePtr top, const group* parent)
1216 { 1205 {
1217 groups_.emplace_back(); 1206 if (parent != nullptr)
1207 {
1208 groups_.emplace_back(*parent);
1209 } else {
1210 groups_.emplace_back();
1211 }
1212
1218 group& grp = groups_.back(); 1213 group& grp = groups_.back();
1219 1214
1220 xmlChar* key; 1215 xmlChar* key;
@@ -1229,8 +1224,11 @@ namespace verbly {
1229 { 1224 {
1230 try 1225 try
1231 { 1226 {
1232 group& subgrp = createGroup(subclass); 1227 // Parsing a subgroup starts by making a copy of everything in
1233 subgrp.setParent(grp); 1228 // the parent. This is okay to do at this point because in the
1229 // VerbNet data, subgroups are always defined after everything
1230 // else.
1231 createGroup(subclass, &grp);
1234 } catch (const std::exception& e) 1232 } catch (const std::exception& e)
1235 { 1233 {
1236 key = xmlGetProp(subclass, reinterpret_cast<const xmlChar*>("ID")); 1234 key = xmlGetProp(subclass, reinterpret_cast<const xmlChar*>("ID"));
@@ -1323,8 +1321,7 @@ namespace verbly {
1323 { 1321 {
1324 if (!xmlStrcmp(frametopnode->name, reinterpret_cast<const xmlChar*>("FRAME"))) 1322 if (!xmlStrcmp(frametopnode->name, reinterpret_cast<const xmlChar*>("FRAME")))
1325 { 1323 {
1326 frames_.emplace_back(); 1324 frame fr;
1327 frame& fr = frames_.back();
1328 1325
1329 for (xmlNodePtr framenode = frametopnode->xmlChildrenNode; framenode != nullptr; framenode = framenode->next) 1326 for (xmlNodePtr framenode = frametopnode->xmlChildrenNode; framenode != nullptr; framenode = framenode->next)
1330 { 1327 {
@@ -1428,15 +1425,13 @@ namespace verbly {
1428 } 1425 }
1429 } 1426 }
1430 1427
1431 grp.addFrame(fr); 1428 grp.addFrame(std::move(fr));
1432 } 1429 }
1433 } 1430 }
1434 } 1431 }
1435 } 1432 }
1436 } 1433 }
1437 } 1434 }
1438
1439 return grp;
1440 } 1435 }
1441 1436
1442 selrestr generator::parseSelrestr(xmlNodePtr top) 1437 selrestr generator::parseSelrestr(xmlNodePtr top)
diff --git a/generator/generator.h b/generator/generator.h index 8352693..bc9b3c7 100644 --- a/generator/generator.h +++ b/generator/generator.h
@@ -105,7 +105,7 @@ namespace verbly {
105 105
106 template <typename... Args> word& createWord(Args&&... args); 106 template <typename... Args> word& createWord(Args&&... args);
107 107
108 group& createGroup(xmlNodePtr top); 108 void createGroup(xmlNodePtr top, const group* parent = nullptr);
109 109
110 selrestr parseSelrestr(xmlNodePtr top); 110 selrestr parseSelrestr(xmlNodePtr top);
111 111
@@ -128,7 +128,6 @@ namespace verbly {
128 std::list<lemma> lemmas_; 128 std::list<lemma> lemmas_;
129 std::list<form> forms_; 129 std::list<form> forms_;
130 std::list<pronunciation> pronunciations_; 130 std::list<pronunciation> pronunciations_;
131 std::list<frame> frames_;
132 std::list<group> groups_; 131 std::list<group> groups_;
133 132
134 // Indexes 133 // Indexes
diff --git a/generator/group.cpp b/generator/group.cpp index cebe2b9..aa28d42 100644 --- a/generator/group.cpp +++ b/generator/group.cpp
@@ -15,12 +15,15 @@ namespace verbly {
15 { 15 {
16 } 16 }
17 17
18 void group::setParent(const group& parent) 18 group::group(const group& parent) :
19 id_(nextId_++),
20 roles_(parent.roles_),
21 roleNames_(parent.roleNames_)
19 { 22 {
20 // Adding a group to itself is nonsensical. 23 for (const frame& f : parent.frames_)
21 assert(&parent != this); 24 {
22 25 frames_.push_back(frame::duplicate(f));
23 parent_ = &parent; 26 }
24 } 27 }
25 28
26 void group::addRole(role r) 29 void group::addRole(role r)
@@ -30,87 +33,114 @@ namespace verbly {
30 roleNames_.insert(std::move(name)); 33 roleNames_.insert(std::move(name));
31 } 34 }
32 35
33 void group::addFrame(const frame& f) 36 void group::addFrame(frame f)
34 { 37 {
35 frames_.insert(&f); 38 frames_.push_back(std::move(f));
36 } 39 }
37 40
38 std::set<std::string> group::getRoles() const 41 bool group::hasRole(std::string name) const
39 { 42 {
40 std::set<std::string> fullRoles = roleNames_; 43 // Rarely, a noun phrase part may use a role that is not defined in the
41 44 // group. See confess-37.10 "NP V NP ADJ".
42 if (hasParent()) 45 return (roles_.count(name) == 1);
43 {
44 for (std::string name : getParent().getRoles())
45 {
46 fullRoles.insert(name);
47 }
48 }
49
50 return fullRoles;
51 } 46 }
52 47
53 const role& group::getRole(std::string name) const 48 const role& group::getRole(std::string name) const
54 { 49 {
55 if (roles_.count(name)) 50 return roles_.at(name);
56 {
57 return roles_.at(name);
58 } else if (hasParent())
59 {
60 return getParent().getRole(name);
61 } else {
62 throw std::invalid_argument("Specified role not found in verb group");
63 }
64 }
65
66 std::set<const frame*> group::getFrames() const
67 {
68 std::set<const frame*> fullFrames = frames_;
69
70 if (hasParent())
71 {
72 for (const frame* f : getParent().getFrames())
73 {
74 fullFrames.insert(f);
75 }
76 }
77
78 return fullFrames;
79 } 51 }
80 52
81 database& operator<<(database& db, const group& arg) 53 database& operator<<(database& db, const group& arg)
82 { 54 {
83 // Serialize the group first 55 // Serialize each frame
56 for (const frame& f : arg.getFrames())
84 { 57 {
85 std::list<field> fields; 58 // First, serialize the group/frame relationship
86 fields.emplace_back("group_id", arg.getId());
87
88 nlohmann::json jsonRoles;
89 for (std::string name : arg.getRoles())
90 { 59 {
91 const role& r = arg.getRole(name); 60 std::list<field> fields;
92 61
93 nlohmann::json jsonRole; 62 fields.emplace_back("frame_id", f.getId());
94 jsonRole["type"] = name; 63 fields.emplace_back("group_id", arg.getId());
95 jsonRole["selrestrs"] = r.getSelrestrs().toJson(); 64 fields.emplace_back("length", f.getLength());
96 65
97 jsonRoles.emplace_back(std::move(jsonRole)); 66 db.insertIntoTable("frames", std::move(fields));
98 } 67 }
99 68
100 fields.emplace_back("data", jsonRoles.dump()); 69 // Then, serialize the frame parts in the context of the group
101 70 for (int partIndex = 0; partIndex < f.getLength(); partIndex++)
102 db.insertIntoTable("groups", std::move(fields)); 71 {
103 } 72 const part& p = f[partIndex];
104 73
105 // Then, serialize the group/frame relationship 74 std::list<field> fields;
106 for (const frame* f : arg.getFrames()) 75 fields.emplace_back("part_id", p.getId());
107 { 76 fields.emplace_back("frame_id", f.getId());
108 std::list<field> fields; 77 fields.emplace_back("part_index", partIndex);
109 78 fields.emplace_back("type", static_cast<int>(p.getType()));
110 fields.emplace_back("group_id", arg.getId()); 79
111 fields.emplace_back("frame_id", f->getId()); 80 switch (p.getType())
112 81 {
113 db.insertIntoTable("groups_frames", std::move(fields)); 82 case part::type::noun_phrase:
83 {
84 fields.emplace_back("role", p.getNounRole());
85
86 selrestr partSelrestr;
87 if (p.getNounSelrestrs().getType() != selrestr::type::empty)
88 {
89 partSelrestr = p.getNounSelrestrs();
90 } else if (arg.hasRole(p.getNounRole()))
91 {
92 partSelrestr = arg.getRole(p.getNounRole()).getSelrestrs();
93 }
94
95 fields.emplace_back("selrestrs", partSelrestr.toJson().dump());
96
97 // Short interlude to serialize the synrestrs
98 for (const std::string& s : p.getNounSynrestrs())
99 {
100 std::list<field> synrestrFields;
101
102 synrestrFields.emplace_back("part_id", p.getId());
103 synrestrFields.emplace_back("synrestr", s);
104
105 db.insertIntoTable("synrestrs", std::move(synrestrFields));
106 }
107
108 break;
109 }
110
111 case part::type::preposition:
112 {
113 fields.emplace_back("prepositions", nlohmann::json(p.getPrepositionChoices()).dump());
114 fields.emplace_back("preposition_literality", p.isPrepositionLiteral() ? 1 : 0);
115
116 break;
117 }
118
119 case part::type::literal:
120 {
121 fields.emplace_back("literal_value", p.getLiteralValue());
122
123 break;
124 }
125
126 case part::type::verb:
127 case part::type::adjective:
128 case part::type::adverb:
129 {
130 break;
131 }
132
133 case part::type::invalid:
134 {
135 // Invalid parts should not be serialized.
136 assert(false);
137
138 break;
139 }
140 }
141
142 db.insertIntoTable("parts", std::move(fields));
143 }
114 } 144 }
115 145
116 return db; 146 return db;
diff --git a/generator/group.h b/generator/group.h index 83f40c2..5486fbe 100644 --- a/generator/group.h +++ b/generator/group.h
@@ -5,7 +5,7 @@
5#include <set> 5#include <set>
6#include <string> 6#include <string>
7#include <cassert> 7#include <cassert>
8#include "../lib/role.h" 8#include "role.h"
9 9
10namespace verbly { 10namespace verbly {
11 namespace generator { 11 namespace generator {
@@ -20,13 +20,13 @@ namespace verbly {
20 20
21 group(); 21 group();
22 22
23 // Mutators 23 explicit group(const group& parent);
24 24
25 void setParent(const group& parent); 25 // Mutators
26 26
27 void addRole(role r); 27 void addRole(role r);
28 28
29 void addFrame(const frame& f); 29 void addFrame(frame f);
30 30
31 // Accessors 31 // Accessors
32 32
@@ -35,24 +35,19 @@ namespace verbly {
35 return id_; 35 return id_;
36 } 36 }
37 37
38 bool hasParent() const 38 const std::set<std::string>& getRoles() const
39 {
40 return (parent_ != nullptr);
41 }
42
43 const group& getParent() const
44 { 39 {
45 // Calling code should always call hasParent first 40 return roleNames_;
46 assert(parent_ != nullptr);
47
48 return *parent_;
49 } 41 }
50 42
51 std::set<std::string> getRoles() const; 43 bool hasRole(std::string name) const;
52 44
53 const role& getRole(std::string name) const; 45 const role& getRole(std::string name) const;
54 46
55 std::set<const frame*> getFrames() const; 47 const std::list<frame>& getFrames() const
48 {
49 return frames_;
50 }
56 51
57 private: 52 private:
58 53
@@ -60,9 +55,8 @@ namespace verbly {
60 55
61 const int id_; 56 const int id_;
62 57
63 const group* parent_ = nullptr;
64 std::map<std::string, role> roles_; 58 std::map<std::string, role> roles_;
65 std::set<const frame*> frames_; 59 std::list<frame> frames_;
66 60
67 // Caches 61 // Caches
68 62
diff --git a/generator/part.cpp b/generator/part.cpp index 8a75ed4..07618a8 100644 --- a/generator/part.cpp +++ b/generator/part.cpp
@@ -4,6 +4,8 @@
4namespace verbly { 4namespace verbly {
5 namespace generator { 5 namespace generator {
6 6
7 int part::nextId_ = 0;
8
7 part part::createNounPhrase(std::string role, selrestr selrestrs, std::set<std::string> synrestrs) 9 part part::createNounPhrase(std::string role, selrestr selrestrs, std::set<std::string> synrestrs)
8 { 10 {
9 part p(type::noun_phrase); 11 part p(type::noun_phrase);
@@ -49,9 +51,52 @@ namespace verbly {
49 return p; 51 return p;
50 } 52 }
51 53
54 part part::duplicate(const part& other)
55 {
56 part result(other.type_);
57
58 switch (result.type_)
59 {
60 case type::noun_phrase:
61 {
62 new(&result.noun_phrase_.role) std::string(other.noun_phrase_.role);
63 new(&result.noun_phrase_.selrestrs) selrestr(other.noun_phrase_.selrestrs);
64 new(&result.noun_phrase_.synrestrs) std::set<std::string>(other.noun_phrase_.synrestrs);
65
66 break;
67 }
68
69 case type::preposition:
70 {
71 new(&result.preposition_.choices) std::set<std::string>(other.preposition_.choices);
72 result.preposition_.literal = other.preposition_.literal;
73
74 break;
75 }
76
77 case type::literal:
78 {
79 new(&result.literal_) std::string(other.literal_);
80
81 break;
82 }
83
84 case type::verb:
85 case type::adjective:
86 case type::adverb:
87 case type::invalid:
88 {
89 break;
90 }
91 }
92
93 return result;
94 }
95
52 part::part(const part& other) 96 part::part(const part& other)
53 { 97 {
54 type_ = other.type_; 98 type_ = other.type_;
99 id_ = other.id_;
55 100
56 switch (type_) 101 switch (type_)
57 { 102 {
@@ -106,6 +151,7 @@ namespace verbly {
106 using type = part::type; 151 using type = part::type;
107 152
108 type tempType = first.type_; 153 type tempType = first.type_;
154 int tempId = first.id_;
109 std::string tempRole; 155 std::string tempRole;
110 selrestr tempSelrestrs; 156 selrestr tempSelrestrs;
111 std::set<std::string> tempSynrestrs; 157 std::set<std::string> tempSynrestrs;
@@ -151,6 +197,7 @@ namespace verbly {
151 first.~part(); 197 first.~part();
152 198
153 first.type_ = second.type_; 199 first.type_ = second.type_;
200 first.id_ = second.id_;
154 201
155 switch (first.type_) 202 switch (first.type_)
156 { 203 {
@@ -190,6 +237,7 @@ namespace verbly {
190 second.~part(); 237 second.~part();
191 238
192 second.type_ = tempType; 239 second.type_ = tempType;
240 second.id_ = tempId;
193 241
194 switch (second.type_) 242 switch (second.type_)
195 { 243 {
diff --git a/generator/part.h b/generator/part.h index b010f62..39ba1e7 100644 --- a/generator/part.h +++ b/generator/part.h
@@ -4,21 +4,16 @@
4#include <string> 4#include <string>
5#include <set> 5#include <set>
6#include "../lib/selrestr.h" 6#include "../lib/selrestr.h"
7#include "../lib/enums.h"
7 8
8namespace verbly { 9namespace verbly {
10
9 namespace generator { 11 namespace generator {
10 12
11 class part { 13 class part {
12 public: 14 public:
13 enum class type { 15
14 invalid = -1, 16 using type = part_type;
15 noun_phrase = 0,
16 verb = 1,
17 preposition = 2,
18 adjective = 3,
19 adverb = 4,
20 literal = 5
21 };
22 17
23 // Static factories 18 // Static factories
24 19
@@ -34,6 +29,10 @@ namespace verbly {
34 29
35 static part createLiteral(std::string value); 30 static part createLiteral(std::string value);
36 31
32 // Duplication
33
34 static part duplicate(const part& other);
35
37 // Copy and move constructors 36 // Copy and move constructors
38 37
39 part(const part& other); 38 part(const part& other);
@@ -54,6 +53,11 @@ namespace verbly {
54 53
55 // General accessors 54 // General accessors
56 55
56 int getId() const
57 {
58 return id_;
59 }
60
57 type getType() const 61 type getType() const
58 { 62 {
59 return type_; 63 return type_;
@@ -79,13 +83,19 @@ namespace verbly {
79 83
80 private: 84 private:
81 85
86 static int nextId_;
87
88 int id_;
89
82 // Private constructors 90 // Private constructors
83 91
84 part() 92 part()
85 { 93 {
86 } 94 }
87 95
88 part(type t) : type_(t) 96 part(type t) :
97 id_(nextId_++),
98 type_(t)
89 { 99 {
90 } 100 }
91 101
diff --git a/lib/role.h b/generator/role.h index 4884ef3..4884ef3 100644 --- a/lib/role.h +++ b/generator/role.h
diff --git a/generator/schema.sql b/generator/schema.sql index c3e54d8..33ebc28 100644 --- a/generator/schema.sql +++ b/generator/schema.sql
@@ -186,19 +186,32 @@ CREATE TABLE `forms_pronunciations` (
186CREATE INDEX `pronunciation_of` ON `forms_pronunciations`(`form_id`); 186CREATE INDEX `pronunciation_of` ON `forms_pronunciations`(`form_id`);
187CREATE INDEX `spelling_of` ON `forms_pronunciations`(`pronunciation_id`); 187CREATE INDEX `spelling_of` ON `forms_pronunciations`(`pronunciation_id`);
188 188
189CREATE TABLE `groups` ( 189CREATE TABLE `frames` (
190 `group_id` INTEGER PRIMARY KEY, 190 `frame_id` INTEGER NOT NULL,
191 `data` BLOB NOT NULL 191 `group_id` INTEGER NOT NULL,
192 'length' INTEGER NOT NULL
192); 193);
193 194
194CREATE TABLE `frames` ( 195CREATE INDEX `frames_in` ON `frames`(`group_id`);
195 `frame_id` INTEGER PRIMARY KEY, 196
196 `data` BLOB NOT NULL 197CREATE TABLE `parts` (
198 `part_id` INTEGER PRIMARY KEY,
199 `frame_id` INTEGER NOT NULL,
200 `part_index` INTEGER NOT NULL,
201 `type` INTEGER NOT NULL,
202 `role` VARCHAR(16),
203 `selrestrs` BLOB,
204 `prepositions` BLOB,
205 `preposition_literality` SMALLINT,
206 `literal_value` VARCHAR(64)
197); 207);
198 208
199CREATE TABLE `groups_frames` ( 209CREATE INDEX `parts_of` ON `parts`(`frame_id`);
200 `group_id` INTEGER NOT NULL, 210CREATE UNIQUE INDEX `part_by_frame_index` ON `parts`(`frame_id`, `part_index`);
201 `frame_id` INTEGER NOT NULL 211
212CREATE TABLE `synrestrs` (
213 `part_id` INTEGER NOT NULL,
214 `synrestr` VARCHAR(32) NOT NULL
202); 215);
203 216
204CREATE INDEX `frames_in` ON `groups_frames`(`group_id`); 217CREATE INDEX `synrestrs_for` ON `synrestrs`(`part_id`);
diff --git a/generator/word.h b/generator/word.h index a994ec3..c6d7b20 100644 --- a/generator/word.h +++ b/generator/word.h
@@ -5,6 +5,7 @@
5#include "../lib/enums.h" 5#include "../lib/enums.h"
6 6
7namespace verbly { 7namespace verbly {
8
8 namespace generator { 9 namespace generator {
9 10
10 class notion; 11 class notion;
diff --git a/lib/database.cpp b/lib/database.cpp index fb00ef3..563ec31 100644 --- a/lib/database.cpp +++ b/lib/database.cpp
@@ -41,39 +41,71 @@ namespace verbly {
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, order sortOrder, 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), std::move(sortOrder), limit);
47 } 47 }
48 48
49 query<word> database::words(filter where, bool random, int limit) const 49 query<word> database::words(filter where, order sortOrder, 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), std::move(sortOrder), limit);
52 } 52 }
53 53
54 query<group> database::groups(filter where, bool random, int limit) const 54 query<frame> database::frames(filter where, order sortOrder, int limit) const
55 { 55 {
56 return query<group>(*this, ppdb_, std::move(where), random, limit); 56 return query<frame>(*this, ppdb_, std::move(where), std::move(sortOrder), limit);
57 } 57 }
58 58
59 query<frame> database::frames(filter where, bool random, int limit) const 59 query<part> database::parts(filter where, order sortOrder, int limit) const
60 { 60 {
61 return query<frame>(*this, ppdb_, std::move(where), random, limit); 61 return query<part>(*this, ppdb_, std::move(where), std::move(sortOrder), limit);
62 } 62 }
63 63
64 query<lemma> database::lemmas(filter where, bool random, int limit) const 64 query<lemma> database::lemmas(filter where, order sortOrder, 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), std::move(sortOrder), limit);
67 } 67 }
68 68
69 query<form> database::forms(filter where, bool random, int limit) const 69 query<form> database::forms(filter where, order sortOrder, 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), std::move(sortOrder), limit);
72 } 72 }
73 73
74 query<pronunciation> database::pronunciations(filter where, bool random, int limit) const 74 query<pronunciation> database::pronunciations(filter where, order sortOrder, 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), std::move(sortOrder), limit);
77 }
78
79 std::set<std::string> database::synrestrs(int partId) const
80 {
81 std::string queryString = "SELECT synrestr FROM synrestrs WHERE part_id = ?";
82
83 sqlite3_stmt* ppstmt;
84 if (sqlite3_prepare_v2(ppdb_, queryString.c_str(), queryString.length(), &ppstmt, NULL) != SQLITE_OK)
85 {
86 std::string errorMsg = sqlite3_errmsg(ppdb_);
87 sqlite3_finalize(ppstmt);
88
89 throw database_error("Error preparing query", errorMsg);
90 }
91
92 if (sqlite3_bind_int(ppstmt, 1, partId) != SQLITE_OK)
93 {
94 std::string errorMsg = sqlite3_errmsg(ppdb_);
95 sqlite3_finalize(ppstmt);
96
97 throw database_error("Error binding value to query", errorMsg);
98 }
99
100 std::set<std::string> result;
101 while (sqlite3_step(ppstmt) == SQLITE_ROW)
102 {
103 result.insert(reinterpret_cast<const char*>(sqlite3_column_blob(ppstmt, 0)));
104 }
105
106 sqlite3_finalize(ppstmt);
107
108 return result;
77 } 109 }
78 110
79}; 111};
diff --git a/lib/database.h b/lib/database.h index ef50739..0b10eba 100644 --- a/lib/database.h +++ b/lib/database.h
@@ -4,13 +4,15 @@
4#include <string> 4#include <string>
5#include <exception> 5#include <exception>
6#include <list> 6#include <list>
7#include <set>
7#include "notion.h" 8#include "notion.h"
8#include "word.h" 9#include "word.h"
9#include "group.h"
10#include "frame.h" 10#include "frame.h"
11#include "part.h"
11#include "lemma.h" 12#include "lemma.h"
12#include "form.h" 13#include "form.h"
13#include "pronunciation.h" 14#include "pronunciation.h"
15#include "order.h"
14 16
15struct sqlite3; 17struct sqlite3;
16 18
@@ -46,19 +48,21 @@ namespace verbly {
46 48
47 // Queries 49 // Queries
48 50
49 query<notion> notions(filter where, bool random = true, int limit = 1) const; 51 query<notion> notions(filter where, order sortOrder = {}, int limit = 1) const;
50 52
51 query<word> words(filter where, bool random = true, int limit = 1) const; 53 query<word> words(filter where, order sortOrder = {}, int limit = 1) const;
52 54
53 query<group> groups(filter where, bool random = true, int limit = 1) const; 55 query<frame> frames(filter where, order sortOrder = {}, int limit = 1) const;
54 56
55 query<frame> frames(filter where, bool random = true, int limit = 1) const; 57 query<part> parts(filter where, order sortOrder = {}, int limit = 1) const;
56 58
57 query<lemma> lemmas(filter where, bool random = true, int limit = 1) const; 59 query<lemma> lemmas(filter where, order sortOrder = {}, int limit = 1) const;
58 60
59 query<form> forms(filter where, bool random = true, int limit = 1) const; 61 query<form> forms(filter where, order sortOrder = {}, int limit = 1) const;
60 62
61 query<pronunciation> pronunciations(filter where, bool random = true, int limit = 1) const; 63 query<pronunciation> pronunciations(filter where, order sortOrder = {}, int limit = 1) const;
64
65 std::set<std::string> synrestrs(int partId) const;
62 66
63 private: 67 private:
64 68
diff --git a/lib/enums.h b/lib/enums.h index e634959..2646fa4 100644 --- a/lib/enums.h +++ b/lib/enums.h
@@ -33,13 +33,23 @@ namespace verbly {
33 undefined = -1, 33 undefined = -1,
34 notion = 0, 34 notion = 0,
35 word = 1, 35 word = 1,
36 group = 2, 36 frame = 2,
37 frame = 3, 37 part = 3,
38 lemma = 4, 38 lemma = 4,
39 form = 5, 39 form = 5,
40 pronunciation = 6 40 pronunciation = 6
41 }; 41 };
42 42
43 enum class part_type {
44 invalid = -1,
45 noun_phrase = 0,
46 verb = 1,
47 preposition = 2,
48 adjective = 3,
49 adverb = 4,
50 literal = 5
51 };
52
43}; 53};
44 54
45#endif /* end of include guard: ENUMS_H_260BA847 */ 55#endif /* end of include guard: ENUMS_H_260BA847 */
diff --git a/lib/field.cpp b/lib/field.cpp index deecb06..5b51ef4 100644 --- a/lib/field.cpp +++ b/lib/field.cpp
@@ -48,6 +48,11 @@ namespace verbly {
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==(part_type value) const
52 {
53 return filter(*this, filter::comparison::int_equals, static_cast<int>(value));
54 }
55
51 filter field::operator==(bool value) const 56 filter field::operator==(bool value) const
52 { 57 {
53 return filter(*this, filter::comparison::boolean_equals, value); 58 return filter(*this, filter::comparison::boolean_equals, value);
@@ -68,6 +73,21 @@ namespace verbly {
68 return filter(*this, filter::comparison::string_is_like, std::move(value)); 73 return filter(*this, filter::comparison::string_is_like, std::move(value));
69 } 74 }
70 75
76 filter field::operator==(const char* value) const
77 {
78 return filter(*this, filter::comparison::string_equals, std::string(value));
79 }
80
81 filter field::operator!=(const char* value) const
82 {
83 return filter(*this, filter::comparison::string_does_not_equal, std::string(value));
84 }
85
86 filter field::operator%=(const char* value) const
87 {
88 return filter(*this, filter::comparison::string_is_like, std::string(value));
89 }
90
71 field::operator filter() const 91 field::operator filter() const
72 { 92 {
73 if (isJoin()) 93 if (isJoin())
diff --git a/lib/field.h b/lib/field.h index f61e038..b4bf02d 100644 --- a/lib/field.h +++ b/lib/field.h
@@ -17,6 +17,7 @@ namespace verbly {
17 integer, 17 integer,
18 boolean, 18 boolean,
19 join, 19 join,
20 join_where,
20 join_through, 21 join_through,
21 hierarchal_join 22 hierarchal_join
22 }; 23 };
@@ -95,6 +96,17 @@ namespace verbly {
95 return field(obj, type::join, name, nullable, table); 96 return field(obj, type::join, name, nullable, table);
96 } 97 }
97 98
99 static field joinWhere(
100 object obj,
101 const char* name,
102 object joinWith,
103 const field& conditionField,
104 int conditionValue,
105 bool nullable = false)
106 {
107 return field(obj, type::join_where, name, nullable, 0, joinWith, 0, 0, 0, &conditionField, conditionValue);
108 }
109
98 static field joinThrough( 110 static field joinThrough(
99 object obj, 111 object obj,
100 const char* name, 112 const char* name,
@@ -151,7 +163,10 @@ namespace verbly {
151 163
152 bool isJoin() const 164 bool isJoin() const
153 { 165 {
154 return ((type_ == type::join) || (type_ == type::join_through) || (type_ == type::hierarchal_join)); 166 return ((type_ == type::join)
167 || (type_ == type::join_where)
168 || (type_ == type::join_through)
169 || (type_ == type::hierarchal_join));
155 } 170 }
156 171
157 const char* getColumn() const 172 const char* getColumn() const
@@ -180,7 +195,7 @@ namespace verbly {
180 { 195 {
181 return (type_ == type::hierarchal_join) 196 return (type_ == type::hierarchal_join)
182 ? object_ 197 ? object_
183 : ((type_ == type::join) || (type_ == type::join_through)) 198 : ((type_ == type::join) || (type_ == type::join_where) || (type_ == type::join_through))
184 ? joinObject_ 199 ? joinObject_
185 : throw std::domain_error("Non-join fields don't have join objects"); 200 : throw std::domain_error("Non-join fields don't have join objects");
186 } 201 }
@@ -209,6 +224,22 @@ namespace verbly {
209 : throw std::domain_error("Only many-to-many join fields have a foreign join column"); 224 : throw std::domain_error("Only many-to-many join fields have a foreign join column");
210 } 225 }
211 226
227 // Condition joins
228
229 const field& getConditionField() const
230 {
231 return (type_ == type::join_where)
232 ? *conditionField_
233 : throw std::domain_error("Only condition join fields have a condition field");
234 }
235
236 int getConditionValue() const
237 {
238 return (type_ == type::join_where)
239 ? conditionValue_
240 : throw std::domain_error("Only condition join fields have a condition value");
241 }
242
212 // Ordering 243 // Ordering
213 244
214 bool operator<(const field& other) const 245 bool operator<(const field& other) const
@@ -217,20 +248,30 @@ namespace verbly {
217 // However, there do exist a number of relationships from an object to 248 // However, there do exist a number of relationships from an object to
218 // itself, such as notion hypernymy/hyponymy. Hypernymy and hyponymy have 249 // itself, such as notion hypernymy/hyponymy. Hypernymy and hyponymy have
219 // the same object (notion), the same column (notion_id), and the same 250 // the same object (notion), the same column (notion_id), and the same
220 // table (hypernymy); however, they have different join columns. 251 // table (hypernymy); however, they have different join columns. For
221 return std::tie(object_, column_, table_, joinColumn_) < std::tie(other.object_, other.column_, other.table_, other.joinColumn_); 252 // condition joins, the condition field and condition value are also
253 // significant.
254 if (conditionField_)
255 {
256 return std::tie(object_, column_, table_, joinColumn_, *conditionField_, conditionValue_)
257 < std::tie(other.object_, other.column_, other.table_, other.joinColumn_, *other.conditionField_, other.conditionValue_);
258 } else {
259 return std::tie(object_, column_, table_, joinColumn_) < std::tie(other.object_, other.column_, other.table_, other.joinColumn_);
260 }
222 } 261 }
223 262
224 // Equality 263 // Equality
225 264
226 bool operator==(const field& other) const 265 bool operator==(const field& other) const
227 { 266 {
228 // For the most part, (object, column) uniquely identifies fields. 267 // See operator<() for documentation.
229 // However, there do exist a number of relationships from an object to 268 if (conditionField_)
230 // itself, such as notion hypernymy/hyponymy. Hypernymy and hyponymy have 269 {
231 // the same object (notion), the same column (notion_id), and the same 270 return std::tie(object_, column_, table_, joinColumn_, *conditionField_, conditionValue_)
232 // table (hypernymy); however, they have different join columns. 271 == std::tie(other.object_, other.column_, other.table_, other.joinColumn_, *other.conditionField_, other.conditionValue_);
233 return std::tie(object_, column_, table_, joinColumn_) == std::tie(other.object_, other.column_, other.table_, other.joinColumn_); 272 } else {
273 return std::tie(object_, column_, table_, joinColumn_) == std::tie(other.object_, other.column_, other.table_, other.joinColumn_);
274 }
234 } 275 }
235 276
236 // Filter construction 277 // Filter construction
@@ -245,6 +286,7 @@ namespace verbly {
245 filter operator==(part_of_speech value) const; // Part of speech equality 286 filter operator==(part_of_speech value) const; // Part of speech equality
246 filter operator==(positioning value) const; // Adjective positioning equality 287 filter operator==(positioning value) const; // Adjective positioning equality
247 filter operator==(inflection value) const; // Inflection category equality 288 filter operator==(inflection value) const; // Inflection category equality
289 filter operator==(part_type value) const; // Verb frame part type equality
248 290
249 filter operator==(bool value) const; // Boolean equality 291 filter operator==(bool value) const; // Boolean equality
250 292
@@ -252,6 +294,10 @@ namespace verbly {
252 filter operator!=(std::string value) const; // String inequality 294 filter operator!=(std::string value) const; // String inequality
253 filter operator%=(std::string value) const; // String matching 295 filter operator%=(std::string value) const; // String matching
254 296
297 filter operator==(const char* value) const; // String equality
298 filter operator!=(const char* value) const; // String inequality
299 filter operator%=(const char* value) const; // String matching
300
255 operator filter() const; // Non-nullity 301 operator filter() const; // Non-nullity
256 filter operator!() const; // Nullity 302 filter operator!() const; // Nullity
257 303
@@ -270,7 +316,9 @@ namespace verbly {
270 object joinObject = object::undefined, 316 object joinObject = object::undefined,
271 const char* foreignColumn = 0, 317 const char* foreignColumn = 0,
272 const char* joinColumn = 0, 318 const char* joinColumn = 0,
273 const char* foreignJoinColumn = 0) : 319 const char* foreignJoinColumn = 0,
320 const field* conditionField = 0,
321 int conditionValue = 0) :
274 object_(obj), 322 object_(obj),
275 type_(datatype), 323 type_(datatype),
276 column_(column), 324 column_(column),
@@ -279,7 +327,9 @@ namespace verbly {
279 joinObject_(joinObject), 327 joinObject_(joinObject),
280 foreignColumn_(foreignColumn), 328 foreignColumn_(foreignColumn),
281 joinColumn_(joinColumn), 329 joinColumn_(joinColumn),
282 foreignJoinColumn_(foreignJoinColumn) 330 foreignJoinColumn_(foreignJoinColumn),
331 conditionField_(conditionField),
332 conditionValue_(conditionValue)
283 { 333 {
284 } 334 }
285 335
@@ -300,6 +350,10 @@ namespace verbly {
300 const char* joinColumn_ = 0; 350 const char* joinColumn_ = 0;
301 const char* foreignJoinColumn_ = 0; 351 const char* foreignJoinColumn_ = 0;
302 352
353 // Condition joins
354 const field* conditionField_ = 0;
355 int conditionValue_ = 0;
356
303 }; 357 };
304 358
305}; 359};
diff --git a/lib/filter.cpp b/lib/filter.cpp index ceb9327..ab46df2 100644 --- a/lib/filter.cpp +++ b/lib/filter.cpp
@@ -3,8 +3,8 @@
3#include <map> 3#include <map>
4#include "notion.h" 4#include "notion.h"
5#include "word.h" 5#include "word.h"
6#include "group.h"
7#include "frame.h" 6#include "frame.h"
7#include "part.h"
8#include "lemma.h" 8#include "lemma.h"
9#include "form.h" 9#include "form.h"
10#include "pronunciation.h" 10#include "pronunciation.h"
@@ -594,6 +594,7 @@ namespace verbly {
594 switch (joinOn.getType()) 594 switch (joinOn.getType())
595 { 595 {
596 case field::type::join: 596 case field::type::join:
597 case field::type::join_where:
597 case field::type::join_through: 598 case field::type::join_through:
598 { 599 {
599 switch (filterType) 600 switch (filterType)
@@ -1108,8 +1109,8 @@ namespace verbly {
1108 } 1109 }
1109 1110
1110 case object::word: 1111 case object::word:
1111 case object::group:
1112 case object::frame: 1112 case object::frame:
1113 case object::part:
1113 case object::lemma: 1114 case object::lemma:
1114 case object::form: 1115 case object::form:
1115 case object::pronunciation: 1116 case object::pronunciation:
@@ -1134,10 +1135,10 @@ namespace verbly {
1134 return *this; 1135 return *this;
1135 } 1136 }
1136 1137
1137 case object::group:
1138 case object::frame: 1138 case object::frame:
1139 case object::part:
1139 { 1140 {
1140 return (verbly::word::group %= *this); 1141 return (verbly::word::frame %= *this);
1141 } 1142 }
1142 1143
1143 case object::lemma: 1144 case object::lemma:
@@ -1148,12 +1149,12 @@ namespace verbly {
1148 } 1149 }
1149 } 1150 }
1150 1151
1151 case object::group: 1152 case object::frame:
1152 { 1153 {
1153 switch (singleton_.filterField.getObject()) 1154 switch (singleton_.filterField.getObject())
1154 { 1155 {
1155 case object::undefined: 1156 case object::undefined:
1156 case object::group: 1157 case object::frame:
1157 { 1158 {
1158 return *this; 1159 return *this;
1159 } 1160 }
@@ -1164,34 +1165,34 @@ namespace verbly {
1164 case object::form: 1165 case object::form:
1165 case object::pronunciation: 1166 case object::pronunciation:
1166 { 1167 {
1167 return (verbly::group::word %= *this); 1168 return (verbly::frame::word %= *this);
1168 } 1169 }
1169 1170
1170 case object::frame: 1171 case object::part:
1171 { 1172 {
1172 return (verbly::group::frame %= *this); 1173 return (verbly::frame::part() %= *this);
1173 } 1174 }
1174 } 1175 }
1175 } 1176 }
1176 1177
1177 case object::frame: 1178 case object::part:
1178 { 1179 {
1179 switch (singleton_.filterField.getObject()) 1180 switch (singleton_.filterField.getObject())
1180 { 1181 {
1181 case object::undefined: 1182 case object::undefined:
1182 case object::frame: 1183 case object::part:
1183 { 1184 {
1184 return *this; 1185 return *this;
1185 } 1186 }
1186 1187
1187 case object::notion: 1188 case object::notion:
1188 case object::word: 1189 case object::word:
1189 case object::group: 1190 case object::frame:
1190 case object::lemma: 1191 case object::lemma:
1191 case object::form: 1192 case object::form:
1192 case object::pronunciation: 1193 case object::pronunciation:
1193 { 1194 {
1194 return (verbly::frame::group %= *this); 1195 return (verbly::part::frame %= *this);
1195 } 1196 }
1196 } 1197 }
1197 } 1198 }
@@ -1202,8 +1203,8 @@ namespace verbly {
1202 { 1203 {
1203 case object::notion: 1204 case object::notion:
1204 case object::word: 1205 case object::word:
1205 case object::group:
1206 case object::frame: 1206 case object::frame:
1207 case object::part:
1207 { 1208 {
1208 return verbly::lemma::word %= *this; 1209 return verbly::lemma::word %= *this;
1209 } 1210 }
@@ -1228,11 +1229,11 @@ namespace verbly {
1228 { 1229 {
1229 case object::notion: 1230 case object::notion:
1230 case object::word: 1231 case object::word:
1231 case object::group:
1232 case object::frame: 1232 case object::frame:
1233 case object::part:
1233 case object::lemma: 1234 case object::lemma:
1234 { 1235 {
1235 return verbly::form::lemma(inflection::base) %= *this; 1236 return verbly::form::lemma %= *this;
1236 } 1237 }
1237 1238
1238 case object::undefined: 1239 case object::undefined:
@@ -1254,8 +1255,8 @@ namespace verbly {
1254 { 1255 {
1255 case object::notion: 1256 case object::notion:
1256 case object::word: 1257 case object::word:
1257 case object::group:
1258 case object::frame: 1258 case object::frame:
1259 case object::part:
1259 case object::lemma: 1260 case object::lemma:
1260 case object::form: 1261 case object::form:
1261 { 1262 {
diff --git a/lib/form.cpp b/lib/form.cpp index 5d4c343..4811f14 100644 --- a/lib/form.cpp +++ b/lib/form.cpp
@@ -16,11 +16,9 @@ namespace verbly {
16 const field form::complexity = field::integerField(object::form, "complexity"); 16 const field form::complexity = field::integerField(object::form, "complexity");
17 const field form::proper = field::booleanField(object::form, "proper"); 17 const field form::proper = field::booleanField(object::form, "proper");
18 18
19 const field form::lemma = field::joinField(object::form, "form_id", object::lemma);
19 const field form::pronunciation = field::joinThrough(object::form, "form_id", object::pronunciation, "forms_pronunciations", "pronunciation_id"); 20 const field form::pronunciation = field::joinThrough(object::form, "form_id", object::pronunciation, "forms_pronunciations", "pronunciation_id");
20 21
21 const field form::lemmaJoin = field::joinField(object::form, "form_id", object::lemma);
22 const field form::inflectionCategory = field::integerField("lemmas_forms", "category");
23
24 form::form(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) 22 form::form(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
25 { 23 {
26 id_ = sqlite3_column_int(row, 0); 24 id_ = sqlite3_column_int(row, 0);
@@ -29,16 +27,6 @@ namespace verbly {
29 proper_ = (sqlite3_column_int(row, 3) == 1); 27 proper_ = (sqlite3_column_int(row, 3) == 1);
30 } 28 }
31 29
32 filter operator%=(form::inflection_field check, filter joinCondition)
33 {
34 return (form::lemmaJoin %= (joinCondition && (form::inflectionCategory == check.getCategory())));
35 }
36
37 form::inflection_field::operator filter() const
38 {
39 return (form::lemmaJoin %= (form::inflectionCategory == category_));
40 }
41
42 const std::vector<pronunciation>& form::getPronunciations() const 30 const std::vector<pronunciation>& form::getPronunciations() const
43 { 31 {
44 if (!valid_) 32 if (!valid_)
@@ -48,7 +36,7 @@ namespace verbly {
48 36
49 if (!initializedPronunciations_) 37 if (!initializedPronunciations_)
50 { 38 {
51 pronunciations_ = db_->pronunciations(pronunciation::form %= *this, false, -1).all(); 39 pronunciations_ = db_->pronunciations(pronunciation::form %= *this, verbly::pronunciation::id, -1).all();
52 initializedPronunciations_ = true; 40 initializedPronunciations_ = true;
53 } 41 }
54 42
diff --git a/lib/form.h b/lib/form.h index aca5b2f..cf64117 100644 --- a/lib/form.h +++ b/lib/form.h
@@ -104,33 +104,9 @@ namespace verbly {
104 104
105 // Relationships to other objects 105 // Relationships to other objects
106 106
107 static const field pronunciation; 107 static const field lemma;
108
109 class inflection_field {
110 public:
111
112 inflection_field(inflection category) : category_(category)
113 {
114 }
115
116 const inflection getCategory() const
117 {
118 return category_;
119 }
120 108
121 operator filter() const; 109 static const field pronunciation;
122
123 private:
124
125 const inflection category_;
126 };
127
128 static const inflection_field lemma(inflection category)
129 {
130 return inflection_field(category);
131 }
132
133 friend filter operator%=(form::inflection_field check, filter joinCondition);
134 110
135 private: 111 private:
136 bool valid_ = false; 112 bool valid_ = false;
@@ -145,9 +121,6 @@ namespace verbly {
145 mutable bool initializedPronunciations_ = false; 121 mutable bool initializedPronunciations_ = false;
146 mutable std::vector<class pronunciation> pronunciations_; 122 mutable std::vector<class pronunciation> pronunciations_;
147 123
148 static const field lemmaJoin;
149 static const field inflectionCategory;
150
151 }; 124 };
152 125
153}; 126};
diff --git a/lib/frame.cpp b/lib/frame.cpp index 8cab56b..a73fbda 100644 --- a/lib/frame.cpp +++ b/lib/frame.cpp
@@ -1,95 +1,36 @@
1#include "frame.h" 1#include "frame.h"
2#include <sqlite3.h> 2#include <sqlite3.h>
3#include <json.hpp> 3#include "database.h"
4#include "query.h"
4 5
5namespace verbly { 6namespace verbly {
6 7
7 const object frame::objectType = object::frame; 8 const object frame::objectType = object::frame;
8 9
9 const std::list<std::string> frame::select = {"frame_id", "data"}; 10 const std::list<std::string> frame::select = {"frame_id", "group_id", "length"};
10 11
11 const field frame::id = field::integerField(object::frame, "frame_id"); 12 const field frame::id = field::integerField(object::frame, "frame_id");
13 const field frame::length = field::integerField(object::frame, "length");
12 14
13 const field frame::group = field::joinThrough(object::frame, "frame_id", object::group, "groups_frames", "group_id"); 15 const field frame::word = field::joinField(object::frame, "group_id", object::word);
14 16
15 frame::frame(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) 17 field frame::part()
16 { 18 {
17 id_ = sqlite3_column_int(row, 0); 19 return field::joinField(object::frame, "frame_id", object::part);
18 20 }
19 std::string partsJsonStr(reinterpret_cast<const char*>(sqlite3_column_blob(row, 1)));
20 nlohmann::json partsJson = nlohmann::json::parse(std::move(partsJsonStr));
21
22 for (const nlohmann::json& partJson : partsJson)
23 {
24 part::type partType = static_cast<part::type>(partJson["type"].get<int>());
25
26 switch (partType)
27 {
28 case part::type::noun_phrase:
29 {
30 std::set<std::string> synrestrs;
31 for (const nlohmann::json& synrestrJson : partJson["synrestrs"])
32 {
33 synrestrs.insert(synrestrJson.get<std::string>());
34 }
35
36 parts_.push_back(part::createNounPhrase(
37 partJson["role"].get<std::string>(),
38 selrestr(partJson["selrestrs"]),
39 std::move(synrestrs)));
40
41 break;
42 }
43
44 case part::type::preposition:
45 {
46 std::vector<std::string> choices;
47 for (const nlohmann::json& choiceJson : partJson["choices"])
48 {
49 choices.push_back(choiceJson.get<std::string>());
50 }
51
52 parts_.push_back(part::createPreposition(
53 std::move(choices),
54 partJson["literal"].get<bool>()));
55
56 break;
57 }
58
59 case part::type::verb:
60 {
61 parts_.push_back(part::createVerb());
62
63 break;
64 }
65
66 case part::type::adjective:
67 {
68 parts_.push_back(part::createAdjective());
69
70 break;
71 }
72
73 case part::type::adverb:
74 {
75 parts_.push_back(part::createAdverb());
76
77 break;
78 }
79 21
80 case part::type::literal: 22 field frame::part(int index)
81 { 23 {
82 parts_.push_back(part::createLiteral(partJson["value"].get<std::string>())); 24 return field::joinWhere(object::frame, "frame_id", object::part, part::index, index);
25 }
83 26
84 break; 27 frame::frame(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
85 } 28 {
29 id_ = sqlite3_column_int(row, 0);
30 groupId_ = sqlite3_column_int(row, 1);
31 length_ = sqlite3_column_int(row, 2);
86 32
87 case part::type::invalid: 33 parts_ = db.parts(*this, verbly::part::index, -1).all();
88 {
89 throw std::domain_error("Invalid part data");
90 }
91 }
92 }
93 } 34 }
94 35
95}; 36};
diff --git a/lib/frame.h b/lib/frame.h index 97473a0..36e179e 100644 --- a/lib/frame.h +++ b/lib/frame.h
@@ -41,6 +41,16 @@ namespace verbly {
41 return id_; 41 return id_;
42 } 42 }
43 43
44 int getLength() const
45 {
46 if (!valid_)
47 {
48 throw std::domain_error("Bad access to uninitialized frame");
49 }
50
51 return length_;
52 }
53
44 const std::vector<part>& getParts() const 54 const std::vector<part>& getParts() const
45 { 55 {
46 if (!valid_) 56 if (!valid_)
@@ -61,6 +71,8 @@ namespace verbly {
61 71
62 static const field id; 72 static const field id;
63 73
74 static const field length;
75
64 operator filter() const 76 operator filter() const
65 { 77 {
66 if (!valid_) 78 if (!valid_)
@@ -73,13 +85,18 @@ namespace verbly {
73 85
74 // Relationships to other objects 86 // Relationships to other objects
75 87
76 static const field group; 88 static const field word;
89
90 static field part();
91 static field part(int index);
77 92
78 private: 93 private:
79 bool valid_ = false; 94 bool valid_ = false;
80 95
81 int id_; 96 int id_;
82 std::vector<part> parts_; 97 int groupId_;
98 int length_;
99 std::vector<class part> parts_;
83 100
84 const database* db_; 101 const database* db_;
85 102
diff --git a/lib/group.cpp b/lib/group.cpp deleted file mode 100644 index d5790e9..0000000 --- a/lib/group.cpp +++ /dev/null
@@ -1,61 +0,0 @@
1#include "group.h"
2#include <sqlite3.h>
3#include <json.hpp>
4#include "database.h"
5#include "query.h"
6
7namespace verbly {
8
9 const object group::objectType = object::group;
10
11 const std::list<std::string> group::select = {"group_id", "data"};
12
13 const field group::id = field::integerField(object::group, "group_id");
14
15 const field group::frame = field::joinThrough(object::group, "group_id", object::frame, "groups_frames", "frame_id");
16 const field group::word = field::joinField(object::group, "group_id", object::word);
17
18 group::group(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
19 {
20 id_ = sqlite3_column_int(row, 0);
21
22 std::string rolesJsonStr(reinterpret_cast<const char*>(sqlite3_column_blob(row, 1)));
23 nlohmann::json rolesJson = nlohmann::json::parse(std::move(rolesJsonStr));
24 for (const nlohmann::json& roleJson : rolesJson)
25 {
26 std::string roleName = roleJson["type"];
27 selrestr roleSelrestr;
28
29 if (roleJson.find("selrestrs") != roleJson.end())
30 {
31 roleSelrestr = selrestr(roleJson["selrestrs"]);
32 }
33
34 roles_[roleName] = role(roleName, std::move(roleSelrestr));
35 }
36 }
37
38 const std::vector<frame>& group::getFrames() const
39 {
40 if (!valid_)
41 {
42 throw std::domain_error("Bad access to uninitialized group");
43 }
44
45 if (!initializedFrames_)
46 {
47 frames_ = db_->frames(frame::group %= *this, false, -1).all();
48
49 initializedFrames_ = true;
50 }
51
52 return frames_;
53 }
54
55 const role& group::getRole(std::string roleName) const
56 {
57 return roles_.at(roleName);
58 }
59
60};
61
diff --git a/lib/group.h b/lib/group.h deleted file mode 100644 index fe62d39..0000000 --- a/lib/group.h +++ /dev/null
@@ -1,91 +0,0 @@
1#ifndef GROUP_H_BD6933C0
2#define GROUP_H_BD6933C0
3
4#include <stdexcept>
5#include <list>
6#include <vector>
7#include "field.h"
8#include "filter.h"
9#include "frame.h"
10#include "role.h"
11
12struct sqlite3_stmt;
13
14namespace verbly {
15
16 class database;
17
18 class group {
19 public:
20
21 // Default constructor
22
23 group() = default;
24
25 // Construct from database
26
27 group(const database& db, sqlite3_stmt* row);
28
29 // Accessors
30
31 operator bool() const
32 {
33 return valid_;
34 }
35
36 int getId() const
37 {
38 if (!valid_)
39 {
40 throw std::domain_error("Bad access to uninitialized group");
41 }
42
43 return id_;
44 }
45
46 const std::vector<frame>& getFrames() const;
47
48 const role& getRole(std::string roleName) const;
49
50 // Type info
51
52 static const object objectType;
53
54 static const std::list<std::string> select;
55
56 // Query fields
57
58 static const field id;
59
60 operator filter() const
61 {
62 if (!valid_)
63 {
64 throw std::domain_error("Bad access to uninitialized group");
65 }
66
67 return (id == id_);
68 }
69
70 // Relationships to other objects
71
72 static const field frame;
73
74 static const field word;
75
76 private:
77 bool valid_ = false;
78
79 int id_;
80 std::map<std::string, role> roles_;
81
82 const database* db_;
83
84 mutable bool initializedFrames_ = false;
85 mutable std::vector<class frame> frames_;
86
87 };
88
89};
90
91#endif /* end of include guard: GROUP_H_BD6933C0 */
diff --git a/lib/lemma.cpp b/lib/lemma.cpp index 1601460..0c6e99e 100644 --- a/lib/lemma.cpp +++ b/lib/lemma.cpp
@@ -10,20 +10,13 @@ namespace verbly {
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
14 const field lemma::word = field::joinField(object::lemma, "lemma_id", object::word);
15
16 const field lemma::formJoin = field::joinField(object::lemma, "form_id", object::form);
17 const field lemma::inflectionCategory = field::integerField(object::lemma, "category"); 13 const field lemma::inflectionCategory = field::integerField(object::lemma, "category");
18 14
19 filter operator%=(lemma::inflection_field check, filter joinCondition) 15 const field lemma::word = field::joinField(object::lemma, "lemma_id", object::word);
20 {
21 return (lemma::formJoin %= joinCondition) && (lemma::inflectionCategory == check.getCategory());
22 }
23 16
24 lemma::inflection_field::operator filter() const 17 field lemma::form(inflection category)
25 { 18 {
26 return (lemma::inflectionCategory == category_); 19 return field::joinWhere(object::lemma, "form_id", object::form, inflectionCategory, static_cast<int>(category));
27 } 20 }
28 21
29 lemma::lemma(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true) 22 lemma::lemma(const database& db, sqlite3_stmt* row) : db_(&db), valid_(true)
@@ -68,7 +61,7 @@ namespace verbly {
68 61
69 void lemma::initializeForm(inflection infl) const 62 void lemma::initializeForm(inflection infl) const
70 { 63 {
71 forms_[infl] = db_->forms(form::lemma(infl) %= *this, false, -1).all(); 64 forms_[infl] = db_->forms(form::lemma %= ((inflectionCategory == infl) && *this), verbly::form::id, -1).all();
72 } 65 }
73 66
74}; 67};
diff --git a/lib/lemma.h b/lib/lemma.h index 407fa3c..56cfc56 100644 --- a/lib/lemma.h +++ b/lib/lemma.h
@@ -74,31 +74,7 @@ namespace verbly {
74 74
75 static const field word; 75 static const field word;
76 76
77 class inflection_field { 77 static field form(inflection category);
78 public:
79
80 inflection_field(inflection category) : category_(category)
81 {
82 }
83
84 const inflection getCategory() const
85 {
86 return category_;
87 }
88
89 operator filter() const;
90
91 private:
92
93 const inflection category_;
94 };
95
96 static const inflection_field form(inflection category)
97 {
98 return inflection_field(category);
99 }
100
101 friend filter operator%=(lemma::inflection_field check, filter joinCondition);
102 78
103 private: 79 private:
104 80
@@ -112,7 +88,6 @@ namespace verbly {
112 88
113 const database* db_; 89 const database* db_;
114 90
115 static const field formJoin;
116 static const field inflectionCategory; 91 static const field inflectionCategory;
117 92
118 }; 93 };
diff --git a/lib/order.h b/lib/order.h new file mode 100644 index 0000000..d2f0f92 --- /dev/null +++ b/lib/order.h
@@ -0,0 +1,69 @@
1#ifndef ORDER_H_0EC669D5
2#define ORDER_H_0EC669D5
3
4#include <stdexcept>
5#include "field.h"
6
7namespace verbly {
8
9 class order {
10 public:
11 enum class type {
12 random,
13 field
14 };
15
16 // Type
17
18 type getType() const
19 {
20 return type_;
21 }
22
23 // Random
24
25 order() : type_(type::random)
26 {
27 }
28
29 // Field
30
31 order(
32 field arg,
33 bool asc = true) :
34 type_(type::field),
35 sortField_(std::move(arg)),
36 ascending_(asc)
37 {
38 }
39
40 field getSortField() const
41 {
42 if (type_ != type::field)
43 {
44 throw std::domain_error("Invalid access to non-field order");
45 }
46
47 return sortField_;
48 }
49
50 bool isAscending() const
51 {
52 if (type_ != type::field)
53 {
54 throw std::domain_error("Invalid access to non-field order");
55 }
56
57 return ascending_;
58 }
59
60 private:
61 type type_;
62 field sortField_;
63 bool ascending_;
64
65 };
66
67};
68
69#endif /* end of include guard: ORDER_H_0EC669D5 */
diff --git a/lib/part.cpp b/lib/part.cpp index e66d151..1fbb24d 100644 --- a/lib/part.cpp +++ b/lib/part.cpp
@@ -1,12 +1,30 @@
1#include "part.h" 1#include "part.h"
2#include <stdexcept> 2#include <stdexcept>
3#include <sqlite3.h>
3#include "selrestr.h" 4#include "selrestr.h"
5#include "database.h"
4 6
5namespace verbly { 7namespace verbly {
6 8
9 const object part::objectType = object::part;
10
11 const std::list<std::string> part::select = {"part_id", "frame_id", "part_index", "type", "role", "selrestrs", "prepositions", "preposition_literality", "literal_value"};
12
13 const field part::index = field::integerField(object::part, "part_index");
14 const field part::type = field::integerField(object::part, "type");
15
16 const field part::role = field::stringField(object::part, "role", true);
17
18 const field part::frame = field::joinField(object::part, "frame_id", object::frame);
19
20 const field part::synrestr_field::synrestrJoin = field::joinField(object::part, "part_id", "synrestrs");
21 const field part::synrestr_field::synrestrField = field::stringField("synrestrs", "synrestr");
22
23 const part::synrestr_field part::synrestr = {};
24
7 part part::createNounPhrase(std::string role, selrestr selrestrs, std::set<std::string> synrestrs) 25 part part::createNounPhrase(std::string role, selrestr selrestrs, std::set<std::string> synrestrs)
8 { 26 {
9 part p(type::noun_phrase); 27 part p(part_type::noun_phrase);
10 28
11 new(&p.noun_phrase_.role) std::string(std::move(role)); 29 new(&p.noun_phrase_.role) std::string(std::move(role));
12 new(&p.noun_phrase_.selrestrs) selrestr(std::move(selrestrs)); 30 new(&p.noun_phrase_.selrestrs) selrestr(std::move(selrestrs));
@@ -17,12 +35,12 @@ namespace verbly {
17 35
18 part part::createVerb() 36 part part::createVerb()
19 { 37 {
20 return part(type::verb); 38 return part(part_type::verb);
21 } 39 }
22 40
23 part part::createPreposition(std::vector<std::string> choices, bool literal) 41 part part::createPreposition(std::vector<std::string> choices, bool literal)
24 { 42 {
25 part p(type::preposition); 43 part p(part_type::preposition);
26 44
27 new(&p.preposition_.choices) std::vector<std::string>(std::move(choices)); 45 new(&p.preposition_.choices) std::vector<std::string>(std::move(choices));
28 p.preposition_.literal = literal; 46 p.preposition_.literal = literal;
@@ -32,30 +50,79 @@ namespace verbly {
32 50
33 part part::createAdjective() 51 part part::createAdjective()
34 { 52 {
35 return part(type::adjective); 53 return part(part_type::adjective);
36 } 54 }
37 55
38 part part::createAdverb() 56 part part::createAdverb()
39 { 57 {
40 return part(type::adverb); 58 return part(part_type::adverb);
41 } 59 }
42 60
43 part part::createLiteral(std::string value) 61 part part::createLiteral(std::string value)
44 { 62 {
45 part p(type::literal); 63 part p(part_type::literal);
46 64
47 new(&p.literal_) std::string(std::move(value)); 65 new(&p.literal_) std::string(std::move(value));
48 66
49 return p; 67 return p;
50 } 68 }
51 69
70 part::part(const database& db, sqlite3_stmt* row)
71 {
72 int id = sqlite3_column_int(row, 0);
73
74 type_ = static_cast<part_type>(sqlite3_column_int(row, 3));
75
76 switch (type_)
77 {
78 case part_type::noun_phrase:
79 {
80 new(&noun_phrase_.role) std::string(reinterpret_cast<const char*>(sqlite3_column_blob(row, 4)));
81 new(&noun_phrase_.selrestrs) selrestr(nlohmann::json::parse(reinterpret_cast<const char*>(sqlite3_column_blob(row, 5))));
82 new(&noun_phrase_.synrestrs) std::set<std::string>(db.synrestrs(id));
83
84 break;
85 }
86
87 case part_type::preposition:
88 {
89 new(&preposition_.choices) std::vector<std::string>();
90 preposition_.literal = (sqlite3_column_int(row, 7) == 1);
91
92 std::string choicesJsonStr(reinterpret_cast<const char*>(sqlite3_column_blob(row, 6)));
93 nlohmann::json choicesJson = nlohmann::json::parse(std::move(choicesJsonStr));
94 for (const nlohmann::json& choiceJson : choicesJson)
95 {
96 preposition_.choices.push_back(choiceJson.get<std::string>());
97 }
98
99 break;
100 }
101
102 case part_type::literal:
103 {
104 new(&literal_) std::string(reinterpret_cast<const char*>(sqlite3_column_blob(row, 8)));
105
106 break;
107 }
108
109 case part_type::verb:
110 case part_type::adjective:
111 case part_type::adverb:
112 case part_type::invalid:
113 {
114 break;
115 }
116 }
117 }
118
52 part::part(const part& other) 119 part::part(const part& other)
53 { 120 {
54 type_ = other.type_; 121 type_ = other.type_;
55 122
56 switch (type_) 123 switch (type_)
57 { 124 {
58 case type::noun_phrase: 125 case part_type::noun_phrase:
59 { 126 {
60 new(&noun_phrase_.role) std::string(other.noun_phrase_.role); 127 new(&noun_phrase_.role) std::string(other.noun_phrase_.role);
61 new(&noun_phrase_.selrestrs) selrestr(other.noun_phrase_.selrestrs); 128 new(&noun_phrase_.selrestrs) selrestr(other.noun_phrase_.selrestrs);
@@ -64,7 +131,7 @@ namespace verbly {
64 break; 131 break;
65 } 132 }
66 133
67 case type::preposition: 134 case part_type::preposition:
68 { 135 {
69 new(&preposition_.choices) std::vector<std::string>(other.preposition_.choices); 136 new(&preposition_.choices) std::vector<std::string>(other.preposition_.choices);
70 preposition_.literal = other.preposition_.literal; 137 preposition_.literal = other.preposition_.literal;
@@ -72,17 +139,17 @@ namespace verbly {
72 break; 139 break;
73 } 140 }
74 141
75 case type::literal: 142 case part_type::literal:
76 { 143 {
77 new(&literal_) std::string(other.literal_); 144 new(&literal_) std::string(other.literal_);
78 145
79 break; 146 break;
80 } 147 }
81 148
82 case type::verb: 149 case part_type::verb:
83 case type::adjective: 150 case part_type::adjective:
84 case type::adverb: 151 case part_type::adverb:
85 case type::invalid: 152 case part_type::invalid:
86 { 153 {
87 break; 154 break;
88 } 155 }
@@ -103,7 +170,7 @@ namespace verbly {
103 170
104 void swap(part& first, part& second) 171 void swap(part& first, part& second)
105 { 172 {
106 using type = part::type; 173 using type = part_type;
107 174
108 type tempType = first.type_; 175 type tempType = first.type_;
109 std::string tempRole; 176 std::string tempRole;
@@ -231,7 +298,7 @@ namespace verbly {
231 { 298 {
232 switch (type_) 299 switch (type_)
233 { 300 {
234 case type::noun_phrase: 301 case part_type::noun_phrase:
235 { 302 {
236 using string_type = std::string; 303 using string_type = std::string;
237 using set_type = std::set<std::string>; 304 using set_type = std::set<std::string>;
@@ -243,7 +310,7 @@ namespace verbly {
243 break; 310 break;
244 } 311 }
245 312
246 case type::preposition: 313 case part_type::preposition:
247 { 314 {
248 using vector_type = std::vector<std::string>; 315 using vector_type = std::vector<std::string>;
249 316
@@ -252,7 +319,7 @@ namespace verbly {
252 break; 319 break;
253 } 320 }
254 321
255 case type::literal: 322 case part_type::literal:
256 { 323 {
257 using string_type = std::string; 324 using string_type = std::string;
258 325
@@ -261,10 +328,10 @@ namespace verbly {
261 break; 328 break;
262 } 329 }
263 330
264 case type::verb: 331 case part_type::verb:
265 case type::adjective: 332 case part_type::adjective:
266 case type::adverb: 333 case part_type::adverb:
267 case type::invalid: 334 case part_type::invalid:
268 { 335 {
269 break; 336 break;
270 } 337 }
@@ -273,7 +340,7 @@ namespace verbly {
273 340
274 std::string part::getNounRole() const 341 std::string part::getNounRole() const
275 { 342 {
276 if (type_ == type::noun_phrase) 343 if (type_ == part_type::noun_phrase)
277 { 344 {
278 return noun_phrase_.role; 345 return noun_phrase_.role;
279 } else { 346 } else {
@@ -283,7 +350,7 @@ namespace verbly {
283 350
284 selrestr part::getNounSelrestrs() const 351 selrestr part::getNounSelrestrs() const
285 { 352 {
286 if (type_ == type::noun_phrase) 353 if (type_ == part_type::noun_phrase)
287 { 354 {
288 return noun_phrase_.selrestrs; 355 return noun_phrase_.selrestrs;
289 } else { 356 } else {
@@ -293,7 +360,7 @@ namespace verbly {
293 360
294 std::set<std::string> part::getNounSynrestrs() const 361 std::set<std::string> part::getNounSynrestrs() const
295 { 362 {
296 if (type_ == type::noun_phrase) 363 if (type_ == part_type::noun_phrase)
297 { 364 {
298 return noun_phrase_.synrestrs; 365 return noun_phrase_.synrestrs;
299 } else { 366 } else {
@@ -303,7 +370,7 @@ namespace verbly {
303 370
304 bool part::nounHasSynrestr(std::string synrestr) const 371 bool part::nounHasSynrestr(std::string synrestr) const
305 { 372 {
306 if (type_ != type::noun_phrase) 373 if (type_ != part_type::noun_phrase)
307 { 374 {
308 throw std::domain_error("part::nounHasSynrestr is only valid for noun phrase parts"); 375 throw std::domain_error("part::nounHasSynrestr is only valid for noun phrase parts");
309 } 376 }
@@ -313,7 +380,7 @@ namespace verbly {
313 380
314 std::vector<std::string> part::getPrepositionChoices() const 381 std::vector<std::string> part::getPrepositionChoices() const
315 { 382 {
316 if (type_ == type::preposition) 383 if (type_ == part_type::preposition)
317 { 384 {
318 return preposition_.choices; 385 return preposition_.choices;
319 } else { 386 } else {
@@ -323,7 +390,7 @@ namespace verbly {
323 390
324 bool part::isPrepositionLiteral() const 391 bool part::isPrepositionLiteral() const
325 { 392 {
326 if (type_ == type::preposition) 393 if (type_ == part_type::preposition)
327 { 394 {
328 return preposition_.literal; 395 return preposition_.literal;
329 } else { 396 } else {
@@ -333,7 +400,7 @@ namespace verbly {
333 400
334 std::string part::getLiteralValue() const 401 std::string part::getLiteralValue() const
335 { 402 {
336 if (type_ == type::literal) 403 if (type_ == part_type::literal)
337 { 404 {
338 return literal_; 405 return literal_;
339 } else { 406 } else {
@@ -341,4 +408,9 @@ namespace verbly {
341 } 408 }
342 } 409 }
343 410
411 filter part::synrestr_field::operator%=(std::string synrestr) const
412 {
413 return (synrestrJoin %= (synrestrField == synrestr));
414 }
415
344}; 416};
diff --git a/lib/part.h b/lib/part.h index 3a15638..9a01312 100644 --- a/lib/part.h +++ b/lib/part.h
@@ -4,21 +4,20 @@
4#include <string> 4#include <string>
5#include <vector> 5#include <vector>
6#include <set> 6#include <set>
7#include <list>
7#include "selrestr.h" 8#include "selrestr.h"
9#include "field.h"
10#include "filter.h"
11#include "enums.h"
12
13struct sqlite3_stmt;
8 14
9namespace verbly { 15namespace verbly {
10 16
17 class database;
18
11 class part { 19 class part {
12 public: 20 public:
13 enum class type {
14 invalid = -1,
15 noun_phrase = 0,
16 verb = 1,
17 preposition = 2,
18 adjective = 3,
19 adverb = 4,
20 literal = 5
21 };
22 21
23 // Static factories 22 // Static factories
24 23
@@ -40,6 +39,10 @@ namespace verbly {
40 { 39 {
41 } 40 }
42 41
42 // Construct from database
43
44 part(const database& db, sqlite3_stmt* row);
45
43 // Copy and move constructors 46 // Copy and move constructors
44 47
45 part(const part& other); 48 part(const part& other);
@@ -60,7 +63,12 @@ namespace verbly {
60 63
61 // General accessors 64 // General accessors
62 65
63 type getType() const 66 operator bool() const
67 {
68 return (type_ != part_type::invalid);
69 }
70
71 part_type getType() const
64 { 72 {
65 return type_; 73 return type_;
66 } 74 }
@@ -85,11 +93,43 @@ namespace verbly {
85 93
86 std::string getLiteralValue() const; 94 std::string getLiteralValue() const;
87 95
96 // Type info
97
98 static const object objectType;
99
100 static const std::list<std::string> select;
101
102 // Query fields
103
104 static const field index;
105 static const field type;
106
107 static const field role;
108
109 // Relationships to other objects
110
111 static const field frame;
112
113 // Noun synrestr relationship
114
115 class synrestr_field {
116 public:
117
118 filter operator%=(std::string synrestr) const;
119
120 private:
121
122 static const field synrestrJoin;
123 static const field synrestrField;
124 };
125
126 static const synrestr_field synrestr;
127
88 private: 128 private:
89 129
90 // Private constructors 130 // Private constructors
91 131
92 part(type t) : type_(t) 132 part(part_type t) : type_(t)
93 { 133 {
94 } 134 }
95 135
@@ -108,7 +148,7 @@ namespace verbly {
108 std::string literal_; 148 std::string literal_;
109 }; 149 };
110 150
111 type type_ = type::invalid; 151 part_type type_ = part_type::invalid;
112 152
113 }; 153 };
114 154
diff --git a/lib/query.h b/lib/query.h index 214bf99..75651f6 100644 --- a/lib/query.h +++ b/lib/query.h
@@ -9,6 +9,7 @@
9#include <iostream> 9#include <iostream>
10#include "statement.h" 10#include "statement.h"
11#include "binding.h" 11#include "binding.h"
12#include "order.h"
12 13
13namespace verbly { 14namespace verbly {
14 15
@@ -24,11 +25,17 @@ namespace verbly {
24 class query { 25 class query {
25 public: 26 public:
26 27
27 query(const database& db, sqlite3* ppdb, filter queryFilter, bool random, int limit) : db_(&db) 28 query(const database& db, sqlite3* ppdb, filter queryFilter, order sortOrder, int limit) : db_(&db)
28 { 29 {
30 if ((sortOrder.getType() == order::type::field)
31 && (sortOrder.getSortField().getObject() != Object::objectType))
32 {
33 throw std::invalid_argument("Can only sort query by a field in the result table");
34 }
35
29 statement stmt(Object::objectType, std::move(queryFilter)); 36 statement stmt(Object::objectType, std::move(queryFilter));
30 37
31 std::string queryString = stmt.getQueryString(Object::select, random, limit); 38 std::string queryString = stmt.getQueryString(Object::select, std::move(sortOrder), limit);
32 std::list<binding> bindings = stmt.getBindings(); 39 std::list<binding> bindings = stmt.getBindings();
33 40
34 if (sqlite3_prepare_v2(ppdb, queryString.c_str(), queryString.length(), &ppstmt_, NULL) != SQLITE_OK) 41 if (sqlite3_prepare_v2(ppdb, queryString.c_str(), queryString.length(), &ppstmt_, NULL) != SQLITE_OK)
diff --git a/lib/statement.cpp b/lib/statement.cpp index 846b9de..1512aa5 100644 --- a/lib/statement.cpp +++ b/lib/statement.cpp
@@ -5,11 +5,12 @@
5#include "util.h" 5#include "util.h"
6#include "notion.h" 6#include "notion.h"
7#include "word.h" 7#include "word.h"
8#include "group.h"
9#include "frame.h" 8#include "frame.h"
9#include "part.h"
10#include "lemma.h" 10#include "lemma.h"
11#include "form.h" 11#include "form.h"
12#include "pronunciation.h" 12#include "pronunciation.h"
13#include "order.h"
13 14
14namespace verbly { 15namespace verbly {
15 16
@@ -20,7 +21,7 @@ namespace verbly {
20 { 21 {
21 } 22 }
22 23
23 std::string statement::getQueryString(std::list<std::string> select, bool random, int limit) const 24 std::string statement::getQueryString(std::list<std::string> select, order sortOrder, int limit, bool debug) const
24 { 25 {
25 std::stringstream queryStream; 26 std::stringstream queryStream;
26 27
@@ -49,7 +50,7 @@ namespace verbly {
49 if (cte.getCondition().getType() != condition::type::empty) 50 if (cte.getCondition().getType() != condition::type::empty)
50 { 51 {
51 cteStream << " WHERE "; 52 cteStream << " WHERE ";
52 cteStream << cte.getCondition().toSql(); 53 cteStream << cte.getCondition().flatten().toSql(true, debug);
53 } 54 }
54 55
55 if (cte.isRecursive()) 56 if (cte.isRecursive())
@@ -101,12 +102,28 @@ namespace verbly {
101 if (topCondition_.getType() != condition::type::empty) 102 if (topCondition_.getType() != condition::type::empty)
102 { 103 {
103 queryStream << " WHERE "; 104 queryStream << " WHERE ";
104 queryStream << topCondition_.toSql(); 105 queryStream << topCondition_.flatten().toSql(true, debug);
105 } 106 }
106 107
107 if (random) 108 queryStream << " ORDER BY ";
109
110 switch (sortOrder.getType())
108 { 111 {
109 queryStream << " ORDER BY RANDOM()"; 112 case order::type::random:
113 {
114 queryStream << "RANDOM()";
115
116 break;
117 }
118
119 case order::type::field:
120 {
121 queryStream << topTable_;
122 queryStream << ".";
123 queryStream << sortOrder.getSortField().getColumn();
124
125 break;
126 }
110 } 127 }
111 128
112 if (limit > 0) 129 if (limit > 0)
@@ -260,6 +277,7 @@ namespace verbly {
260 } 277 }
261 278
262 case field::type::join: 279 case field::type::join:
280 case field::type::join_where:
263 { 281 {
264 // First, figure out what table we need to join against. 282 // First, figure out what table we need to join against.
265 std::string joinTableName; 283 std::string joinTableName;
@@ -269,13 +287,22 @@ namespace verbly {
269 } else { 287 } else {
270 joinTableName = getTableForContext(clause.getField().getJoinObject()); 288 joinTableName = getTableForContext(clause.getField().getJoinObject());
271 } 289 }
290
291 filter joinCondition = clause.getJoinCondition();
292
293 // If this is a condition join, we need to add the field join
294 // condition to the clause.
295 if (clause.getField().getType() == field::type::join_where)
296 {
297 joinCondition &= (clause.getField().getConditionField() == clause.getField().getConditionValue());
298 }
272 299
273 // Recursively parse the subquery, and therefore obtain an 300 // Recursively parse the subquery, and therefore obtain an
274 // instantiated table to join against, as well as any joins or CTEs 301 // instantiated table to join against, as well as any joins or CTEs
275 // that the subquery may require to function. 302 // that the subquery may require to function.
276 statement joinStmt( 303 statement joinStmt(
277 joinTableName, 304 joinTableName,
278 clause.getJoinCondition().normalize(clause.getField().getJoinObject()), 305 std::move(joinCondition).normalize(clause.getField().getJoinObject()),
279 nextTableId_, 306 nextTableId_,
280 nextWithId_); 307 nextWithId_);
281 308
@@ -801,7 +828,7 @@ namespace verbly {
801 new(&singleton_.value_) binding(std::move(value)); 828 new(&singleton_.value_) binding(std::move(value));
802 } 829 }
803 830
804 std::string statement::condition::toSql() const 831 std::string statement::condition::toSql(bool toplevel, bool debug) const
805 { 832 {
806 switch (type_) 833 switch (type_)
807 { 834 {
@@ -816,42 +843,92 @@ namespace verbly {
816 { 843 {
817 case comparison::equals: 844 case comparison::equals:
818 { 845 {
819 return singleton_.table_ + "." + singleton_.column_ + " = ?"; 846 if (debug)
847 {
848 if (singleton_.value_.getType() == binding::type::string)
849 {
850 return singleton_.table_ + "." + singleton_.column_ + " = \"" + singleton_.value_.getString() + "\"";
851 } else {
852 return singleton_.table_ + "." + singleton_.column_ + " = " + std::to_string(singleton_.value_.getInteger());
853 }
854 } else {
855 return singleton_.table_ + "." + singleton_.column_ + " = ?";
856 }
820 } 857 }
821 858
822 case comparison::does_not_equal: 859 case comparison::does_not_equal:
823 { 860 {
824 return singleton_.table_ + "." + singleton_.column_ + " != ?"; 861 if (debug)
862 {
863 if (singleton_.value_.getType() == binding::type::string)
864 {
865 return singleton_.table_ + "." + singleton_.column_ + " != \"" + singleton_.value_.getString() + "\"";
866 } else {
867 return singleton_.table_ + "." + singleton_.column_ + " != " + std::to_string(singleton_.value_.getInteger());
868 }
869 } else {
870 return singleton_.table_ + "." + singleton_.column_ + " != ?";
871 }
825 } 872 }
826 873
827 case comparison::is_greater_than: 874 case comparison::is_greater_than:
828 { 875 {
829 return singleton_.table_ + "." + singleton_.column_ + " > ?"; 876 if (debug)
877 {
878 return singleton_.table_ + "." + singleton_.column_ + " > " + std::to_string(singleton_.value_.getInteger());
879 } else {
880 return singleton_.table_ + "." + singleton_.column_ + " > ?";
881 }
830 } 882 }
831 883
832 case comparison::is_at_most: 884 case comparison::is_at_most:
833 { 885 {
834 return singleton_.table_ + "." + singleton_.column_ + " <= ?"; 886 if (debug)
887 {
888 return singleton_.table_ + "." + singleton_.column_ + " <= " + std::to_string(singleton_.value_.getInteger());
889 } else {
890 return singleton_.table_ + "." + singleton_.column_ + " <= ?";
891 }
835 } 892 }
836 893
837 case comparison::is_less_than: 894 case comparison::is_less_than:
838 { 895 {
839 return singleton_.table_ + "." + singleton_.column_ + " < ?"; 896 if (debug)
897 {
898 return singleton_.table_ + "." + singleton_.column_ + " < " + std::to_string(singleton_.value_.getInteger());
899 } else {
900 return singleton_.table_ + "." + singleton_.column_ + " < ?";
901 }
840 } 902 }
841 903
842 case comparison::is_at_least: 904 case comparison::is_at_least:
843 { 905 {
844 return singleton_.table_ + "." + singleton_.column_ + " >= ?"; 906 if (debug)
907 {
908 return singleton_.table_ + "." + singleton_.column_ + " >= " + std::to_string(singleton_.value_.getInteger());
909 } else {
910 return singleton_.table_ + "." + singleton_.column_ + " >= ?";
911 }
845 } 912 }
846 913
847 case comparison::is_like: 914 case comparison::is_like:
848 { 915 {
849 return singleton_.table_ + "." + singleton_.column_ + " LIKE ?"; 916 if (debug)
917 {
918 return singleton_.table_ + "." + singleton_.column_ + " LIKE \"" + singleton_.value_.getString() + "\"";
919 } else {
920 return singleton_.table_ + "." + singleton_.column_ + " LIKE ?";
921 }
850 } 922 }
851 923
852 case comparison::is_not_like: 924 case comparison::is_not_like:
853 { 925 {
854 return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE ?"; 926 if (debug)
927 {
928 return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE \"" + singleton_.value_.getString() + "\"";
929 } else {
930 return singleton_.table_ + "." + singleton_.column_ + " NOT LIKE ?";
931 }
855 } 932 }
856 933
857 case comparison::is_not_null: 934 case comparison::is_not_null:
@@ -871,10 +948,25 @@ namespace verbly {
871 std::list<std::string> clauses; 948 std::list<std::string> clauses;
872 for (const condition& cond : group_.children_) 949 for (const condition& cond : group_.children_)
873 { 950 {
874 clauses.push_back(cond.toSql()); 951 clauses.push_back(cond.toSql(false, debug));
875 } 952 }
876 953
877 return implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND "); 954 if (clauses.empty())
955 {
956 return "";
957 } else if (clauses.size() == 1)
958 {
959 return clauses.front();
960 } else {
961 std::string result = implode(std::begin(clauses), std::end(clauses), group_.orlogic_ ? " OR " : " AND ");
962
963 if (toplevel)
964 {
965 return result;
966 } else {
967 return "(" + result + ")";
968 }
969 }
878 } 970 }
879 } 971 }
880 } 972 }
@@ -988,5 +1080,39 @@ namespace verbly {
988 throw std::domain_error("Cannot get children of non-group condition"); 1080 throw std::domain_error("Cannot get children of non-group condition");
989 } 1081 }
990 } 1082 }
1083
1084 statement::condition statement::condition::flatten() const
1085 {
1086 switch (type_)
1087 {
1088 case type::empty:
1089 case type::singleton:
1090 {
1091 return *this;
1092 }
1093
1094 case type::group:
1095 {
1096 condition result(group_.orlogic_);
1097
1098 for (const condition& child : group_.children_)
1099 {
1100 condition newChild = child.flatten();
1101
1102 if ((newChild.type_ == type::group) && (newChild.group_.orlogic_ == group_.orlogic_))
1103 {
1104 for (condition subChild : std::move(newChild.group_.children_))
1105 {
1106 result += std::move(subChild);
1107 }
1108 } else {
1109 result += std::move(newChild);
1110 }
1111 }
1112
1113 return result;
1114 }
1115 }
1116 }
991 1117
992}; 1118};
diff --git a/lib/statement.h b/lib/statement.h index aa56568..15c4ac3 100644 --- a/lib/statement.h +++ b/lib/statement.h
@@ -13,13 +13,14 @@
13namespace verbly { 13namespace verbly {
14 14
15 class filter; 15 class filter;
16 class order;
16 17
17 class statement { 18 class statement {
18 public: 19 public:
19 20
20 statement(object context, filter queryFilter); 21 statement(object context, filter queryFilter);
21 22
22 std::string getQueryString(std::list<std::string> select, bool random, int limit) const; 23 std::string getQueryString(std::list<std::string> select, order sortOrder, int limit, bool debug = false) const;
23 24
24 std::list<binding> getBindings() const; 25 std::list<binding> getBindings() const;
25 26
@@ -153,10 +154,12 @@ namespace verbly {
153 154
154 // Utility 155 // Utility
155 156
156 std::string toSql() const; 157 std::string toSql(bool toplevel, bool debug = false) const;
157 158
158 std::list<binding> flattenBindings() const; 159 std::list<binding> flattenBindings() const;
159 160
161 condition flatten() const;
162
160 private: 163 private:
161 union { 164 union {
162 struct { 165 struct {
@@ -246,8 +249,8 @@ namespace verbly {
246 { 249 {
247 return (context == object::notion) ? "notions" 250 return (context == object::notion) ? "notions"
248 : (context == object::word) ? "words" 251 : (context == object::word) ? "words"
249 : (context == object::group) ? "groups"
250 : (context == object::frame) ? "frames" 252 : (context == object::frame) ? "frames"
253 : (context == object::part) ? "parts"
251 : (context == object::lemma) ? "lemmas_forms" 254 : (context == object::lemma) ? "lemmas_forms"
252 : (context == object::form) ? "forms" 255 : (context == object::form) ? "forms"
253 : (context == object::pronunciation) ? "pronunciations" 256 : (context == object::pronunciation) ? "pronunciations"
diff --git a/lib/verbly.h b/lib/verbly.h index d8875b3..112907b 100644 --- a/lib/verbly.h +++ b/lib/verbly.h
@@ -6,16 +6,15 @@
6#include "filter.h" 6#include "filter.h"
7#include "field.h" 7#include "field.h"
8#include "query.h" 8#include "query.h"
9#include "order.h"
9#include "notion.h" 10#include "notion.h"
10#include "word.h" 11#include "word.h"
11#include "group.h"
12#include "frame.h" 12#include "frame.h"
13#include "part.h"
13#include "lemma.h" 14#include "lemma.h"
14#include "form.h" 15#include "form.h"
15#include "pronunciation.h" 16#include "pronunciation.h"
16#include "token.h" 17#include "token.h"
17#include "selrestr.h" 18#include "selrestr.h"
18#include "part.h"
19#include "role.h"
20 19
21#endif /* end of include guard: VERBLY_H_5B39CE50 */ 20#endif /* end of include guard: VERBLY_H_5B39CE50 */
diff --git a/lib/word.cpp b/lib/word.cpp index a928659..90eab1d 100644 --- a/lib/word.cpp +++ b/lib/word.cpp
@@ -17,7 +17,7 @@ namespace verbly {
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::frame = field::joinField(object::word, "group_id", object::frame, 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
@@ -93,7 +93,27 @@ namespace verbly {
93 return lemma_; 93 return lemma_;
94 } 94 }
95 95
96 const group& word::getGroup() const 96 bool word::hasFrames() const
97 {
98 if (!valid_)
99 {
100 throw std::domain_error("Bad access to uninitialized word");
101 }
102
103 if (!hasGroup_)
104 {
105 return false;
106 }
107
108 if (!initializedFrames_)
109 {
110 initializeFrames();
111 }
112
113 return !frames_.empty();
114 }
115
116 const std::vector<frame>& word::getFrames() const
97 { 117 {
98 if (!valid_) 118 if (!valid_)
99 { 119 {
@@ -105,12 +125,12 @@ namespace verbly {
105 throw std::domain_error("Word does not have a group"); 125 throw std::domain_error("Word does not have a group");
106 } 126 }
107 127
108 if (!group_) 128 if (!initializedFrames_)
109 { 129 {
110 group_ = db_->groups(group::id == groupId_).first(); 130 initializeFrames();
111 } 131 }
112 132
113 return group_; 133 return frames_;
114 } 134 }
115 135
116 std::string word::getBaseForm() const 136 std::string word::getBaseForm() const
@@ -129,4 +149,10 @@ namespace verbly {
129 return result; 149 return result;
130 } 150 }
131 151
152 void word::initializeFrames() const
153 {
154 initializedFrames_ = true;
155 frames_ = db_->frames(*this, {}, -1).all();
156 }
157
132}; 158};
diff --git a/lib/word.h b/lib/word.h index ddcabe4..8a333a4 100644 --- a/lib/word.h +++ b/lib/word.h
@@ -7,7 +7,7 @@
7#include "filter.h" 7#include "filter.h"
8#include "notion.h" 8#include "notion.h"
9#include "lemma.h" 9#include "lemma.h"
10#include "group.h" 10#include "frame.h"
11 11
12struct sqlite3_stmt; 12struct sqlite3_stmt;
13 13
@@ -97,17 +97,9 @@ namespace verbly {
97 97
98 const lemma& getLemma() const; 98 const lemma& getLemma() const;
99 99
100 bool hasGroup() const 100 bool hasFrames() const;
101 {
102 if (!valid_)
103 {
104 throw std::domain_error("Bad access to uninitialized word");
105 }
106 101
107 return hasGroup_; 102 const std::vector<frame>& getFrames() const;
108 }
109
110 const group& getGroup() const;
111 103
112 // Convenience accessors 104 // Convenience accessors
113 105
@@ -136,7 +128,7 @@ namespace verbly {
136 128
137 static const field notion; 129 static const field notion;
138 static const field lemma; 130 static const field lemma;
139 static const field group; 131 static const field frame;
140 132
141 // Relationships with self 133 // Relationships with self
142 134
@@ -161,6 +153,9 @@ namespace verbly {
161 static const field regionalDomains; 153 static const field regionalDomains;
162 154
163 private: 155 private:
156
157 void initializeFrames() const;
158
164 bool valid_ = false; 159 bool valid_ = false;
165 160
166 int id_; 161 int id_;
@@ -176,7 +171,9 @@ namespace verbly {
176 171
177 mutable class notion notion_; 172 mutable class notion notion_;
178 mutable class lemma lemma_; 173 mutable class lemma lemma_;
179 mutable class group group_; 174
175 mutable bool initializedFrames_ = false;
176 mutable std::vector<class frame> frames_;
180 177
181 }; 178 };
182 179