UNPKG

@cocalc/database

Version:

CoCalc: code for working with our PostgreSQL database

61 lines 2.44 kB
"use strict"; 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