mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-28 01:26:16 +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) => {
|
await module.transaction(async (client) => {
|
||||||
const dataString = JSON.stringify(data);
|
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 helpers.ensureLegacyObjectType(client, key, 'hash');
|
||||||
await client.query({
|
await client.query({
|
||||||
name: 'setObject',
|
name: 'setObject',
|
||||||
@@ -28,11 +41,6 @@ module.exports = function (module) {
|
|||||||
values: [key, dataString],
|
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) {
|
if (!keys.length || !data.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: single query?
|
await module.transaction(async (client) => {
|
||||||
await Promise.all(keys.map((k, i) => module.setObject(k, data[i])));
|
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) {
|
module.setObjectField = async function (key, field, value) {
|
||||||
@@ -51,7 +87,9 @@ module.exports = function (module) {
|
|||||||
|
|
||||||
await module.transaction(async (client) => {
|
await module.transaction(async (client) => {
|
||||||
const valueString = JSON.stringify(value);
|
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 helpers.ensureLegacyObjectType(client, key, 'hash');
|
||||||
await client.query({
|
await client.query({
|
||||||
name: 'setObjectField',
|
name: 'setObjectField',
|
||||||
@@ -63,12 +101,6 @@ module.exports = function (module) {
|
|||||||
values: [key, field, valueString],
|
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) {
|
if (!key || (Array.isArray(key) && !key.length) || !Array.isArray(fields) || !fields.length) {
|
||||||
return;
|
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({
|
await module.pool.query({
|
||||||
name: 'deleteObjectFields',
|
name: 'deleteObjectFields',
|
||||||
text: `
|
text: `
|
||||||
@@ -281,11 +325,6 @@ SELECT (h."data" ? $2::TEXT AND h."data"->>$2::TEXT IS NOT NULL) b
|
|||||||
values: [key, fields],
|
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) {
|
module.incrObjectField = async function (key, field) {
|
||||||
|
|||||||
@@ -90,6 +90,13 @@ describe('Hash methods', () => {
|
|||||||
assert.deepStrictEqual(result, [{ foo: '1' }, null]);
|
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 () => {
|
it('should not error if object is empty', async () => {
|
||||||
const keys = ['bulkKey5'];
|
const keys = ['bulkKey5'];
|
||||||
const data = [{ }];
|
const data = [{ }];
|
||||||
|
|||||||
Reference in New Issue
Block a user