Manual Reference Source Test

src/helpers/ProjectContent.js

import ProjectContentService from '../services/ProjectContentService';
import { validate, isRequired } from '../utilities/ValidationUtility';


/**
 * The ProjectContent class wraps custom API endpoints in a simple and quick set of objects /
 * methods.  This object will contain many properties belonging to the type when returned from the
 * server.  A ProjectContent for a car, for example, may have `myCar.make` or `myCar.model` in
 * addition to the listed properties.
 *
 * @property {Object} _options                - Used for API calls
 * @property {String} _options.owner          - The owner of the object (id)
 * @property {String} _options.ownerType      - The ownerType of the object (type)
 * @property {String} [_options.version=v2]   - The version of the api being used
 * @property {any} _meta                      - The combined list of meta data obtained through
 *                                              this instance's call
 * @example
 * let labs1 = new ProjectContent('site_start/labs');  // commonly used
 * let labs2 = new ProjectContent('site_start/labs', { version: 'v2' });
 * let labs3 = new ProjectContent('site_start/labs', { id: 23 });  // commonly used
 * let labs4 = new ProjectContent('site_start/labs', {}, { make: 'corolla' });
 */
class ProjectContent {
  /**
   * This is used to manage the `_options` property
   * - owner (unique identifier / id)
   * - ownerType (content type)
   * - version
   * @type {Object}
   */
  set options(options) { Object.assign(this._options, options); }

  /**
   * This is used to manage the `_options` property
   * @type {Object}
   */
  get options() { return this._options; }

  /**
   * Set _data to set information to the current object.
   * @type {Object}
   */
  set _data(data) { Object.assign(this, data); }

  /**
   * Get _data to quickly get the raw data without options.
   * @type {Object}
   */
  get _data() {
    const clone = JSON.parse(JSON.stringify(this));
    delete clone._options;
    delete clone._meta;
    return clone;
  }

  /**
   * Return meta data for the project content.  The data it consumes is required to come at the
   * root of the API endpoint with the `meta` key containing keys pointing to arrays of data.
   * For example `{"meta": { "certificate_types": [ {"value": ..., "label": ...} ] }}` could then
   * be obtained through `myProjectContent.meta['certificate_types']`
   *
   * @readonly
   *
   * @type {Object}
   */
  get meta() {
    return this._meta;
  }

  /**
   * Creates an instance of ProjectContent.
   *
   * @param {?String} [type='']  - Type of the ProjectContent ('site_start/labs')
   * @param {?any} [options={}]  - Options available to support the API.  Version = 'v2'
   * @param {?any} [data={}]     - The data of the object
   */
  constructor(type = '', options = {}, data = {}, meta = {}) {
    /** @type {Object} */
    this._options = {
      version: 'v2',
      ownerType: type,
    };

    if (options.id) {
      this._options.owner = options.id;
    }

    if (options.type) {
      this._options.ownerType = options.type;
    }

    // copy over data
    this.options = options;
    this._data = data;
    /** @type {Object} */
    this._meta = meta;
  }

  /**
   * Add child of type belonging to the ProjectContent
   *
   * @param {String} type - The type of the child being inserted
   * @param {Object} child - The child data being inserted
   *
   * @return {Promise<Object>} - Promise of the resulting API call
   * @example
   * let lab = new ProjectContent('site_start/labs', { id: 23 });
   * let lab_director = { first_name: 'Joe', last_name: 'Waldron' };
   * await lab.addChild('lab_directors', lab_director).then((data) => (lab_director = data));
   */
  addChild(type, child) {
    return (new ProjectContentService()).insertProject(this.options, type, child);
  }

  // /**
  //  * Add a comment for this project content
  //  *
  //  * @return {Promise<Comment>} - Promise with an array containing the new comment
  //  */
  // addComment(text) {
  //   return (new DiscussService()).addComment(
  //     text,
  //     this._options.ownerType,  // content type
  //     this._options.owner,  // content id
  //     'mobile_user'
  //     // this._options.ownerType,  // owner type
  //     // this._options.owner // owner id
  //   );
  // }

  /**
   * Gets all data belonging to the ProjectContent ownerType
   *
   * @return {Promise<ProjectContent[]>} - Promise of an Array of ProjectContent
   * @example
   * let labs = new ProjectContent('site_start/labs');
   * labs.getAll().then((list) => {
   *   console.log(list);
   * });
   * // or alternatively in one line
   * (new ProjectContent('site_start/labs')).getAll().then((list) => console.log(list));
   */
  getAll() {
    const { version, ownerType } = this.options;
    return (new ProjectContentService()).getProject({ version, ownerType }).then((results) => {
      // @TODO handle meta
      this._meta = Object.assign({}, results.meta || {}, this._meta);
      return results.data.map(obj => new ProjectContent(ownerType, { version, owner: obj.id }, obj));
    });
  }

