scan. glob to regex (#14063)

* scan. glob to regex

* lint
This commit is contained in:
Barış Uşaklı
2026-03-05 16:01:03 -05:00
committed by GitHub
parent 5d1a8a11fd
commit 7d50baecf0
6 changed files with 44 additions and 30 deletions

View File

@@ -26,3 +26,19 @@ helpers.mergeBatch = function (batchData, start, stop, sort) {
} while (item && (result.length < (stop - start + 1) || stop === -1));
return result;
};
helpers.globToRegex = function (match) {
if (!match) {
return '^.*$';
}
let _match = match.replace(/[.+^${}()|[\]\\]/g, '\\$&');
_match = _match.replace(/\*/g, '.*').replace(/\?/g, '.');
if (!match.startsWith('*')) {
_match = '^' + _match;
}
if (!match.endsWith('*')) {
_match = _match + '$';
}
return _match;
};

View File

@@ -1,7 +1,6 @@
'use strict';
const helpers = module.exports;
const utils = require('../../utils');
helpers.noop = function () {};
@@ -50,20 +49,3 @@ helpers.valueToString = function (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;
};

View File

@@ -1,7 +1,7 @@
'use strict';
module.exports = function (module) {
const helpers = require('./helpers');
const dbHelpers = require('../helpers');
module.flushdb = async function () {
await module.client.dropDatabase();
};
@@ -39,7 +39,7 @@ module.exports = function (module) {
};
module.scan = async function (params) {
const match = helpers.buildMatchQuery(params.match);
const match = dbHelpers.globToRegex(params.match);
return await module.client.collection('objects').distinct(
'_key', { _key: { $regex: new RegExp(match) } }
);

View File

@@ -543,7 +543,7 @@ module.exports = function (module) {
project.score = 1;
}
const match = helpers.buildMatchQuery(params.match);
const match = dbHelpers.globToRegex(params.match);
let regex;
try {
regex = new RegExp(match);

View File

@@ -2,6 +2,7 @@
module.exports = function (module) {
const helpers = require('./helpers');
const dbHelpers = require('../helpers');
module.flushdb = async function () {
await module.pool.query(`DROP SCHEMA "public" CASCADE`);
@@ -84,20 +85,14 @@ module.exports = function (module) {
};
module.scan = async function (params) {
let { match } = params;
if (match.startsWith('*')) {
match = `%${match.substring(1)}`;
}
if (match.endsWith('*')) {
match = `${match.substring(0, match.length - 1)}%`;
}
const regex = dbHelpers.globToRegex(params.match);
const res = await module.pool.query({
text: `
SELECT o."_key"
FROM "legacy_object_live" o
WHERE o."_key" LIKE $1`,
values: [match],
WHERE o."_key" ~ $1`,
values: [regex],
});
return res.rows.map(r => r._key);

View File

@@ -86,6 +86,27 @@ describe('Key methods', () => {
assert(data.includes('ip:124:uid'));
assert(data.includes('ip:1:uid'));
});
it('should scan keys for specific glob pattern', async () => {
const keys = [
'tid:00000b86-a333-45ee-ba88-17e78aa6c814:recipients',
'tid:00001fa5-61e1-4ba5-ac22-572ab98eb76f:recipients',
'tid:00002ce3-203d-4b14-a201-b3d021f462a5:recipients',
'other:123:stuff',
'tid:999:sender',
];
await db.sortedSetAddBulk(keys.map(key => [key, 1, 'a']));
const data = await db.scan({ match: 'tid:*:recipients' });
assert.equal(data.length, 3, 'Should have found exactly 3 recipient keys');
assert(data.includes('tid:00000b86-a333-45ee-ba88-17e78aa6c814:recipients'));
assert(data.includes('tid:00001fa5-61e1-4ba5-ac22-572ab98eb76f:recipients'));
assert(data.includes('tid:00002ce3-203d-4b14-a201-b3d021f462a5:recipients'));
assert(!data.includes('other:123:stuff'), 'Should not include unrelated keys');
assert(!data.includes('tid:999:sender'), 'Should not include sender keys');
});
});
it('should delete a key without error', (done) => {