in source/layers/core-lib/lib/db.js [108:194]
async update(primaryValue, sortValue, attributes, merge = true) {
try {
let original = {};
/* run deepmerge to merge records */
let merged = await (async () => {
if (!merge) {
return Object.assign({}, attributes);
}
const emptyTarget = val =>
((Array.isArray(val)) ? [] : {});
const clone = (val, options) =>
DeepMerge(emptyTarget(val), val, options);
const combineMerge = (target, source, options) => {
const destination = target.slice();
source.forEach((e, i) => {
if (typeof destination[i] === 'undefined') {
const cloneRequested = options.clone !== false;
const shouldClone = cloneRequested && options.isMergeableObject(e);
destination[i] = shouldClone ? clone(e, options) : e;
} else if (options.isMergeableObject(e)) {
destination[i] = DeepMerge(target[i], e, options);
} else if (target.indexOf(e) === -1) {
destination.push(e);
}
});
return destination;
};
/* merge the record first */
original = await this.fetch(primaryValue, sortValue);
return DeepMerge(original, attributes, { arrayMerge: combineMerge });
})();
/* make sure no paritionKey is present in the attributes */
delete merged[this.partitionKey];
delete merged[this.sortKey];
/* IMPORTANT: manually merge attribute(s) that are Array type, the logic below */
/* only handles the top level. Should do it recursively. */
const arrayAttribNames = Object.keys(original).filter(x =>
Array.isArray(original[x]));
arrayAttribNames.forEach((x) => {
if (Array.isArray(attributes[arrayAttribNames])) {
const unique = new Set(attributes[arrayAttribNames].concat(original[arrayAttribNames]));
merged[arrayAttribNames] = Array.from(unique);
}
});
/* now, run sanitizeJson to avoid xss attack before we save to db */
merged = X.sanitizeJson(merged);
const params = {
TableName: this.table,
Key: {
[this.partitionKey]: primaryValue,
},
AttributeUpdates: {},
};
if (this.sortKey) {
params.Key[this.sortKey] = sortValue;
}
Object.keys(merged).forEach((x) => {
params.AttributeUpdates[x] = {
Action: 'PUT',
Value: merged[x],
};
});
const response = await this.instance.update(params).promise();
return response;
} catch (e) {
e.message = `update(${primaryValue}): ${e.message}`;
console.error(e);
throw (e instanceof DBError) ? e : new DBError(e);
}
}