File indexing completed on 2024-12-15 04:56:11
0001 /* 0002 * Copyright (C) 2014 Aaron Seigo <aseigo@kde.org> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2.1 of the License, or (at your option) version 3, or any 0008 * later version accepted by the membership of KDE e.V. (or its 0009 * successor approved by the membership of KDE e.V.), which shall 0010 * act as a proxy defined in Section 6 of version 3 of the license. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Lesser General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Lesser General Public 0018 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 0019 */ 0020 0021 #include "dataset.h" 0022 0023 #include <QDateTime> 0024 #include <QDebug> 0025 #include <QDataStream> 0026 0027 #include <iostream> 0028 0029 namespace HAWD 0030 { 0031 0032 static const QString s_annotationKey("__annotation__"); 0033 static const QString s_hashKey("__commithash__"); 0034 static const QString s_timestampKey("__timestamp"); 0035 static const int s_fieldWidth(20); 0036 0037 Dataset::Row::Row(const Row &other) 0038 : m_key(other.m_key), 0039 m_columns(other.m_columns), 0040 m_data(other.m_data), 0041 m_annotation(other.m_annotation), 0042 m_commitHash(other.m_commitHash), 0043 m_dataset(other.m_dataset) 0044 { 0045 } 0046 0047 Dataset::Row::Row(const Dataset &dataset, qint64 key) 0048 : m_key(key), 0049 m_columns(dataset.definition().columns()), 0050 m_dataset(&dataset) 0051 { 0052 // TODO: pre-populate m_data, or do that on buffer creation? 0053 for (const auto &colum : dataset.definition().columns()) { 0054 m_data.insert(colum.first, QVariant()); 0055 } 0056 } 0057 0058 Dataset::Row &Dataset::Row::operator=(const Row &rhs) 0059 { 0060 m_key = rhs.m_key; 0061 m_columns = rhs.m_columns; 0062 m_data = rhs.m_data; 0063 m_dataset = rhs.m_dataset; 0064 m_annotation = rhs.m_annotation; 0065 m_commitHash = rhs.m_commitHash; 0066 return *this; 0067 } 0068 0069 void Dataset::Row::setValue(const QString &col, const QVariant &value) 0070 { 0071 for (const auto &column : m_columns) { 0072 if (column.first == col) { 0073 if (value.canConvert(column.second.type())) { 0074 m_data[col] = value; 0075 } 0076 return; 0077 } 0078 } 0079 } 0080 0081 QVariant Dataset::Row::value(const QString &col) const 0082 { 0083 return m_data.value(col); 0084 } 0085 0086 void Dataset::Row::annotate(const QString ¬e) 0087 { 0088 m_annotation = note; 0089 } 0090 0091 void Dataset::Row::setCommitHash(const QString &hash) 0092 { 0093 m_commitHash = hash; 0094 } 0095 0096 qint64 Dataset::Row::key() const 0097 { 0098 if (m_key < 1) { 0099 const_cast<Dataset::Row *>(this)->m_key = QDateTime::currentMSecsSinceEpoch(); 0100 } 0101 0102 return m_key; 0103 } 0104 0105 void Dataset::Row::fromBinary(QByteArray data) 0106 { 0107 QVariant value; 0108 QString key; 0109 QDataStream stream(&data, QIODevice::ReadOnly); 0110 0111 while (!stream.atEnd()) { 0112 stream >> key; 0113 if (stream.atEnd()) { 0114 break; 0115 } 0116 0117 stream >> value; 0118 if (key == s_annotationKey) { 0119 m_annotation = value.toString(); 0120 } else if (key == s_hashKey) { 0121 m_commitHash = value.toString(); 0122 } else if (key == s_timestampKey) { 0123 m_timeStamp = value.toDateTime(); 0124 } else { 0125 setValue(key, value); 0126 } 0127 } 0128 } 0129 0130 QByteArray Dataset::Row::toBinary() const 0131 { 0132 QByteArray data; 0133 QDataStream stream(&data, QIODevice::WriteOnly); 0134 0135 QHashIterator<QString, QVariant> it(m_data); 0136 while (it.hasNext()) { 0137 it.next(); 0138 if (it.value().isValid()) { 0139 stream << it.key() << it.value(); 0140 } 0141 } 0142 0143 if (!m_commitHash.isEmpty()) { 0144 stream << s_hashKey << QVariant(m_commitHash); 0145 } 0146 0147 if (!m_timeStamp.isValid()) { 0148 stream << s_timestampKey << QVariant(m_timeStamp); 0149 } 0150 0151 if (!m_annotation.isEmpty()) { 0152 stream << s_annotationKey << QVariant(m_annotation); 0153 } 0154 0155 return data; 0156 } 0157 0158 QString Dataset::tableHeaders(const QStringList &cols, int standardCols, const QString &seperator) const 0159 { 0160 if (!isValid()) { 0161 return QString(); 0162 } 0163 0164 QStringList strings; 0165 0166 if (standardCols & Row::Timestamp) { 0167 strings << QObject::tr("Timestamp").leftJustified(s_fieldWidth, ' '); 0168 } 0169 0170 if (standardCols & Row::CommitHash) { 0171 strings << QObject::tr("Commit").leftJustified(s_fieldWidth, ' '); 0172 } 0173 0174 for (const auto &column : m_definition.columns()) { 0175 QString header = column.first; 0176 if (cols.isEmpty() || cols.contains(header)) { 0177 if (!column.second.unit().isEmpty()) { 0178 header.append(" (").append(column.second.unit()).append(")"); 0179 } 0180 strings << header.leftJustified(s_fieldWidth, ' '); 0181 } 0182 } 0183 0184 if (standardCols & Row::Annotation) { 0185 strings << QObject::tr("Annotation").leftJustified(s_fieldWidth, ' '); 0186 } 0187 0188 return strings.join(seperator); 0189 } 0190 0191 0192 QString Dataset::Row::commitHash() const 0193 { 0194 return m_commitHash; 0195 } 0196 0197 QDateTime Dataset::Row::timestamp() const 0198 { 0199 if (m_timeStamp.isValid()) { 0200 return m_timeStamp; 0201 } 0202 QDateTime dt; 0203 dt.setMSecsSinceEpoch(m_key); 0204 return dt; 0205 } 0206 0207 void Dataset::Row::setTimestamp(const QDateTime &dt) 0208 { 0209 m_timeStamp = dt; 0210 } 0211 0212 QString Dataset::Row::toString(const QStringList &cols, int standardCols, const QString &seperator) const 0213 { 0214 if (m_data.isEmpty()) { 0215 return QString(); 0216 } 0217 0218 QStringList strings; 0219 0220 if (standardCols & Timestamp) { 0221 strings << timestamp().toString("yyMMdd:hhmmss").leftJustified(s_fieldWidth, ' '); 0222 } 0223 0224 if (standardCols & CommitHash) { 0225 strings << m_commitHash.leftJustified(s_fieldWidth, ' '); 0226 } 0227 0228 for (const auto &column : m_columns) { 0229 const auto key = column.first; 0230 if (cols.isEmpty() || cols.contains(key)) { 0231 const auto value = m_data.value(key); 0232 if (value.canConvert<double>()) { 0233 strings << QString("%1").arg(value.toDouble(), s_fieldWidth, 'f', 3); 0234 } else { 0235 strings << value.toString().leftJustified(s_fieldWidth, ' '); 0236 } 0237 } 0238 } 0239 0240 if (standardCols & Annotation) { 0241 strings << m_annotation.leftJustified(s_fieldWidth, ' '); 0242 } 0243 0244 return strings.join(seperator); 0245 } 0246 0247 Dataset::Dataset(const QString &name, const State &state) 0248 : m_definition(state.datasetDefinition(name)), 0249 m_storage(state.resultsPath(), name, Sink::Storage::DataStore::ReadWrite), 0250 m_transaction(m_storage.createTransaction()), 0251 m_commitHash(state.commitHash()) 0252 { 0253 } 0254 0255 Dataset::~Dataset() 0256 { 0257 m_transaction.commit(); 0258 } 0259 0260 bool Dataset::isValid() const 0261 { 0262 return m_definition.isValid(); 0263 } 0264 0265 const DatasetDefinition &Dataset::definition() const 0266 { 0267 return m_definition; 0268 } 0269 0270 qint64 Dataset::insertRow(const Row &row) 0271 { 0272 if (row.m_dataset != this) { 0273 return 0; 0274 } 0275 0276 qint64 key = row.key(); 0277 m_transaction.openDatabase().write(QByteArray::fromRawData((const char *)&key, sizeof(qint64)), row.toBinary()); 0278 return key; 0279 } 0280 0281 void Dataset::removeRow(const Row &row) 0282 { 0283 //TODO 0284 } 0285 0286 void Dataset::eachRow(const std::function<void(const Row &row)> &resultHandler) 0287 { 0288 if (!isValid()) { 0289 return; 0290 } 0291 0292 Row row(*this); 0293 m_transaction.openDatabase().scan("", 0294 [&](const QByteArray &key, const QByteArray &value) -> bool { 0295 if (key.size() != sizeof(qint64)) { 0296 return true; 0297 } 0298 0299 row.fromBinary(value); 0300 row.m_key = *(const qint64 *)key.data(); 0301 resultHandler(row); 0302 return true; 0303 }, 0304 Sink::Storage::DataStore::basicErrorHandler()); 0305 } 0306 0307 Dataset::Row Dataset::row(qint64 key) 0308 { 0309 if (key < 1) { 0310 Row row(*this, Sink::Storage::DataStore::maxRevision(m_transaction)); 0311 row.setCommitHash(m_commitHash); 0312 return row; 0313 } 0314 0315 Row row(*this, key); 0316 m_transaction.openDatabase().scan(QByteArray::fromRawData((const char *)&key, sizeof(qint64)), 0317 [&row](const QByteArray &key, const QByteArray &value) -> bool { 0318 row.fromBinary(value); 0319 return true; 0320 }, 0321 Sink::Storage::DataStore::basicErrorHandler() 0322 ); 0323 return row; 0324 } 0325 0326 Dataset::Row Dataset::lastRow() 0327 { 0328 //TODO 0329 return Row(*this); 0330 } 0331 0332 } // namespace HAWD 0333