  /**
   * Get one child with id and type belonging to the ProjectContent
   *
   * @param {String} type - The type of the child
   * @param {Number} id - The id of the child
   *
   * @return {Promise<Object>} - Promise of the resulting API call
   * @example
   * let lab = new ProjectContent('site_start/labs', { id: 23 });
   * let lab_director = await lab.getChild('lab_directors', 512);
   */
  getChild(type, id) {
    return (new ProjectContentService()).getProject(this.options, type, id).then((results) => {
      // @TODO handle meta data
      this._meta = Object.assign({}, results.meta || {}, this._meta);
      return results.data;
    });
  }

  /**
   * Get all children with type belonging to the ProjectContent
   *
   * @param {String} type - The type of the children to be returned
   * @return {Promise<Array>} - Promise of an array of children json
   * @example
   * let lab = new ProjectContent('site_start/labs', { id: 23 });
   * let lab_directors = await lab.getChildren('lab_directors');
   */
  getChildren(type) {
    return (new ProjectContentService()).getProject(this.options, type).then((results) => {
      // @TODO handle meta data
      this._meta = Object.assign({}, results.meta || {}, this._meta);
      return results.data;
    });
  }

  /**
   * Gets data belonging to this ProjectContent (ownerType and owner).  Stores data in
   * ProjectContent.
   *
   * @return {Promise<Object>} - Promise of the data
   * @example
   * let lab = new ProjectContent('site_start/labs');
   * lab.getAll().then((list) => {
   *   list[0].getData().then(() => console.log(list[0])); // should have new properties
   * });
   * lab = new ProjectContent('site_start/labs', { id: 23 });
   * lab.getData().then(() => console.log(lab)); // should have new properties
   * lab.meta;  // Accumulates through getData, getChildren, and getSibling calls
   */
  getData() {
    validate('Clinical6 ProjectContent.getData',
      isRequired({ version: this.options.version }),
      isRequired({ ownerType: this.options.ownerType }),
      isRequired({ owner: this.options.owner }));
    return (new ProjectContentService()).getProject(this.options).then((results) => {
      this._meta = Object.assign({}, results.meta || {}, this._meta);
      this._data = results;
      return this._data;
    });
  }

  /**
   * Get data belonging to a sibling provided the id assuming ProjectContent's type
   *
   * @param {Number} id - The id of the sibling
   * @return {Promise<ProjectContent>}
   * @example
   * let lab = new ProjectContent('site_start/labs', { id: 23 });
   * let other_lab = await lab.getSibling(24);
   */
  getSibling(id) {
    const params = {
      version: this.options.version,
      ownerType: this.options.ownerType,
      owner: id,
    };
    return (new ProjectContentService()).getProject(params).then((results) => {
      this._meta = Object.assign({}, results.meta || {}, this._meta);
      return new ProjectContent('', params, results.data, results.meta || {});
    });
  }

  /**
   * Remove child of type belonging to the ProjectContent
   *
   * @param {String} type - The type of the child being removed
   * @param {Number} id - The child data being inserted
   *
   * @return {Promise<any>} - Promise of the resulting API call
   * @example
   * let lab = new ProjectContent('site_start/labs', { id: 23 });
   * let lab_director = await lab.removeChild('lab_directors', 512);
   */
  removeChild(type, id) {
    return (new ProjectContentService()).deleteProject(this.options, type, id);
  }

  /**
   * Saves the current ProjectContent object.  If it has an id, then update else insert.
   *
   * @return {Promise<any>}
   * @example
   * // Create new lab
   * let lab = new ProjectContent('site_start/labs');
   * lab.name = 'La Jolla Clinic';
   * await lab.save();  // id does not exist so it inserts, but will now have name
   * // Update existing lab name
   * lab.name = 'New Name';
   * lab.save();
   */
  save() {
    return (this.options.owner && this.options.owner !== '')
      ? (new ProjectContentService()).updateProject(this.options, '', null, this._data)
      : (new ProjectContentService()).insertProject(this.options, '', this._data)
        .then((results) => {
          this._data = results;
          this._options.owner = results.id;
        });
  }

  /**
   * Update child of type belonging to the ProjectContent
   *
   * @param {String} type   - The type of the child being updated
   * @param {Object} child  - The child data being updated
   * @param {Number} [id]   - The id of the child being updated
   * @return {Promise<any>}
   * @example
   * let lab = new ProjectContent('site_start/labs', { id: 23 });
   * let lab_directors = await lab.getChildren('lab_directors');
   * lab_directors[0].first_name = 'Joe';
   * lab.updateChild('lab_directors', lab_directors[0]);
   */
  updateChild(type, child, id = undefined) {
    return (new ProjectContentService())
      .updateProject(this.options, type, id || child.id, child);
  }
}

export default ProjectContent;