Skip to content

Commit

Permalink
Add support for regex in NS separators
Browse files Browse the repository at this point in the history
Fix #3669
  • Loading branch information
uglide committed Sep 6, 2021
1 parent 4e8920a commit 29e4f18
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 43 deletions.
10 changes: 10 additions & 0 deletions src/app/models/connectionconf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ void ServerConfig::setNamespaceSeparator(QString ns)
return setParam<QString>("namespace_separator", ns);
}

bool ServerConfig::namespaceSeparatorIsRegex() const
{
return param<bool>("namespace_separator_is_regex", false);
}

void ServerConfig::setNamespaceSeparatorIsRegex(bool v)
{
return setParam<bool>("namespace_separator_is_regex", v);
}

uint ServerConfig::databaseScanLimit() const
{
return param<uint>("db_scan_limit", DEFAULT_DB_SCAN_LIMIT);
Expand Down
5 changes: 5 additions & 0 deletions src/app/models/connectionconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ServerConfig : public RedisClient::ConnectionConfig
/* Advanced settings */
Q_PROPERTY(QString keysPattern READ keysPattern WRITE setKeysPattern)
Q_PROPERTY(QString namespaceSeparator READ namespaceSeparator WRITE setNamespaceSeparator)
Q_PROPERTY(bool namespaceSeparatorIsRegex READ namespaceSeparatorIsRegex WRITE setNamespaceSeparatorIsRegex)
Q_PROPERTY(uint executeTimeout READ executeTimeout WRITE setExecutionTimeout)
Q_PROPERTY(uint connectionTimeout READ connectionTimeout WRITE setConnectionTimeout)
Q_PROPERTY(bool overrideClusterHost READ overrideClusterHost WRITE setClusterHostOverride)
Expand Down Expand Up @@ -59,6 +60,10 @@ class ServerConfig : public RedisClient::ConnectionConfig
QString namespaceSeparator() const;
void setNamespaceSeparator(QString);

bool namespaceSeparatorIsRegex() const;
void setNamespaceSeparatorIsRegex(bool v);

bool luaKeysLoading() const;
void setLuaKeysLoading(bool);

uint databaseScanLimit() const;
Expand Down
5 changes: 3 additions & 2 deletions src/app/models/treeoperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,9 @@ void TreeOperations::resetConnection() {
QtConcurrent::run([oldConnection]() { oldConnection->disconnect(); });
}

QString TreeOperations::getNamespaceSeparator() {
return m_config.namespaceSeparator();
QRegExp TreeOperations::getNamespaceSeparator() {
return QRegExp(m_config.namespaceSeparator(), Qt::CaseSensitive,
m_config.namespaceSeparatorIsRegex()? QRegExp::RegExp : QRegExp::FixedString);
}

QString TreeOperations::defaultFilter() { return m_config.keysPattern(); }
Expand Down
2 changes: 1 addition & 1 deletion src/app/models/treeoperations.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class TreeOperations : public QObject,

void resetConnection() override;

QString getNamespaceSeparator() override;
QRegExp getNamespaceSeparator() override;

QString defaultFilter() override;

Expand Down
14 changes: 11 additions & 3 deletions src/modules/connections-tree/items/keyitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,17 @@ QString KeyItem::getDisplayName() const {
m_shortRendering) {
auto parent = parentTreeItemToNs(m_parent);

title = printableString(getFullPath().mid(
parent->getFullPath().size() +
parent->operations()->getNamespaceSeparator().size()));
auto nsRx = parent->operations()->getNamespaceSeparator();
int searchFrom = parent->getFullPath().size() > 0 ? parent->getFullPath().size() - 1 : 0;
int nsRxPos = QString::fromUtf8(getFullPath()).indexOf(nsRx, searchFrom);

int nsSize = 0;

if (nsRxPos >= 0) {
nsSize = nsRx.matchedLength();
}

title = printableString(getFullPath().mid(parent->getFullPath().size() + nsSize));
} else {
title = printableString(getFullPath(), true);
}
Expand Down
22 changes: 12 additions & 10 deletions src/modules/connections-tree/items/namespaceitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ using namespace ConnectionsTree;
NamespaceItem::NamespaceItem(const QByteArray &fullPath,
QSharedPointer<Operations> operations,
QWeakPointer<TreeItem> parent, Model &model,
uint dbIndex, QRegExp filter)
uint dbIndex, QRegExp filter, QString lastNsSeparator)
: AbstractNamespaceItem(model, parent, operations, dbIndex, filter),
m_fullPath(fullPath),
m_lastNsSeparator(lastNsSeparator),
m_removed(false) {}

QString NamespaceItem::getDisplayName() const {
Expand All @@ -33,10 +34,11 @@ QString NamespaceItem::getDisplayName() const {
}

QByteArray NamespaceItem::getName() const {
qsizetype pos = m_fullPath.lastIndexOf(m_operations->getNamespaceSeparator());
auto rx = m_operations->getNamespaceSeparator();
qsizetype pos = QString::fromUtf8(m_fullPath).lastIndexOf(rx);

if (pos >= 0) {
return m_fullPath.mid(pos + m_operations->getNamespaceSeparator().size());
return m_fullPath.mid(pos + rx.matchedLength());
} else {
return m_fullPath;
}
Expand Down Expand Up @@ -71,18 +73,18 @@ void NamespaceItem::load() {
return renderRawKeys(rawKeys, m_filter, onKeysRendered, true, false);
}

QString nsFilter = QString("%1%2*")
.arg(QString::fromUtf8(m_fullPath))
.arg(m_operations->getNamespaceSeparator());
QString nsFilter = QString("%1%2*")
.arg(QString::fromUtf8(m_fullPath))
.arg(m_lastNsSeparator);

if (!m_filter.isEmpty()) {
if (m_filter.pattern().startsWith(nsFilter.chopped(1))) {
nsFilter = m_filter.pattern();
} else {
nsFilter = QString("%1%2%3")
.arg(QString::fromUtf8(m_fullPath))
.arg(m_operations->getNamespaceSeparator())
.arg(m_filter.pattern());
.arg(QString::fromUtf8(m_fullPath))
.arg(m_lastNsSeparator)
.arg(m_filter.pattern());
}
}

Expand Down Expand Up @@ -134,7 +136,7 @@ QHash<QString, std::function<void()>> NamespaceItem::eventHandlers() {
},
QString("%1%2")
.arg(QString::fromUtf8(getFullPath()))
.arg(m_operations->getNamespaceSeparator()));
.arg(m_lastNsSeparator));
});

