Skip to content

Commit e92d283

Browse files
committed
Add support for regex in NS separators
Fix #3669
1 parent 4e8920a commit e92d283

11 files changed

+97
-41
lines changed

src/app/models/connectionconf.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ void ServerConfig::setNamespaceSeparator(QString ns)
3939
return setParam<QString>("namespace_separator", ns);
4040
}
4141

42+
bool ServerConfig::namespaceSeparatorIsRegex() const
43+
{
44+
return param<bool>("namespace_separator_is_regex", false);
45+
}
46+
47+
void ServerConfig::setNamespaceSeparatorIsRegex(bool v)
48+
{
49+
return setParam<bool>("namespace_separator_is_regex", v);
50+
}
51+
4252
uint ServerConfig::databaseScanLimit() const
4353
{
4454
return param<uint>("db_scan_limit", DEFAULT_DB_SCAN_LIMIT);

src/app/models/connectionconf.h

+5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class ServerConfig : public RedisClient::ConnectionConfig
3232
/* Advanced settings */
3333
Q_PROPERTY(QString keysPattern READ keysPattern WRITE setKeysPattern)
3434
Q_PROPERTY(QString namespaceSeparator READ namespaceSeparator WRITE setNamespaceSeparator)
35+
Q_PROPERTY(bool namespaceSeparatorIsRegex READ namespaceSeparatorIsRegex WRITE setNamespaceSeparatorIsRegex)
3536
Q_PROPERTY(uint executeTimeout READ executeTimeout WRITE setExecutionTimeout)
3637
Q_PROPERTY(uint connectionTimeout READ connectionTimeout WRITE setConnectionTimeout)
3738
Q_PROPERTY(bool overrideClusterHost READ overrideClusterHost WRITE setClusterHostOverride)
@@ -59,6 +60,10 @@ class ServerConfig : public RedisClient::ConnectionConfig
5960
QString namespaceSeparator() const;
6061
void setNamespaceSeparator(QString);
6162

63+
bool namespaceSeparatorIsRegex() const;
64+
void setNamespaceSeparatorIsRegex(bool v);
65+
66+
bool luaKeysLoading() const;
6267
void setLuaKeysLoading(bool);
6368

6469
uint databaseScanLimit() const;

src/app/models/treeoperations.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,9 @@ void TreeOperations::resetConnection() {
236236
QtConcurrent::run([oldConnection]() { oldConnection->disconnect(); });
237237
}
238238

239-
QString TreeOperations::getNamespaceSeparator() {
240-
return m_config.namespaceSeparator();
239+
QRegExp TreeOperations::getNamespaceSeparator() {
240+
return QRegExp(m_config.namespaceSeparator(), Qt::CaseSensitive,
241+
m_config.namespaceSeparatorIsRegex()? QRegExp::RegExp : QRegExp::FixedString);
241242
}
242243

243244
QString TreeOperations::defaultFilter() { return m_config.keysPattern(); }

src/app/models/treeoperations.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class TreeOperations : public QObject,
3636

3737
void resetConnection() override;
3838

39-
QString getNamespaceSeparator() override;
39+
QRegExp getNamespaceSeparator() override;
4040

4141
QString defaultFilter() override;
4242

src/modules/connections-tree/items/keyitem.cpp

+11-3
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,17 @@ QString KeyItem::getDisplayName() const {
3939
m_shortRendering) {
4040
auto parent = parentTreeItemToNs(m_parent);
4141

42-
title = printableString(getFullPath().mid(
43-
parent->getFullPath().size() +
44-
parent->operations()->getNamespaceSeparator().size()));
42+
auto nsRx = parent->operations()->getNamespaceSeparator();
43+
int searchFrom = parent->getFullPath().size() > 0 ? parent->getFullPath().size() - 1 : 0;
44+
int nsRxPos = QString::fromUtf8(getFullPath()).indexOf(nsRx, searchFrom);
45+
46+
int nsSize = 0;
47+
48+
if (nsRxPos >= 0) {
49+
nsSize = nsRx.matchedLength();
50+
}
51+
52+
title = printableString(getFullPath().mid(parent->getFullPath().size() + nsSize));
4553
} else {
4654
title = printableString(getFullPath(), true);
4755
}

src/modules/connections-tree/items/namespaceitem.cpp

+12-10
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ using namespace ConnectionsTree;
1515
NamespaceItem::NamespaceItem(const QByteArray &fullPath,
1616
QSharedPointer<Operations> operations,
1717
QWeakPointer<TreeItem> parent, Model &model,
18-
uint dbIndex, QRegExp filter)
18+
uint dbIndex, QRegExp filter, QString lastNsSeparator)
1919
: AbstractNamespaceItem(model, parent, operations, dbIndex, filter),
2020
m_fullPath(fullPath),
21+
m_lastNsSeparator(lastNsSeparator),
2122
m_removed(false) {}
2223

2324
QString NamespaceItem::getDisplayName() const {
@@ -33,10 +34,11 @@ QString NamespaceItem::getDisplayName() const {
3334
}
3435

3536
QByteArray NamespaceItem::getName() const {
36-
qsizetype pos = m_fullPath.lastIndexOf(m_operations->getNamespaceSeparator());
37+
auto rx = m_operations->getNamespaceSeparator();
38+
qsizetype pos = QString::fromUtf8(m_fullPath).lastIndexOf(rx);
3739

3840
if (pos >= 0) {
39-
return m_fullPath.mid(pos + m_operations->getNamespaceSeparator().size());
41+
return m_fullPath.mid(pos + rx.matchedLength());
4042
} else {
4143
return m_fullPath;
4244
}
@@ -71,18 +73,18 @@ void NamespaceItem::load() {
7173
return renderRawKeys(rawKeys, m_filter, onKeysRendered, true, false);
7274
}
7375

74-
QString nsFilter = QString("%1%2*")
75-
.arg(QString::fromUtf8(m_fullPath))
76-
.arg(m_operations->getNamespaceSeparator());
76+
QString nsFilter = QString("%1%2*")
77+
.arg(QString::fromUtf8(m_fullPath))
78+
.arg(m_lastNsSeparator);
7779

7880
if (!m_filter.isEmpty()) {
7981
if (m_filter.pattern().startsWith(nsFilter.chopped(1))) {
8082
nsFilter = m_filter.pattern();
8183
} else {
8284
nsFilter = QString("%1%2%3")
83-
.arg(QString::fromUtf8(m_fullPath))
84-
.arg(m_operations->getNamespaceSeparator())
85-
.arg(m_filter.pattern());
85+
.arg(QString::fromUtf8(m_fullPath))
86+
.arg(m_lastNsSeparator)
87+
.arg(m_filter.pattern());
8688
}
8789
}
8890

@@ -134,7 +136,7 @@ QHash<QString, std::function<void()>> NamespaceItem::eventHandlers() {
134136
},
135137
QString("%1%2")
136138
.arg(QString::fromUtf8(getFullPath()))
137-
.arg(m_operations->getNamespaceSeparator()));
139+
.arg(m_lastNsSeparator));
138140
});
139141

