diff --git a/src/app/models/key-models/keyfactory.cpp b/src/app/models/key-models/keyfactory.cpp index 89684d4a6..15af5515a 100644 --- a/src/app/models/key-models/keyfactory.cpp +++ b/src/app/models/key-models/keyfactory.cpp @@ -7,6 +7,7 @@ #include "sortedsetkey.h" #include "hashkey.h" #include "listkey.h" +#include "rejsonkey.h" #include KeyFactory::KeyFactory() @@ -56,6 +57,9 @@ void KeyFactory::loadKey(QSharedPointer connection, result = createModel(type, connection, keyFullPath, dbIndex, ttl); + if (!result) + return callback(result, QString(QObject::tr("Unsupported Redis Data type %1").arg(type))); + callback(result, QString()); }, dbIndex); @@ -92,6 +96,8 @@ QSharedPointer KeyFactory::createModel(QString type, QShared return QSharedPointer(new SortedSetKeyModel(connection, keyFullPath, dbIndex, ttl)); } else if (type == "hash") { return QSharedPointer(new HashKeyModel(connection, keyFullPath, dbIndex, ttl)); + } else if (type == "ReJSON-RL") { + return QSharedPointer(new ReJSONKeyModel(connection, keyFullPath, dbIndex, ttl)); } return QSharedPointer(); diff --git a/src/app/models/key-models/rejsonkey.cpp b/src/app/models/key-models/rejsonkey.cpp new file mode 100644 index 000000000..d89a91f3b --- /dev/null +++ b/src/app/models/key-models/rejsonkey.cpp @@ -0,0 +1,96 @@ +#include "rejsonkey.h" +#include + +ReJSONKeyModel::ReJSONKeyModel(QSharedPointer connection, + QByteArray fullPath, int dbIndex, long long ttl) + : KeyModel(connection, fullPath, dbIndex, ttl, false, + QByteArray(), QByteArray(), QByteArray()) +{ +} + +QString ReJSONKeyModel::getType() +{ + return "ReJSON"; +} + +QStringList ReJSONKeyModel::getColumnNames() +{ + return QStringList(); // Single value type - No columns +} + +QHash ReJSONKeyModel::getRoles() +{ + QHash roles; + roles[Roles::Value] = "value"; + return roles; +} + +QVariant ReJSONKeyModel::getData(int rowIndex, int dataRole) +{ + if (!isRowLoaded(rowIndex)) + return QVariant(); + + if (dataRole == Roles::Value) + return m_rowsCache[rowIndex]; + + return QVariant(); +} + +void ReJSONKeyModel::updateRow(int rowIndex, const QVariantMap &row) +{ + if (rowIndex > 0 || !isRowValid(row)) { + qDebug() << "Row is not valid"; + return; + } + + QByteArray value = row.value("value").toByteArray(); + + if (value.isEmpty()) + return; + + RedisClient::Response result; + try { + result = m_connection->commandSync({"JSON.SET", m_keyFullPath, ".", value}, m_dbIndex); + } catch (const RedisClient::Connection::Exception& e) { + throw Exception(QObject::tr("Connection error: ") + QString(e.what())); + } + + if (result.isOkMessage()) { + m_rowsCache.clear(); + m_rowsCache.addLoadedRange({0, 0}, (QList() << value)); + m_notifier->dataLoaded(); + } +} + +void ReJSONKeyModel::addRow(const QVariantMap &row) +{ + updateRow(0, row); +} + +void ReJSONKeyModel::loadRows(unsigned long, unsigned long, std::function callback) +{ + try { + m_connection->command({"JSON.GET", m_keyFullPath}, + getConnector().data(), + [this, callback](RedisClient::Response r, QString e) + { + if (r.getType() != RedisClient::Response::Bulk || !e.isEmpty()) { + return callback(QString("Cannot load value")); + } + + m_rowsCache.clear(); + m_rowsCache.push_back(r.getValue().toByteArray()); + m_notifier->dataLoaded(); + + callback(QString()); + }, m_dbIndex); + } catch (const RedisClient::Connection::Exception& e) { + throw Exception(QObject::tr("Connection error: ") + QString(e.what())); + } +} + +void ReJSONKeyModel::removeRow(int) +{ + m_rowCount--; + setRemovedIfEmpty(); +} diff --git a/src/app/models/key-models/rejsonkey.h b/src/app/models/key-models/rejsonkey.h new file mode 100644 index 000000000..2b3a18d9f --- /dev/null +++ b/src/app/models/key-models/rejsonkey.h @@ -0,0 +1,25 @@ +#pragma once +#include "abstractkey.h" + +class ReJSONKeyModel : public KeyModel +{ +public: + ReJSONKeyModel(QSharedPointer connection, + QByteArray fullPath, int dbIndex, long long ttl); + + QString getType() override; + QStringList getColumnNames() override; + QHash getRoles() override; + QVariant getData(int rowIndex, int dataRole) override; + + void addRow(const QVariantMap&) override; + virtual void updateRow(int rowIndex, const QVariantMap& row) override; + void loadRows(unsigned long, unsigned long, std::function callback) override; + void removeRow(int) override; + +protected: + void addLoadedRowsToCache(const QVariantList&, int) override {} + +private: + enum Roles { Value = Qt::UserRole + 1 }; +}; diff --git a/src/qml/value-editor/ValueTabs.qml b/src/qml/value-editor/ValueTabs.qml index 92a4cb13e..4f7ab4f4f 100644 --- a/src/qml/value-editor/ValueTabs.qml +++ b/src/qml/value-editor/ValueTabs.qml @@ -296,7 +296,7 @@ Repeater { elide: styleData.elideMode text: { - if (styleData.value === "" || keyType === "string") { + if (styleData.value === "" || keyType === "string" || keyType === "ReJSON") { return "" } @@ -337,7 +337,7 @@ Repeater { console.log(keyType) - if (keyType === "string") { + if (keyType === "string" || keyType === "ReJSON") { valueEditor.loadRowValue(0) } else { var columns = columnNames diff --git a/src/qml/value-editor/editors/editor.js b/src/qml/value-editor/editors/editor.js index bcbc6df30..f4a0e88a0 100644 --- a/src/qml/value-editor/editors/editor.js +++ b/src/qml/value-editor/editors/editor.js @@ -12,6 +12,8 @@ function getEditorByTypeString(keyType) { return "./editors/SortedSetItemEditor.qml" } else if (keyType === "hash") { return "./editors/HashItemEditor.qml" + } else if (keyType === "ReJSON") { + return "./editors/SingleItemEditor.qml" } else { console.error("Editor for type " + keyType + " is not defined!") } diff --git a/tests/unit_tests/testcases/app/app-tests.pri b/tests/unit_tests/testcases/app/app-tests.pri index 4a8e8899f..6bdbd7997 100644 --- a/tests/unit_tests/testcases/app/app-tests.pri +++ b/tests/unit_tests/testcases/app/app-tests.pri @@ -17,6 +17,7 @@ HEADERS += \ $$APP_SRC_DIR/models/key-models/setkey.h \ $$APP_SRC_DIR/models/key-models/sortedsetkey.h \ $$APP_SRC_DIR/models/key-models/hashkey.h \ + $$APP_SRC_DIR/models/key-models/rejsonkey.h \ SOURCES += \ $$PWD/test_*.cpp \ @@ -30,7 +31,8 @@ SOURCES += \ $$APP_SRC_DIR/models/key-models/listlikekey.cpp \ $$APP_SRC_DIR/models/key-models/setkey.cpp \ $$APP_SRC_DIR/models/key-models/sortedsetkey.cpp \ - $$APP_SRC_DIR/models/key-models/hashkey.cpp \ + $$APP_SRC_DIR/models/key-models/hashkey.cpp \ + $$APP_SRC_DIR/models/key-models/rejsonkey.cpp \ OTHER_FILES += \ connections.xml