summaryrefslogtreecommitdiffstats
path: root/common/typeindex.cpp
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-02-16 17:43:22 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-02-16 17:43:22 +0100
commit529dd17eec62a9702b8837f8f1976dfbf28fdd82 (patch)
tree3fe5581a76b83cd9c4360b67e7dd99ceb8c0eaab /common/typeindex.cpp
parent8acaae496f9e816c4c1b1126fc6409b6fafe6500 (diff)
downloadsink-529dd17eec62a9702b8837f8f1976dfbf28fdd82.tar.gz
sink-529dd17eec62a9702b8837f8f1976dfbf28fdd82.zip
Prepared sort indexes
Diffstat (limited to 'common/typeindex.cpp')
-rw-r--r--common/typeindex.cpp95
1 files changed, 74 insertions, 21 deletions
diff --git a/common/typeindex.cpp b/common/typeindex.cpp
index 37c0517..e945dcb 100644
--- a/common/typeindex.cpp
+++ b/common/typeindex.cpp
@@ -25,22 +25,41 @@
25#undef DEBUG_AREA 25#undef DEBUG_AREA
26#define DEBUG_AREA "common.typeindex" 26#define DEBUG_AREA "common.typeindex"
27 27
28static QByteArray getByteArray(const QVariant &value)
29{
30 if (value.isValid() && !value.toByteArray().isEmpty()) {
31 return value.toByteArray();
32 }
33 //LMDB can't handle empty keys, so use something different
34 return "toplevel";
35}
36
37static QByteArray toSortableByteArray(const QDateTime &date)
38{
39 return QByteArray::number(std::numeric_limits<unsigned int>::max() - date.toTime_t());
40}
41
42
28TypeIndex::TypeIndex(const QByteArray &type) 43TypeIndex::TypeIndex(const QByteArray &type)
29 : mType(type) 44 : mType(type)
30{ 45{
31 46
32} 47}
33 48
49QByteArray TypeIndex::indexName(const QByteArray &property, const QByteArray &sortProperty) const
50{
51 if (sortProperty.isEmpty()) {
52 return mType + ".index." + property;
53 }
54 return mType + ".index." + property + ".sort." + sortProperty;
55}
56
34template<> 57template<>
35void TypeIndex::addProperty<QByteArray>(const QByteArray &property) 58void TypeIndex::addProperty<QByteArray>(const QByteArray &property)
36{ 59{
37 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction) { 60 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction) {
38 // Trace() << "Indexing " << mType + ".index." + property << value.toByteArray(); 61 // Trace() << "Indexing " << mType + ".index." + property << value.toByteArray();
39 if (value.isValid() && !value.toByteArray().isEmpty()) { 62 Index(indexName(property), transaction).add(getByteArray(value), identifier);
40 Index(mType + ".index." + property, transaction).add(value.toByteArray(), identifier);
41 } else {
42 Index(mType + ".index." + property, transaction).add("toplevel", identifier);
43 }
44 }; 63 };
45 mIndexer.insert(property, indexer); 64 mIndexer.insert(property, indexer);
46 mProperties << property; 65 mProperties << property;
@@ -51,11 +70,7 @@ void TypeIndex::addProperty<QString>(const QByteArray &property)
51{ 70{
52 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction) { 71 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction) {
53 // Trace() << "Indexing " << mType + ".index." + property << value.toByteArray(); 72 // Trace() << "Indexing " << mType + ".index." + property << value.toByteArray();
54 if (value.isValid() && !value.toByteArray().isEmpty()) { 73 Index(indexName(property), transaction).add(getByteArray(value), identifier);
55 Index(mType + ".index." + property, transaction).add(value.toByteArray(), identifier);
56 } else {
57 Index(mType + ".index." + property, transaction).add("toplevel", identifier);
58 }
59 }; 74 };
60 mIndexer.insert(property, indexer); 75 mIndexer.insert(property, indexer);
61 mProperties << property; 76 mProperties << property;
@@ -68,13 +83,25 @@ void TypeIndex::addProperty<QDateTime>(const QByteArray &property)
68 const auto date = value.toDateTime(); 83 const auto date = value.toDateTime();
69 // Trace() << "Indexing " << mType + ".index." + property << date.toString(); 84 // Trace() << "Indexing " << mType + ".index." + property << date.toString();
70 if (date.isValid()) { 85 if (date.isValid()) {
71 Index(mType + ".index." + property, transaction).add(date.toString().toLatin1(), identifier); 86 Index(indexName(property), transaction).add(date.toString().toLatin1(), identifier);
72 } 87 }
73 }; 88 };
74 mIndexer.insert(property, indexer); 89 mIndexer.insert(property, indexer);
75 mProperties << property; 90 mProperties << property;
76} 91}
77 92
93template<>
94void TypeIndex::addPropertyWithSorting<QByteArray, QDateTime>(const QByteArray &property, const QByteArray &sortProperty)
95{
96 auto indexer = [=](const QByteArray &identifier, const QVariant &value, const QVariant &sortValue, Sink::Storage::Transaction &transaction) {
97 const auto date = sortValue.toDateTime();
98 const auto propertyValue = getByteArray(value);
99 Index(indexName(property, sortProperty), transaction).add(propertyValue + toSortableByteArray(date), identifier);
100 };
101 mSortIndexer.insert(property+sortProperty, indexer);
102 mSortedProperties.insert(property, sortProperty);
103}
104
78void TypeIndex::add(const QByteArray &identifier, const Sink::ApplicationDomain::BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction) 105void TypeIndex::add(const QByteArray &identifier, const Sink::ApplicationDomain::BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction)
79{ 106{
80 for (const auto &property : mProperties) { 107 for (const auto &property : mProperties) {
@@ -82,31 +109,57 @@ void TypeIndex::add(const QByteArray &identifier, const Sink::ApplicationDomain:
82 auto indexer = mIndexer.value(property); 109 auto indexer = mIndexer.value(property);
83 indexer(identifier, value, transaction); 110 indexer(identifier, value, transaction);
84 } 111 }
112 for (auto it = mSortedProperties.constBegin(); it != mSortedProperties.constEnd(); it++) {
113 const auto value = bufferAdaptor.getProperty(it.key());
114 const auto sortValue = bufferAdaptor.getProperty(it.value());
115 auto indexer = mSortIndexer.value(it.key()+it.value());
116 indexer(identifier, value, sortValue, transaction);
117 }
85} 118}
86 119
87void TypeIndex::remove(const QByteArray &identifier, const Sink::ApplicationDomain::BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction) 120void TypeIndex::remove(const QByteArray &identifier, const Sink::ApplicationDomain::BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction)
88{ 121{
89 for (const auto &property : mProperties) { 122 for (const auto &property : mProperties) {
90 const auto value = bufferAdaptor.getProperty(property); 123 const auto value = bufferAdaptor.getProperty(property);
91 if (value.isValid()) { 124 //FIXME don't always convert to byte array
92 //FIXME don't always convert to byte array 125 Index(indexName(property), transaction).remove(getByteArray(value), identifier);
93 Index(mType + ".index." + property, transaction).remove(value.toByteArray(), identifier); 126 }
127 for (auto it = mSortedProperties.constBegin(); it != mSortedProperties.constEnd(); it++) {
128 const auto propertyValue = bufferAdaptor.getProperty(it.key());
129 const auto sortValue = bufferAdaptor.getProperty(it.value());
130 if (sortValue.type() == QVariant::DateTime) {
131 Index(indexName(it.key(), it.value()), transaction).remove(propertyValue.toByteArray() + toSortableByteArray(sortValue.toDateTime()), identifier);
94 } else { 132 } else {
95 Index(mType + ".index." + property, transaction).remove("toplevel", identifier); 133 Index(indexName(it.key(), it.value()), transaction).remove(propertyValue.toByteArray() + sortValue.toByteArray(), identifier);
96 } 134 }
97 } 135 }
98} 136}
99 137
100ResultSet TypeIndex::query(const Sink::Query &query, QSet<QByteArray> &appliedFilters, Sink::Storage::Transaction &transaction) 138ResultSet TypeIndex::query(const Sink::Query &query, QSet<QByteArray> &appliedFilters, QByteArray &appliedSorting, Sink::Storage::Transaction &transaction)
101{ 139{
102 QVector<QByteArray> keys; 140 QVector<QByteArray> keys;
141 for (auto it = mSortedProperties.constBegin(); it != mSortedProperties.constEnd(); it++) {
142 if (query.propertyFilter.contains(it.key()) && query.sortProperty == it.value()) {
143 Index index(indexName(it.key(), it.value()), transaction);
144 const auto lookupKey = getByteArray(query.propertyFilter.value(it.key()));
145 Trace() << "looking for " << lookupKey;
146 index.lookup(lookupKey, [&](const QByteArray &value) {
147 keys << value;
148 },
149 [it](const Index::Error &error) {
150 Warning() << "Error in index: " << error.message << it.key() << it.value();
151 }, true);
152 appliedFilters << it.key();
153 appliedSorting = it.value();
154 Trace() << "Index lookup on " << it.key() << it.value() << " found " << keys.size() << " keys.";
155 return ResultSet(keys);
156
157 }
158 }
103 for (const auto &property : mProperties) { 159 for (const auto &property : mProperties) {
104 if (query.propertyFilter.contains(property)) { 160 if (query.propertyFilter.contains(property)) {
105 Index index(mType + ".index." + property, transaction); 161 Index index(indexName(property), transaction);
106 auto lookupKey = query.propertyFilter.value(property).toByteArray(); 162 const auto lookupKey = getByteArray(query.propertyFilter.value(property));
107 if (lookupKey.isEmpty()) {
108 lookupKey = "toplevel";
109 }
110 index.lookup(lookupKey, [&](const QByteArray &value) { 163 index.lookup(lookupKey, [&](const QByteArray &value) {
111 keys << value; 164 keys << value;
112 }, 165 },