events.insert("reload", [this]() { reload(); });
Expand Down
3 changes: 2 additions & 1 deletion src/modules/connections-tree/items/namespaceitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class NamespaceItem : public AbstractNamespaceItem {
NamespaceItem(const QByteArray& fullPath,
QSharedPointer<Operations> operations,
QWeakPointer<TreeItem> parent, Model& model, uint dbIndex,
QRegExp filter);
QRegExp filter, QString lastNsSeparator);

QString getDisplayName() const override;

Expand All @@ -38,6 +38,7 @@ class NamespaceItem : public AbstractNamespaceItem {

private:
QByteArray m_fullPath;
QString m_lastNsSeparator;
bool m_removed;
};
} // namespace ConnectionsTree
47 changes: 34 additions & 13 deletions src/modules/connections-tree/keysrendering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,20 @@ void KeysTreeRenderer::renderKeys(QSharedPointer<Operations> operations,

int unprocessedPartStart = 0;
if (parent->getFullPath().size() > 0 || parent->type() == "namespace") {
unprocessedPartStart =
parent->getFullPath().size() + settings.nsSeparator.length();
int nsLength = 0;

if (keys.size() > 0) {
QString firstKey = QString::fromUtf8(keys[0]);
int res = firstKey.indexOf(settings.nsSeparator, parent->getFullPath().size());

qDebug() << "NSs regex pos:" << res;

nsLength = settings.nsSeparator.matchedLength();
}

unprocessedPartStart =
parent->getFullPath().size() + nsLength;

}

auto rootItem = resolveRootItem(parent);
Expand Down Expand Up @@ -68,10 +80,12 @@ void KeysTreeRenderer::renderKeys(QSharedPointer<Operations> operations,

auto isBulkInsert = [settings, preRenderedKeysSet, unprocessedPartStart](
const QByteArray &current, const QByteArray &next) {
QString currentKey = QString::fromUtf8(current);
QString nextKey = QString::fromUtf8(current);
return (settings.appendNewItems &&
current.indexOf(settings.nsSeparator, unprocessedPartStart) == -1 &&
currentKey.indexOf(settings.nsSeparator, unprocessedPartStart) == -1 &&
!next.isEmpty() &&
next.indexOf(settings.nsSeparator, unprocessedPartStart) == -1 &&
nextKey.indexOf(settings.nsSeparator, unprocessedPartStart) == -1 &&
!preRenderedKeysSet.contains(next));
};

Expand Down Expand Up @@ -130,7 +144,7 @@ void KeysTreeRenderer::renderKeys(QSharedPointer<Operations> operations,
parent->showLoadingError("Not enough memory to render all keys");
break;
}
}
}

