diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-02-16 17:43:22 +0100 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-02-16 17:43:22 +0100 |
commit | 529dd17eec62a9702b8837f8f1976dfbf28fdd82 (patch) | |
tree | 3fe5581a76b83cd9c4360b67e7dd99ceb8c0eaab /common/typeindex.cpp | |
parent | 8acaae496f9e816c4c1b1126fc6409b6fafe6500 (diff) | |
download | sink-529dd17eec62a9702b8837f8f1976dfbf28fdd82.tar.gz sink-529dd17eec62a9702b8837f8f1976dfbf28fdd82.zip |
Prepared sort indexes
Diffstat (limited to 'common/typeindex.cpp')
-rw-r--r-- | common/typeindex.cpp | 95 |
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 | ||
28 | static 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 | |||
37 | static QByteArray toSortableByteArray(const QDateTime &date) | ||
38 | { | ||
39 | return QByteArray::number(std::numeric_limits<unsigned int>::max() - date.toTime_t()); | ||
40 | } | ||
41 | |||
42 | |||
28 | TypeIndex::TypeIndex(const QByteArray &type) | 43 | TypeIndex::TypeIndex(const QByteArray &type) |
29 | : mType(type) | 44 | : mType(type) |
30 | { | 45 | { |
31 | 46 | ||
32 | } | 47 | } |
33 | 48 | ||
49 | QByteArray 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 | |||
34 | template<> | 57 | template<> |
35 | void TypeIndex::addProperty<QByteArray>(const QByteArray &property) | 58 | void 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 | ||
93 | template<> | ||
94 | void 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 | |||
78 | void TypeIndex::add(const QByteArray &identifier, const Sink::ApplicationDomain::BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction) | 105 | void 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 | ||
87 | void TypeIndex::remove(const QByteArray &identifier, const Sink::ApplicationDomain::BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction) | 120 | void 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 | ||
100 | ResultSet TypeIndex::query(const Sink::Query &query, QSet<QByteArray> &appliedFilters, Sink::Storage::Transaction &transaction) | 138 | ResultSet 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 | }, |