From 7d5402fe66d3c244be4e0d4103e9386a0c933f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20U=C5=9Fakl=C4=B1?= Date: Wed, 3 Dec 2025 18:18:14 -0500 Subject: [PATCH] feat: setAddBulk (#13805) * feat: setAddBulk add some tests * fix: sAdd with value array on redis --- src/database/mongo/sets.js | 25 +++++++++++++++++++++++++ src/database/postgres/sets.js | 26 ++++++++++++++++++++++++++ src/database/redis/sets.js | 22 ++++++++++++++++++++-- test/database/sets.js | 30 ++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 2 deletions(-) diff --git a/src/database/mongo/sets.js b/src/database/mongo/sets.js index 0c84a0f210..0dafb61945 100644 --- a/src/database/mongo/sets.js +++ b/src/database/mongo/sets.js @@ -68,6 +68,31 @@ module.exports = function (module) { } }; + module.setAddBulk = async function (data) { + if (!data.length) { + return; + } + + const bulk = module.client.collection('objects').initializeUnorderedBulkOp(); + + data.forEach(([key, member]) => { + bulk.find({ _key: key }).upsert().updateOne({ + $addToSet: { + members: helpers.valueToString(member), + }, + }); + }); + try { + await bulk.execute(); + } catch (err) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, data); + return await module.setAddBulk(data); + } + throw err; + } + }; + module.setRemove = async function (key, value) { if (!Array.isArray(value)) { value = [value]; diff --git a/src/database/postgres/sets.js b/src/database/postgres/sets.js index 82c3f16aff..41a05c8953 100644 --- a/src/database/postgres/sets.js +++ b/src/database/postgres/sets.js @@ -54,6 +54,32 @@ DO NOTHING`, }); }; + module.setAddBulk = async function (data) { + if (!data.length) { + return; + } + const keys = []; + const members = []; + + for (const [key, member] of data) { + keys.push(key); + members.push(member); + } + await module.transaction(async (client) => { + await helpers.ensureLegacyObjectsType(client, keys, 'set'); + await client.query({ + name: 'setAddBulk', + text: ` +INSERT INTO "legacy_set" ("_key", "member") +SELECT k, m +FROM UNNEST($1::TEXT[], $2::TEXT[]) AS t(k, m) +ON CONFLICT ("_key", "member") +DO NOTHING;`, + values: [keys, members], + }); + }); + }; + module.setRemove = async function (key, value) { if (!Array.isArray(key)) { key = [key]; diff --git a/src/database/redis/sets.js b/src/database/redis/sets.js index dd7e484325..861bf275ea 100644 --- a/src/database/redis/sets.js +++ b/src/database/redis/sets.js @@ -14,11 +14,29 @@ module.exports = function (module) { }; module.setsAdd = async function (keys, value) { - if (!Array.isArray(keys) || !keys.length) { + if (!Array.isArray(keys) || !keys.length || !value) { + return; + } + if (!Array.isArray(value)) { + value = [value]; + } + if (!value.length) { return; } const batch = module.client.batch(); - keys.forEach(k => batch.sAdd(String(k), String(value))); + keys.forEach((k) => { + value.forEach(v => batch.sAdd(String(k), String(v))); + }); + await helpers.execBatch(batch); + }; + + module.setAddBulk = async function (data) { + if (!data.length) { + return; + } + + const batch = module.client.batch(); + data.forEach(([key, member]) => batch.sAdd(String(key), String(member))); await helpers.execBatch(batch); }; diff --git a/test/database/sets.js b/test/database/sets.js index 126490aff8..e8e7a454c6 100644 --- a/test/database/sets.js +++ b/test/database/sets.js @@ -88,6 +88,36 @@ describe('Set methods', () => { done(); }); }); + + it('should add the values to each set', async () => { + await db.setsAdd(['saddarray1', 'saddarray2', 'saddarray3'], ['v1', 'v2', 'v3']); + const data = await db.getSetsMembers(['saddarray1', 'saddarray2', 'saddarray3']); + data.forEach(members => members.sort()); + assert.deepStrictEqual(data, [ + ['v1', 'v2', 'v3'], + ['v1', 'v2', 'v3'], + ['v1', 'v2', 'v3'], + ]); + }); + }); + + describe('setAddBulk()', () => { + it('should add multiple key-member pairs', async () => { + await db.setAddBulk([ + ['bulkSet1', 'value1'], + ['bulkSet2', 'value2'], + ]); + let data = await db.getSetMembers('bulkSet1'); + assert.deepStrictEqual(data, ['value1']); + data = await db.getSetMembers('bulkSet2'); + assert.deepStrictEqual(data, ['value2']); + await db.setAddBulk([ + ['bulkSet1', 'value1'], + ['bulkSet1', 'value3'], + ]); + data = await db.getSetMembers('bulkSet1'); + assert.deepStrictEqual(data.sort(), ['value1', 'value3']); + }); }); describe('getSetsMembers()', () => {