140142
events.insert("reload", [this]() { reload(); });

src/modules/connections-tree/items/namespaceitem.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class NamespaceItem : public AbstractNamespaceItem {
1515
NamespaceItem(const QByteArray& fullPath,
1616
QSharedPointer<Operations> operations,
1717
QWeakPointer<TreeItem> parent, Model& model, uint dbIndex,
18-
QRegExp filter);
18+
QRegExp filter, QString lastNsSeparator);
1919

2020
QString getDisplayName() const override;
2121

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

3939
private:
4040
QByteArray m_fullPath;
41+
QString m_lastNsSeparator;
4142
bool m_removed;
4243
};
4344
} // namespace ConnectionsTree

src/modules/connections-tree/keysrendering.cpp

+30-11
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,20 @@ void KeysTreeRenderer::renderKeys(QSharedPointer<Operations> operations,
3535

3636
int unprocessedPartStart = 0;
3737
if (parent->getFullPath().size() > 0 || parent->type() == "namespace") {
38-
unprocessedPartStart =
39-
parent->getFullPath().size() + settings.nsSeparator.length();
38+
int nsLength = 0;
39+
40+
if (keys.size() > 0) {
41+
QString firstKey = QString::fromUtf8(keys[0]);
42+
int res = firstKey.indexOf(settings.nsSeparator, parent->getFullPath().size());
43+
44+
qDebug() << "NSs regex pos:" << res;
45+
46+
nsLength = settings.nsSeparator.matchedLength();
47+
}
48+
49+
unprocessedPartStart =
50+
parent->getFullPath().size() + nsLength;
51+
4052
}
4153

4254
auto rootItem = resolveRootItem(parent);
@@ -130,7 +142,7 @@ void KeysTreeRenderer::renderKeys(QSharedPointer<Operations> operations,
130142
parent->showLoadingError("Not enough memory to render all keys");
131143
break;
132144
}
133-
}
145+
}
134146

