@cocalc/database
Version:
CoCalc: code for working with our PostgreSQL database
61 lines • 2.44 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.jsonbSet = void 0;
const misc_1 = require("@cocalc/util/misc");
/*
jsonbSet: This little piece of very hard to write (and clever?) code
makes it so we can set or **merge in at any nested level** (!)
arbitrary JSON objects. We can also delete any key at any
level by making the value null or undefined! This is amazingly
easy to use in queries -- basically making JSONP with postgres
as expressive as RethinkDB REQL (even better in some ways).
*/
// The input desc is an object that describes what is being set, e.g.,
// account_id = '... some uuid ';
// desc = {"users": {[account_id]:{group:'collaborator'}}}
// changes the users JSONB field of the table so that users[account_id] has
// the group set to "collaborator".
// If the merge field is set then we merge in the change; otherwise,
// we replace the value.
// IMPORTANT: this is a dangerous attack vector -- do not call this function
// with unsanitized input from a user!
function jsonbSet(desc, merge = false) {
const params = [];
function pushParam(val, type) {
if (type.toUpperCase() == "JSONB") {
val = JSON.stringify(val); // this is needed by the driver....}
}
params.push(val);
return params.length;
}
function set(field, data, path) {
let obj = `COALESCE(${field}#>'{${path.join(",")}}', '{}'::JSONB)`;
for (const key in data) {
const val = data[key];
if (val == null) {
// remove key from object
obj = `(${obj} - '${key}')`;
}
else {
// set key in object
if (merge && typeof val === "object" && !(0, misc_1.is_date)(val)) {
const subobj = set(field, val, path.concat([key]));
obj = `JSONB_SET(${obj}, '{${key}}', ${subobj})`;
}
else {
// completely replace field[key] with val.
obj = `JSONB_SET(${obj}, '{${key}}', $${pushParam(val, "JSONB")}::JSONB)`;
}
}
}
return obj;
}
const v = [];
for (const field in desc) {
const data = desc[field];
v.push(`${field}=${set(field, data, [])}`);
}
return { set: v.join(","), params };
}
exports.jsonbSet = jsonbSet;
//# sourceMappingURL=jsonb-utils.js.map