mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-27 09:06:15 +01:00
perf: convert promise.all to single query (#9851)
This commit is contained in:
committed by
GitHub
parent
7d1c7e0a7b
commit
ea04aeded4
@@ -16,7 +16,20 @@ module.exports = function (module) {
|
||||
}
|
||||
await module.transaction(async (client) => {
|
||||
const dataString = JSON.stringify(data);
|
||||
async function setOne(key) {
|
||||
|
||||
if (Array.isArray(key)) {
|
||||
await helpers.ensureLegacyObjectsType(client, key, 'hash');
|
||||
await client.query({
|
||||
name: 'setObjectKeys',
|
||||
text: `
|
||||
INSERT INTO "legacy_hash" ("_key", "data")
|
||||
SELECT k, $2::TEXT::JSONB
|
||||
FROM UNNEST($1::TEXT[]) vs(k)
|
||||
ON CONFLICT ("_key")
|
||||
DO UPDATE SET "data" = "legacy_hash"."data" || $2::TEXT::JSONB`,
|
||||
values: [key, dataString],
|
||||
});
|
||||
} else {
|
||||
await helpers.ensureLegacyObjectType(client, key, 'hash');
|
||||
await client.query({
|
||||
name: 'setObject',
|
||||
@@ -28,11 +41,6 @@ module.exports = function (module) {
|
||||
values: [key, dataString],
|
||||
});
|
||||
}
|
||||
if (Array.isArray(key)) {
|
||||
await Promise.all(key.map(k => setOne(k)));
|
||||
} else {
|
||||
await setOne(key);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -40,8 +48,36 @@ module.exports = function (module) {
|
||||
if (!keys.length || !data.length) {
|
||||
return;
|
||||
}
|
||||
// TODO: single query?
|
||||
await Promise.all(keys.map((k, i) => module.setObject(k, data[i])));
|
||||
await module.transaction(async (client) => {
|
||||
keys = keys.slice();
|
||||
data = data.filter((d, i) => {
|
||||
if (d.hasOwnProperty('')) {
|
||||
delete d[''];
|
||||
}
|
||||
const keep = !!Object.keys(d).length;
|
||||
if (!keep) {
|
||||
keys.splice(i, 1);
|
||||
}
|
||||
return keep;
|
||||
});
|
||||
|
||||
if (!keys.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
await helpers.ensureLegacyObjectsType(client, keys, 'hash');
|
||||
const dataStrings = data.map(JSON.stringify);
|
||||
await client.query({
|
||||
name: 'setObjectBulk',
|
||||
text: `
|
||||
INSERT INTO "legacy_hash" ("_key", "data")
|
||||
SELECT k, d
|
||||
FROM UNNEST($1::TEXT[], $2::TEXT::JSONB[]) vs(k, d)
|
||||
ON CONFLICT ("_key")
|
||||
DO UPDATE SET "data" = "legacy_hash"."data" || EXCLUDED.data`,
|
||||
values: [keys, dataStrings],
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.setObjectField = async function (key, field, value) {
|
||||
@@ -51,7 +87,9 @@ module.exports = function (module) {
|
||||
|
||||
await module.transaction(async (client) => {
|
||||
const valueString = JSON.stringify(value);
|
||||
async function setOne(key) {
|
||||
if (Array.isArray(key)) {
|
||||
await module.setObject(key, { [field]: value });
|
||||
} else {
|
||||
await helpers.ensureLegacyObjectType(client, key, 'hash');
|
||||
await client.query({
|
||||
name: 'setObjectField',
|
||||
@@ -63,12 +101,6 @@ module.exports = function (module) {
|
||||
values: [key, field, valueString],
|
||||
});
|
||||
}
|
||||
|
||||
if (Array.isArray(key)) {
|
||||
await Promise.all(key.map(k => setOne(k)));
|
||||
} else {
|
||||
await setOne(key);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -269,7 +301,19 @@ SELECT (h."data" ? $2::TEXT AND h."data"->>$2::TEXT IS NOT NULL) b
|
||||
if (!key || (Array.isArray(key) && !key.length) || !Array.isArray(fields) || !fields.length) {
|
||||
return;
|
||||
}
|
||||
async function delKey(key, fields) {
|
||||
|
||||
if (Array.isArray(key)) {
|
||||
await module.pool.query({
|
||||
name: 'deleteObjectFieldsKeys',
|
||||
text: `
|
||||
UPDATE "legacy_hash"
|
||||
SET "data" = COALESCE((SELECT jsonb_object_agg("key", "value")
|
||||
FROM jsonb_each("data")
|
||||
WHERE "key" <> ALL ($2::TEXT[])), '{}')
|
||||
WHERE "_key" = ANY($1::TEXT[])`,
|
||||
values: [key, fields],
|
||||
});
|
||||
} else {
|
||||
await module.pool.query({
|
||||
name: 'deleteObjectFields',
|
||||
text: `
|
||||
@@ -281,11 +325,6 @@ SELECT (h."data" ? $2::TEXT AND h."data"->>$2::TEXT IS NOT NULL) b
|
||||
values: [key, fields],
|
||||
});
|
||||
}
|
||||
if (Array.isArray(key)) {
|
||||
await Promise.all(key.map(k => delKey(k, fields)));
|
||||
} else {
|
||||
await delKey(key, fields);
|
||||
}
|
||||
};
|
||||
|
||||
module.incrObjectField = async function (key, field) {
|
||||
|
||||
@@ -90,6 +90,13 @@ describe('Hash methods', () => {
|
||||
assert.deepStrictEqual(result, [{ foo: '1' }, null]);
|
||||
});
|
||||
|
||||
it('should update existing object on second call', async () => {
|
||||
await db.setObjectBulk(['bulkKey3.5'], [{ foo: '1' }]);
|
||||
await db.setObjectBulk(['bulkKey3.5'], [{ baz: '2' }]);
|
||||
const result = await db.getObject('bulkKey3.5');
|
||||
assert.deepStrictEqual(result, { foo: '1', baz: '2' });
|
||||
});
|
||||
|
||||
it('should not error if object is empty', async () => {
|
||||
const keys = ['bulkKey5'];
|
||||
const data = [{ }];
|
||||
|
||||
Reference in New Issue
Block a user