Source: batchmanager.js

import stampit from 'stampit';
import _ from 'lodash';
import Request from './request';

/**
* Manager for handling batch requests to the platform. Supported actions are 'create', 'update', 'delete'. Meant to be used directly form the {@link Syncano} instance.
*
* @constructor
* @type {BatchManager}
*
* @example {@lang javascript}
* const connection = Syncano();
* const manager = connection.BatchManager({instanceName});
* manager.addObjects({ object: DataObject({data}), action: 'save' }, { object: DataObject({other_data}), action: 'create' });
* manager.batch().then(() => {
*   // success
* })
*
* @example {@lang javascript}
* const connection = Syncano();
* const manager = connection.BatchManager({instanceName});
* manager.addSingleObject(DataObject({data}), 'create');
* manager.batch().then(() => {
*   // success
* })
*/
const BatchManager = stampit()
  .compose(Request)
  .props({
    objects: [],
    batchUrl: '/v1.1/instances/{instance}/batch/',
    maxBatchObjects: 50
  })
  .init(function() {
    if(!_.has(this, 'instanceName') && !_.has(this.getDefaultProperties(), 'instanceName')) {
      throw new Error('No instance name specified.');
    }
    this.instanceName = this.instanceName || this.getDefaultProperties().instanceName;
    this.batchUrl = _.replace(this.batchUrl, '{instance}', this.instanceName);
  })
  .methods({

    addObjects(...objects) {
      this.validateObjectsLength(_.size(_.flatten(objects)));
      _.each(objects, (object) => {
          this.objects = _.concat(this.objects, object);
      });
      this.objects = _.flatten(this.objects);
      if(!_.every(this.objects, (object) => {
        return _.has(object, 'object._meta') && _.has(object, 'action');
      })) {
        this.removeObjects();
        throw new Error('The Batch Manager only accepts properly formatted objects.');
      }
      return this;
    },

    addObjectsFromArray(objects, action) {
      this.validateObjectsLength(objects.length);
      _.each(objects, (object) => {
        this.objects = _.concat(this.objects, { object, action });
      });
      return this;
    },

    addSingleObject(object, action) {
      if(!_.has(object, '_meta')) {
        throw new Error('The supplied object is not a valid object.');
      }
      this.validateObjectsLength(1);
      this.objects = _.concat(this.objects, { object, action });
      return this;
    },

    batch() {
      if(_.isEmpty(this.objects)) {
        throw new Error('No objects provided for batching.');
      }
      const requests = _.map(this.objects, (batch) => batch.object.toBatchObject(batch.action));

      return this.makeRequest('POST', this.batchUrl, { payload: {requests}});
    },

    validateObjectsLength(length) {
      const existingLength = _.size(this.objects);
      if(_.add(existingLength, length) > this.maxBatchObjects) {
        throw new Error('Only 50 objects can be batched at once.');
      }
    },

    removeObjects() {
      this.objects = [];
      return this;
    },

    getObjects() {
      return this.objects;
    }

  });

export default BatchManager;