dataclasses/columns.js

const mergeAll = require('ramda/src/mergeAll');
const trim = require('ramda/src/trim');
const $_type = require('./$_type');

/**
 * Target type definition
 * @typedef {Object} Target
 * @memberof dataclasses
 */

/**
 * Create a new target
 * @param {object} target target
 * @param {string} target.target_id - unique id for this target
 * @param {string} target.label - label that will be displayed for this target
 * @param {string} target.type_id - the type_id name this target has
 * @return {Target} {@link dataclasses.Target}
 * @memberof dataclasses
 */
function Target(target) {
  const { target_id, label, type_id } = _requireProps(
    target,
    'target_id,label,type_id'
  );
  // target MUST at least have the attributes bellow
  return mergeAll([$_type('Target'), { target_id, label, type_id }, target]);
}

/**
 * @param  {Target} target target
 * @return {Object} JSON serializable object
 */
Target.toJSON = function(target) {
  return {
    target_id: target.target_id,
  };
};

/**
 * A type operator
 * @typedef Operator
 * @memberof dataclasses
 */

/**
 * Create a new operator
 * @param {object} operator operator
 * @param {string} operator.operator_id - unique id for this operator
 * @param {string} operator.argumentType_id - the argumentType associated with the operator. For example to define a "is" operator and associate it with two targets "article publishing date" and "article title" then we would have to define 2 operators because ["article publishing date" "is"] and  ["article title" "is"] do NOT have the same kind of arguments (one is a date the other is a string) and associated UI components (one is a date picker the other is a text input)
 * @param {string} operator.label - label that will be displayed for this operator
 * @return {Operator} {@link dataclasses.Operator}
 * @memberof dataclasses
 */
function Operator(operator) {
  // operator MUST at least have the properties bellow
  const { operator_id, label, argumentType_id } = _requireProps(
    operator,
    'operator_id,label,argumentType_id'
  );
  return mergeAll([
    $_type('Operator'),
    {
      operator_id,
      argumentType_id,
      label,
    },
    operator,
  ]);
}

/**
 * @param  {Operator} operator operator
 * @return {Object} JSON serializable object
 */
Operator.toJSON = function(operator) {
  return {
    operator_id: operator.operator_id,
  };
};

/**
 * Defines a target type
 * @typedef Type
 * @memberof dataclasses
 */

/**
 * Create a new type
 * @param {Object} type type
 * @param {string} type.type_id type_id
 * @param {string[]} type.operator_ids array of operator_id
 * @return {Type} {@link dataclasses.Type}
 * @memberof dataclasses
 */
function Type(type) {
  // type MUST at least have the properties bellow
  const { type_id, operator_ids } = _requireProps(type, 'type_id,operator_ids');
  return mergeAll([
    $_type('Type'),
    {
      type_id,
      operator_ids,
    },
    type,
  ]);
}

/**
 * Create a new type logical type
 * Logical types or used in CompoundPredicates
 * @param {Object} logicalType The predicate logic
 * @param {string} logicalType.logicalType_id logicalType_id
 * @param {string} logicalType.label label
 * @return {object} logicalType object
 * @memberof dataclasses
 */
function LogicalType(logicalType) {
  // logicalType MUST at least have the properties bellow
  const { logicalType_id, label } = _requireProps(
    logicalType,
    'logicalType_id,label'
  );
  return mergeAll([
    $_type('LogicalType'),
    {
      logicalType_id,
      label,
    },
    logicalType,
  ]);
}

/**
 * @param  {LogicalType} logicalType logicalType
 * @return {Object} JSON serializable object
 */
LogicalType.toJSON = function(logicalType) {
  return {
    logicalType_id: logicalType.logicalType_id,
  };
};

/**
 * Create a new argument type
 * @param {Object} argumentType argumentType
 * @param {string} type.argumentType_id argumentType_id
 * @param {*} type.component this attribute will be used by the UI Framework adapter
 * @return {object} ArgumentType
 * @memberof dataclasses
 */
function ArgumentType(argumentType) {
  // argumentType MUST at least have the properties bellow
  const { argumentType_id, component } = _requireProps(
    argumentType,
    'argumentType_id,component'
  );
  return mergeAll([
    $_type('ArgumentType'),
    {
      argumentType_id,
      component,
    },
    argumentType,
  ]);
}

const _toString = Object.prototype.toString;
function _isObject(mixed) {
  return _toString.call(mixed) === '[object Object]';
}
/**
 * @param       {Object} object object
 * @param       {string} properties comma-separated list of properties
 * @return      {Object} the passed object
 * @throws throw if a property is missing from the object
 * @private
 */
function _requireProps(object, properties) {
  if (!_isObject(object))
    throw new Error(`Object is required, got: ${JSON.stringify(object)}.`);

  const props = properties.split(',').map(trim);
  let prop;

  while ((prop = props.pop())) {
    if (!object.hasOwnProperty(prop)) {
      throw new Error(
        `Object ${JSON.stringify(object)} MUST have a '${prop}' property.`
      );
    }
  }

  return object;
}

module.exports = {
  Type,
  Target,
  Operator,
  LogicalType,
  ArgumentType,
  _requireProps,
};