135147
if (preRenderedKeysToBeRemoved.size() > 0) {
136148
QList<QWeakPointer<KeyItem>> obsoleteKeys;
@@ -161,10 +173,17 @@ void KeysTreeRenderer::renderLazily(QSharedPointer<AbstractNamespaceItem> root,
161173
QWeakPointer<TreeItem> currentParent =
162174
parent.staticCast<TreeItem>().toWeakRef();
163175

164-
int indexOfNaspaceSeparator =
165-
(settings.nsSeparator.isEmpty())
166-
? -1
167-
: notProcessedKeyPart.indexOf(settings.nsSeparator);
176+
int indexOfNaspaceSeparator = -1;
177+
auto nsSeparator = settings.nsSeparator;
178+
int nsSeparatorLength = nsSeparator.pattern().size();
179+
180+
if (!nsSeparator.isEmpty() && nsSeparator.patternSyntax() == QRegExp::RegExp) {
181+
QString keyPart = QString::fromUtf8(notProcessedKeyPart);
182+
indexOfNaspaceSeparator = keyPart.indexOf(nsSeparator);
183+
184+
qDebug() << "NSs regex pos:" << indexOfNaspaceSeparator << nsSeparator.cap();
185+
nsSeparatorLength = nsSeparator.matchedLength();
186+
}
168187

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

201220
// Single namespaced key
202-
if (nextKey.isEmpty() || nextKey.indexOf(namespaceFullPath) == -1) {
221+
if (nsSeparator.patternSyntax() != QRegExp::RegExp
222+
&& (nextKey.isEmpty() || nextKey.indexOf(namespaceFullPath) == -1)) {
203223
QSharedPointer<KeyItem> newKey(new KeyItem(fullKey, currentParent,
204224
parent->model(),
205225
settings.shortKeysRendering));
@@ -209,7 +229,7 @@ void KeysTreeRenderer::renderLazily(QSharedPointer<AbstractNamespaceItem> root,
209229

210230
namespaceItem = QSharedPointer<NamespaceItem>(
211231
new NamespaceItem(namespaceFullPath, m_operations, currentParent,
212-
parent->model(), settings.dbIndex, settings.filter));
232+
parent->model(), settings.dbIndex, settings.filter, nsSeparator.cap()));
213233

214234
if (expandedNamespaces.contains(namespaceFullPath)) {
215235
namespaceItem->setExpanded(true);
@@ -219,8 +239,7 @@ void KeysTreeRenderer::renderLazily(QSharedPointer<AbstractNamespaceItem> root,
219239
}
220240

221241
renderLazily(root, namespaceItem,
222-
notProcessedKeyPart.mid(indexOfNaspaceSeparator +
223-
settings.nsSeparator.length()),
242+
notProcessedKeyPart.mid(indexOfNaspaceSeparator + nsSeparatorLength),
224243
fullKey, m_operations, settings, expandedNamespaces,
225244
level + 1, nextKey);
226245
}

src/modules/connections-tree/keysrendering.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ namespace ConnectionsTree {
1818
public:
1919
struct RenderingSettigns {
2020
QRegExp filter;
21-
QString nsSeparator;
22-
uint dbIndex;
23-
uint renderLimit;
21+
QRegExp nsSeparator;
22+
uint dbIndex;
23+
uint renderLimit;
2424
bool appendNewItems;
2525
bool checkPreRenderedItems;
2626
bool shortKeysRendering;
@@ -31,7 +31,7 @@ namespace ConnectionsTree {
3131
RedisClient::Connection::RawKeysList keys,
3232
QSharedPointer<AbstractNamespaceItem> parent,
3333
RenderingSettigns settings,
34-
const QSet<QByteArray> &expandedNamespaces);
34+
const QSet<QByteArray> &expandedNamespaces);
3535

3636
private:
3737
static void renderLazily(QSharedPointer<AbstractNamespaceItem> root,

src/modules/connections-tree/operations.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class Operations {
5858
* @brief getNamespaceSeparator
5959
* @return
6060
*/
61-
virtual QString getNamespaceSeparator() = 0;
61+
virtual QRegExp getNamespaceSeparator() = 0;
6262

6363
virtual QString defaultFilter() = 0;
6464

src/qml/ConnectionSettignsDialog.qml

+18-8
Original file line numberDiff line numberDiff line change
@@ -761,14 +761,24 @@ Dialog {
761761

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

764-
BetterTextField
765-
{
766-
id: namespaceSeparator
767-
Layout.fillWidth: true
768-
objectName: "rdm_advanced_settings_namespace_separator_field"
769-
placeholderText: qsTranslate("RDM","Separator used for namespace extraction from keys")
770-
text: root.settings ? root.settings.namespaceSeparator : ""
771-
onTextChanged: if (root.settings) { root.settings.namespaceSeparator = text }
764+
RowLayout {
765+
BetterTextField
766+
{
767+
id: namespaceSeparator
768+
Layout.fillWidth: true
769+
objectName: "rdm_advanced_settings_namespace_separator_field"
770+
placeholderText: qsTranslate("RDM","Separator used for namespace extraction from keys")
771+
text: root.settings ? root.settings.namespaceSeparator : ""
772+
onTextChanged: if (root.settings) { root.settings.namespaceSeparator = text }
773+
}
774+
775+
BetterCheckbox {
776+
id: nsRegex
777+
Layout.fillWidth: true
778+
checked: root.settings ? root.settings.namespaceSeparatorIsRegex : false
779+
onCheckedChanged: if (root.settings) { root.settings.namespaceSeparatorIsRegex = checked }
780+
text: qsTranslate("RDM","Regex")
781+
}
772782
}
773783

774784
SettingsGroupTitle {

0 commit comments

Comments
 (0)