if (preRenderedKeysToBeRemoved.size() > 0) {
QList<QWeakPointer<KeyItem>> obsoleteKeys;
Expand Down Expand Up @@ -161,10 +175,17 @@ void KeysTreeRenderer::renderLazily(QSharedPointer<AbstractNamespaceItem> root,
QWeakPointer<TreeItem> currentParent =
parent.staticCast<TreeItem>().toWeakRef();

int indexOfNaspaceSeparator =
(settings.nsSeparator.isEmpty())
? -1
: notProcessedKeyPart.indexOf(settings.nsSeparator);
int indexOfNaspaceSeparator = -1;
auto nsSeparator = settings.nsSeparator;
int nsSeparatorLength = nsSeparator.pattern().size();

if (!nsSeparator.isEmpty() && nsSeparator.patternSyntax() == QRegExp::RegExp) {
QString keyPart = QString::fromUtf8(notProcessedKeyPart);
indexOfNaspaceSeparator = keyPart.indexOf(nsSeparator);

qDebug() << "NSs regex pos:" << indexOfNaspaceSeparator << nsSeparator.cap();
nsSeparatorLength = nsSeparator.matchedLength();
}

if (indexOfNaspaceSeparator == -1) {
if (parent->getAllChilds().size() >= settings.renderLimit) {
Expand Down Expand Up @@ -199,7 +220,8 @@ void KeysTreeRenderer::renderLazily(QSharedPointer<AbstractNamespaceItem> root,
QByteArray namespaceFullPath = fullKey.mid(0, nsPos);

// Single namespaced key
if (nextKey.isEmpty() || nextKey.indexOf(namespaceFullPath) == -1) {
if (nsSeparator.patternSyntax() != QRegExp::RegExp
&& (nextKey.isEmpty() || nextKey.indexOf(namespaceFullPath) == -1)) {
QSharedPointer<KeyItem> newKey(new KeyItem(fullKey, currentParent,
parent->model(),
settings.shortKeysRendering));
Expand All @@ -209,7 +231,7 @@ void KeysTreeRenderer::renderLazily(QSharedPointer<AbstractNamespaceItem> root,

namespaceItem = QSharedPointer<NamespaceItem>(
new NamespaceItem(namespaceFullPath, m_operations, currentParent,
parent->model(), settings.dbIndex, settings.filter));
parent->model(), settings.dbIndex, settings.filter, nsSeparator.cap()));

if (expandedNamespaces.contains(namespaceFullPath)) {
namespaceItem->setExpanded(true);
Expand All @@ -219,8 +241,7 @@ void KeysTreeRenderer::renderLazily(QSharedPointer<AbstractNamespaceItem> root,
}

renderLazily(root, namespaceItem,
notProcessedKeyPart.mid(indexOfNaspaceSeparator +
settings.nsSeparator.length()),
notProcessedKeyPart.mid(indexOfNaspaceSeparator + nsSeparatorLength),
fullKey, m_operations, settings, expandedNamespaces,
level + 1, nextKey);
}
8 changes: 4 additions & 4 deletions src/modules/connections-tree/keysrendering.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ namespace ConnectionsTree {
public:
struct RenderingSettigns {
QRegExp filter;
QString nsSeparator;
uint dbIndex;
uint renderLimit;
QRegExp nsSeparator;
uint dbIndex;
uint renderLimit;
bool appendNewItems;
bool checkPreRenderedItems;
bool shortKeysRendering;
Expand All @@ -31,7 +31,7 @@ namespace ConnectionsTree {
RedisClient::Connection::RawKeysList keys,
QSharedPointer<AbstractNamespaceItem> parent,
RenderingSettigns settings,
const QSet<QByteArray> &expandedNamespaces);
const QSet<QByteArray> &expandedNamespaces);

private:
static void renderLazily(QSharedPointer<AbstractNamespaceItem> root,
Expand Down
2 changes: 1 addition & 1 deletion src/modules/connections-tree/operations.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class Operations {
* @brief getNamespaceSeparator
* @return
*/
virtual QString getNamespaceSeparator() = 0;
virtual QRegExp getNamespaceSeparator() = 0;

virtual QString defaultFilter() = 0;

Expand Down
26 changes: 18 additions & 8 deletions src/qml/ConnectionSettignsDialog.qml
Original file line number Diff line number Diff line change
Expand Up @@ -761,14 +761,24 @@ Dialog {

BetterLabel { text: qsTranslate("RDM","Namespace Separator:") }

BetterTextField
{
id: namespaceSeparator
Layout.fillWidth: true
objectName: "rdm_advanced_settings_namespace_separator_field"
placeholderText: qsTranslate("RDM","Separator used for namespace extraction from keys")
text: root.settings ? root.settings.namespaceSeparator : ""
onTextChanged: if (root.settings) { root.settings.namespaceSeparator = text }
RowLayout {
BetterTextField
{
id: namespaceSeparator
Layout.fillWidth: true
objectName: "rdm_advanced_settings_namespace_separator_field"
placeholderText: qsTranslate("RDM","Separator used for namespace extraction from keys")
text: root.settings ? root.settings.namespaceSeparator : ""
onTextChanged: if (root.settings) { root.settings.namespaceSeparator = text }
}

BetterCheckbox {
id: nsRegex
Layout.fillWidth: true
checked: root.settings ? root.settings.namespaceSeparatorIsRegex : false
onCheckedChanged: if (root.settings) { root.settings.namespaceSeparatorIsRegex = checked }
text: qsTranslate("RDM","Regex")
}
}

SettingsGroupTitle {
Expand Down

0 comments on commit 29e4f18

Please sign in to comment.