async update()

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);
    }
  }