mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-05 13:36:01 +01:00
PostgreSQL database driver (#5861)
* [test/database/list] Fix test list 4 being used in two different tests * [database/postgres] PostgreSQL database driver * [database/postgres] Make transactions work based on continuation scope. * [database/postgres] Implement nested transactions * eslint --fix * Add database changes from earlier this week to the PostgreSQL driver. * Fix typo * Fix postgres.incrObjectFieldBy returning undefined instead of null when given NaN * [database/postgres] Fix sortedSetsCard returning an array of strings. * Update socket.io postgres adapter * Fix PostgreSQL erroring when multiple updates are made to the same sorted set entry in a single operation. Add a test case to catch this error. * Fix lint errors. * Only prune sessions on one instance in a cluster to avoid deadlocks. They're caught and handled by the database server, but they spam the logs. * Fix arguments.slice.
This commit is contained in:
139
src/database/postgres/helpers.js
Normal file
139
src/database/postgres/helpers.js
Normal file
@@ -0,0 +1,139 @@
|
||||
'use strict';
|
||||
|
||||
var helpers = {};
|
||||
|
||||
helpers.valueToString = function (value) {
|
||||
if (value === null || value === undefined) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return value.toString();
|
||||
};
|
||||
|
||||
helpers.removeDuplicateValues = function (values) {
|
||||
var others = Array.prototype.slice.call(arguments, 1);
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
if (values.lastIndexOf(values[i]) !== i) {
|
||||
values.splice(i, 1);
|
||||
for (var j = 0; j < others.length; j++) {
|
||||
others[j].splice(i, 1);
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
helpers.ensureLegacyObjectType = function (db, key, type, callback) {
|
||||
db.query({
|
||||
name: 'ensureLegacyObjectTypeBefore',
|
||||
text: `
|
||||
DELETE FROM "legacy_object"
|
||||
WHERE "expireAt" IS NOT NULL
|
||||
AND "expireAt" <= CURRENT_TIMESTAMP`,
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
db.query({
|
||||
name: 'ensureLegacyObjectType1',
|
||||
text: `
|
||||
INSERT INTO "legacy_object" ("_key", "type")
|
||||
VALUES ($1::TEXT, $2::TEXT::LEGACY_OBJECT_TYPE)
|
||||
ON CONFLICT
|
||||
DO NOTHING`,
|
||||
values: [key, type],
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
db.query({
|
||||
name: 'ensureLegacyObjectType2',
|
||||
text: `
|
||||
SELECT "type"
|
||||
FROM "legacy_object_live"
|
||||
WHERE "_key" = $1::TEXT`,
|
||||
values: [key],
|
||||
}, function (err, res) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (res.rows[0].type !== type) {
|
||||
return callback(new Error('database: cannot insert ' + JSON.stringify(key) + ' as ' + type + ' because it already exists as ' + res.rows[0].type));
|
||||
}
|
||||
|
||||
callback(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
helpers.ensureLegacyObjectsType = function (db, keys, type, callback) {
|
||||
db.query({
|
||||
name: 'ensureLegacyObjectTypeBefore',
|
||||
text: `
|
||||
DELETE FROM "legacy_object"
|
||||
WHERE "expireAt" IS NOT NULL
|
||||
AND "expireAt" <= CURRENT_TIMESTAMP`,
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
db.query({
|
||||
name: 'ensureLegacyObjectsType1',
|
||||
text: `
|
||||
INSERT INTO "legacy_object" ("_key", "type")
|
||||
SELECT k, $2::TEXT::LEGACY_OBJECT_TYPE
|
||||
FROM UNNEST($1::TEXT[]) k
|
||||
ON CONFLICT
|
||||
DO NOTHING`,
|
||||
values: [keys, type],
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
db.query({
|
||||
name: 'ensureLegacyObjectsType2',
|
||||
text: `
|
||||
SELECT "_key", "type"
|
||||
FROM "legacy_object_live"
|
||||
WHERE "_key" = ANY($1::TEXT[])`,
|
||||
values: [keys],
|
||||
}, function (err, res) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var invalid = res.rows.filter(function (r) {
|
||||
return r.type !== type;
|
||||
});
|
||||
|
||||
if (invalid.length) {
|
||||
return callback(new Error('database: cannot insert multiple objects as ' + type + ' because they already exist: ' + invalid.map(function (r) {
|
||||
return JSON.stringify(r._key) + ' is ' + r.type;
|
||||
}).join(', ')));
|
||||
}
|
||||
|
||||
var missing = keys.filter(function (k) {
|
||||
return !res.rows.some(function (r) {
|
||||
return r._key === k;
|
||||
});
|
||||
});
|
||||
|
||||
if (missing.length) {
|
||||
return callback(new Error('database: failed to insert keys for objects: ' + JSON.stringify(missing)));
|
||||
}
|
||||
|
||||
callback(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
helpers.noop = function () {};
|
||||
|
||||
module.exports = helpers;
|
||||
Reference in New Issue
Block a user