mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-02 12:05:57 +01:00
Zscan (#8458)
* feat: zscan * fix: mongodb tests * feat: scan, ip search starts with
This commit is contained in:
committed by
GitHub
parent
be85123ad5
commit
e95cd28f6f
@@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var helpers = module.exports;
|
const helpers = module.exports;
|
||||||
|
const utils = require('../../utils');
|
||||||
|
|
||||||
helpers.noop = function () {};
|
helpers.noop = function () {};
|
||||||
|
|
||||||
@@ -48,3 +49,21 @@ helpers.deserializeData = function (data) {
|
|||||||
helpers.valueToString = function (value) {
|
helpers.valueToString = function (value) {
|
||||||
return String(value);
|
return String(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
helpers.buildMatchQuery = function (match) {
|
||||||
|
let _match = match;
|
||||||
|
if (match.startsWith('*')) {
|
||||||
|
_match = _match.substring(1);
|
||||||
|
}
|
||||||
|
if (match.endsWith('*')) {
|
||||||
|
_match = _match.substring(0, _match.length - 1);
|
||||||
|
}
|
||||||
|
_match = utils.escapeRegexChars(_match);
|
||||||
|
if (!match.startsWith('*')) {
|
||||||
|
_match = '^' + _match;
|
||||||
|
}
|
||||||
|
if (!match.endsWith('*')) {
|
||||||
|
_match += '$';
|
||||||
|
}
|
||||||
|
return _match;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = function (module) {
|
module.exports = function (module) {
|
||||||
|
const helpers = require('./helpers');
|
||||||
module.flushdb = async function () {
|
module.flushdb = async function () {
|
||||||
await module.client.dropDatabase();
|
await module.client.dropDatabase();
|
||||||
};
|
};
|
||||||
@@ -27,6 +28,13 @@ module.exports = function (module) {
|
|||||||
return item !== undefined && item !== null;
|
return item !== undefined && item !== null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.scan = async function (params) {
|
||||||
|
const match = helpers.buildMatchQuery(params.match);
|
||||||
|
return await module.client.collection('objects').distinct(
|
||||||
|
'_key', { _key: { $regex: new RegExp(match) } }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
module.delete = async function (key) {
|
module.delete = async function (key) {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -472,20 +472,7 @@ module.exports = function (module) {
|
|||||||
project.score = 1;
|
project.score = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let match = params.match;
|
const match = helpers.buildMatchQuery(params.match);
|
||||||
if (params.match.startsWith('*')) {
|
|
||||||
match = match.substring(1);
|
|
||||||
}
|
|
||||||
if (params.match.endsWith('*')) {
|
|
||||||
match = match.substring(0, match.length - 1);
|
|
||||||
}
|
|
||||||
match = utils.escapeRegexChars(match);
|
|
||||||
if (!params.match.startsWith('*')) {
|
|
||||||
match = '^' + match;
|
|
||||||
}
|
|
||||||
if (!params.match.endsWith('*')) {
|
|
||||||
match += '$';
|
|
||||||
}
|
|
||||||
let regex;
|
let regex;
|
||||||
try {
|
try {
|
||||||
regex = new RegExp(match);
|
regex = new RegExp(match);
|
||||||
|
|||||||
@@ -42,6 +42,25 @@ module.exports = function (module) {
|
|||||||
return res.rows[0].e;
|
return res.rows[0].e;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.scan = async function (params) {
|
||||||
|
let match = params.match;
|
||||||
|
if (match.startsWith('*')) {
|
||||||
|
match = '%' + match.substring(1);
|
||||||
|
}
|
||||||
|
if (match.endsWith('*')) {
|
||||||
|
match = match.substring(0, match.length - 1) + '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await module.pool.query({
|
||||||
|
text: `
|
||||||
|
SELECT o."_key"
|
||||||
|
FROM "legacy_object_live" o
|
||||||
|
WHERE o."_key" LIKE '${match}'`,
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.rows.map(r => r._key);
|
||||||
|
};
|
||||||
|
|
||||||
module.delete = async function (key) {
|
module.delete = async function (key) {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -23,6 +23,18 @@ module.exports = function (module) {
|
|||||||
return exists === 1;
|
return exists === 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.scan = async function (params) {
|
||||||
|
let cursor = '0';
|
||||||
|
let returnData = [];
|
||||||
|
do {
|
||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
|
const res = await module.client.async.scan(cursor, 'MATCH', params.match, 'COUNT', 10000);
|
||||||
|
cursor = res[0];
|
||||||
|
returnData = returnData.concat(res[1]);
|
||||||
|
} while (cursor !== '0');
|
||||||
|
return returnData;
|
||||||
|
};
|
||||||
|
|
||||||
module.delete = async function (key) {
|
module.delete = async function (key) {
|
||||||
await module.client.async.del(key);
|
await module.client.async.del(key);
|
||||||
module.objectCache.delObjectCache(key);
|
module.objectCache.delObjectCache(key);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ module.exports = function (redisClient) {
|
|||||||
send_command: util.promisify(redisClient.send_command).bind(redisClient),
|
send_command: util.promisify(redisClient.send_command).bind(redisClient),
|
||||||
|
|
||||||
exists: util.promisify(redisClient.exists).bind(redisClient),
|
exists: util.promisify(redisClient.exists).bind(redisClient),
|
||||||
|
scan: util.promisify(redisClient.scan).bind(redisClient),
|
||||||
|
|
||||||
del: util.promisify(redisClient.del).bind(redisClient),
|
del: util.promisify(redisClient.del).bind(redisClient),
|
||||||
get: util.promisify(redisClient.get).bind(redisClient),
|
get: util.promisify(redisClient.get).bind(redisClient),
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const _ = require('lodash');
|
||||||
|
|
||||||
const meta = require('../meta');
|
const meta = require('../meta');
|
||||||
const plugins = require('../plugins');
|
const plugins = require('../plugins');
|
||||||
const db = require('../database');
|
const db = require('../database');
|
||||||
@@ -128,6 +130,8 @@ module.exports = function (User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function searchByIP(ip) {
|
async function searchByIP(ip) {
|
||||||
return await db.getSortedSetRevRange('ip:' + ip + ':uid', 0, -1);
|
const ipKeys = await db.scan({ match: 'ip:' + ip + '*' });
|
||||||
|
const uids = await db.getSortedSetRevRange(ipKeys, 0, -1);
|
||||||
|
return _.uniq(uids);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -61,6 +61,21 @@ describe('Key methods', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('scan', function () {
|
||||||
|
it('should scan keys for pattern', async function () {
|
||||||
|
await db.sortedSetAdd('ip:123:uid', 1, 'a');
|
||||||
|
await db.sortedSetAdd('ip:123:uid', 2, 'b');
|
||||||
|
await db.sortedSetAdd('ip:124:uid', 2, 'b');
|
||||||
|
await db.sortedSetAdd('ip:1:uid', 1, 'a');
|
||||||
|
await db.sortedSetAdd('ip:23:uid', 1, 'a');
|
||||||
|
const data = await db.scan({ match: 'ip:1*' });
|
||||||
|
assert.equal(data.length, 3);
|
||||||
|
assert(data.includes('ip:123:uid'));
|
||||||
|
assert(data.includes('ip:124:uid'));
|
||||||
|
assert(data.includes('ip:1:uid'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should delete a key without error', function (done) {
|
it('should delete a key without error', function (done) {
|
||||||
db.delete('testKey', function (err) {
|
db.delete('testKey', function (err) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
|
|||||||
Reference in New Issue
Block a user