function upsertOneSample(sampleQueryBodyObj, isBulk, user) {
  const userName = user ? user.name : false;
  const sampleName = sampleQueryBodyObj.name;
  let parsedSampleName = {};
  try {
    parsedSampleName = parseName(sampleName.toLowerCase());
  } catch (err) {
    if (isBulk) {
      return Promise.reject({ isFailed: true, explanation: err });
    }

    return Promise.reject(err);
  }

  const sampleKey = sampleStore.toKey(constants.objectType.sample, sampleName);
  const absolutePath = parsedSampleName.subject.absolutePath;
  const aspectName = parsedSampleName.aspect.name;
  const subjKey = sampleStore.toKey(constants.objectType.subject, absolutePath);
  let aspectObj = {};
  let subject;
  let aspect;
  let sample;
  let noChange = false;

  /*
   * If any of these promises throws an error, we drop through to the catch
   * block and return an error. Otherwise, we return the sample.
   */
  return checkWritePermission(aspectName, userName, isBulk)
  .then(() => Promise.all([
    redisClient.hgetallAsync(subjKey),
    redisClient.hgetallAsync(
      sampleStore.toKey(constants.objectType.aspect, aspectName)),
    redisClient.hgetallAsync(sampleKey),
  ])
  .then((responses) => {
    [subject, aspect, sample] = responses;
    if (!subject || subject.isPublished === 'false') {
      handleUpsertError(constants.objectType.subject, isBulk, sampleName);
    }

    if (!aspect || aspect.isPublished === 'false') {
      handleUpsertError(constants.objectType.aspect, isBulk, sampleName);
    }

    sampleQueryBodyObj.subjectId = subject.id;
    sampleQueryBodyObj.aspectId = aspect.id;
    aspectObj = sampleStore.arrayObjsStringsToJson(aspect,
      constants.fieldsToStringify.aspect);
    return checkWritePermission(aspectObj, userName, isBulk);
  })
  .then(() => {
    if (sample && !isSampleChanged(sampleQueryBodyObj, sample)) {
      /* Sample is not new AND nothing has changed */
      noChange = true;
    }

    // sampleQueryBodyObj updated with fields
    updateSampleAttributes(sampleQueryBodyObj, sample, aspectObj);

    if (sample) { // if sample exists, just update sample
      delete sampleQueryBodyObj.name; // to avoid updating sample name
      logInvalidHmsetValues(sampleKey, sampleQueryBodyObj);
      return redisClient.hmsetAsync(sampleKey, sampleQueryBodyObj);
    }

    /*
     * Otherwise the sample is new. Set the name to be the combination of
     * subject absolutePath and aspect name.
     */
    sampleQueryBodyObj.name = subject.absolutePath + '|' + aspectObj.name;

    // Add the provider and user fields.
    if (user) {
      sampleQueryBodyObj.provider = user.id;
      sampleQueryBodyObj.user = JSON.stringify({
        name: user.name,
        email: user.email,
        profile: {
          name: user.profile.name,
        },
      });
    }

    const cmds = []; // redis commands for batch processing

    // add the aspect name to the subject-to-aspect resource mapping
    cmds.push(redisOps.addAspectInSubjSetCmd(absolutePath, aspectName));

    // add sample to the master list of sample index
    cmds.push(redisOps.addKeyToIndexCmd(sampleType, sampleName));

    // create/update hash of sample. Check and log invalid Hmset values
    cmds.push(
      redisOps.setHashMultiCmd(sampleType, sampleName, sampleQueryBodyObj)
    );

    // add subject absolute path to aspect-to-subject resource mapping
    cmds.push(redisOps.addSubjectAbsPathInAspectSet(
      aspectObj.name, subject.absolutePath)
    );

    return redisOps.executeBatchCmds(cmds);
  }))
  .then(() => redisClient.hgetallAsync(sampleKey))
  .then((updatedSamp) => {
    if (!updatedSamp.name) {
      updatedSamp.name = subject.absolutePath + '|' + aspectObj.name;
    }

    // Publish the sample.nochange event
    if (noChange) {
      updatedSamp.noChange = true;
      updatedSamp.absolutePath = subject.absolutePath;
      updatedSamp.aspectName = aspectObj.name;
      updatedSamp.aspectTags = aspectObj.tags || [];
      updatedSamp.aspectTimeout = aspectObj.timeout;

      if (Array.isArray(subject.tags)) {
        updatedSamp.subjectTags = subject.tags;
      } else {
        try {
          updatedSamp.subjectTags = JSON.parse(subject.tags);
        } catch (err) {
          updatedSamp.subjectTags = [];
        }
      }

      return updatedSamp; // skip cleanAdd...
    }

    return cleanAddAspectToSample(updatedSamp, aspectObj);
  })
  .then((updatedSamp) => {
    if (updatedSamp.hasOwnProperty(noChange) && updatedSamp.noChange === true) {
      return updatedSamp;
    }

    return cleanAddSubjectToSample(updatedSamp, subject);
  })
  .catch((err) => {
    if (isBulk) return err;
    throw err;
  });
} // upsertOneSample
/**
 * Upsert a sample. If subject exists, get aspect and sample. If aspect exists,
 * create fields array with values need to be set for sample in redis. Add
 * aspect name to subject set, add aspect key to sample set and update/create
 * sample hash. We use hset which updates a sample if exists, else creates a
 * new one.
 *
 * @param  {Object} sampleQueryBodyObj - Query Body Object for a sample
 * @param  {Boolean} isBulk - If the caller method is bulk upsert
 * @param {Object} user - The user performing the write operation
 * @returns {Object} - Updated sample
 */
Upsert a sample. If subject exists, get aspect and sample. If aspect exists,
create fields array with values need to be set for sample in redis. Add
aspect name to subject set, add aspect key to sample set and update/create
sample hash. We use hset which updates a sample if exists, else creates a
new one.

@param  {Object} sampleQueryBodyObj - Query Body Object for a sample
@param  {Boolean} isBulk - If the caller method is bulk upsert
@param {Object} user - The user performing the write operation
@returns {Object} - Updated sample
Upsert a sample . If subject exists get aspect and sample . If aspect exists create fields array with values need to be set for sample in redis . Add aspect name to subject set add aspect key to sample set and update / create sample hash . We use hset which updates a sample if exists else creates a new one . @param { Object } sampleQueryBodyObj - Query Body Object for a sample @param { Boolean } isBulk - If the caller method is bulk upsert @param { Object } user - The user performing the write operation @returns { Object } - Updated sample
function upsertOneSample(sampleQueryBodyObj, isBulk, user) {
  const userName = user ? user.name : false;
  const sampleName = sampleQueryBodyObj.name;
  let parsedSampleName = {};
  try {
    parsedSampleName = parseName(sampleName.toLowerCase());
  } catch (err) {
    if (isBulk) {
      return Promise.reject({ isFailed: true, explanation: err });
    }
    return Promise.reject(err);
  }
  const sampleKey = sampleStore.toKey(constants.objectType.sample, sampleName);
  const absolutePath = parsedSampleName.subject.absolutePath;
  const aspectName = parsedSampleName.aspect.name;
  const subjKey = sampleStore.toKey(constants.objectType.subject, absolutePath);
  let aspectObj = {};
  let subject;
  let aspect;
  let sample;
  let noChange = false;
  return checkWritePermission(aspectName, userName, isBulk)
  .then(() => Promise.all([
    redisClient.hgetallAsync(subjKey),
    redisClient.hgetallAsync(
      sampleStore.toKey(constants.objectType.aspect, aspectName)),
    redisClient.hgetallAsync(sampleKey),
  ])
  .then((responses) => {
    [subject, aspect, sample] = responses;
    if (!subject || subject.isPublished === 'false') {
      handleUpsertError(constants.objectType.subject, isBulk, sampleName);
    }
    if (!aspect || aspect.isPublished === 'false') {
      handleUpsertError(constants.objectType.aspect, isBulk, sampleName);
    }
    sampleQueryBodyObj.subjectId = subject.id;
    sampleQueryBodyObj.aspectId = aspect.id;
    aspectObj = sampleStore.arrayObjsStringsToJson(aspect,
      constants.fieldsToStringify.aspect);
    return checkWritePermission(aspectObj, userName, isBulk);
  })
  .then(() => {
    if (sample && !isSampleChanged(sampleQueryBodyObj, sample)) {
      noChange = true;
    }
    updateSampleAttributes(sampleQueryBodyObj, sample, aspectObj);
    if (sample) { 
      delete sampleQueryBodyObj.name; 
      logInvalidHmsetValues(sampleKey, sampleQueryBodyObj);
      return redisClient.hmsetAsync(sampleKey, sampleQueryBodyObj);
    }
    sampleQueryBodyObj.name = subject.absolutePath + '|' + aspectObj.name;
    if (user) {
      sampleQueryBodyObj.provider = user.id;
      sampleQueryBodyObj.user = JSON.stringify({
        name: user.name,
        email: user.email,
        profile: {
          name: user.profile.name,
        },
      });
    }
    const cmds = []; 
    cmds.push(redisOps.addAspectInSubjSetCmd(absolutePath, aspectName));
    cmds.push(redisOps.addKeyToIndexCmd(sampleType, sampleName));
    cmds.push(
      redisOps.setHashMultiCmd(sampleType, sampleName, sampleQueryBodyObj)
    );
    cmds.push(redisOps.addSubjectAbsPathInAspectSet(
      aspectObj.name, subject.absolutePath)
    );
    return redisOps.executeBatchCmds(cmds);
  }))
  .then(() => redisClient.hgetallAsync(sampleKey))
  .then((updatedSamp) => {
    if (!updatedSamp.name) {
      updatedSamp.name = subject.absolutePath + '|' + aspectObj.name;
    }
    if (noChange) {
      updatedSamp.noChange = true;
      updatedSamp.absolutePath = subject.absolutePath;
      updatedSamp.aspectName = aspectObj.name;
      updatedSamp.aspectTags = aspectObj.tags || [];
      updatedSamp.aspectTimeout = aspectObj.timeout;
      if (Array.isArray(subject.tags)) {
        updatedSamp.subjectTags = subject.tags;
      } else {
        try {
          updatedSamp.subjectTags = JSON.parse(subject.tags);
        } catch (err) {
          updatedSamp.subjectTags = [];
        }
      }
      return updatedSamp; 
    }
    return cleanAddAspectToSample(updatedSamp, aspectObj);
  })
  .then((updatedSamp) => {
    if (updatedSamp.hasOwnProperty(noChange) && updatedSamp.noChange === true) {
      return updatedSamp;
    }
    return cleanAddSubjectToSample(updatedSamp, subject);
  })
  .catch((err) => {
    if (isBulk) return err;
    throw err;
  });
} 
function upsertOneSample ( sampleQueryBodyObj , isBulk , user ) { const userName = user ? user . name : false ; const sampleName = sampleQueryBodyObj . name ; let parsedSampleName = { } ; try { parsedSampleName = parseName ( sampleName . toLowerCase ( ) ) ; } catch ( err ) { if ( isBulk ) { return Promise . reject ( { isFailed : true , explanation : err } ) ; } return Promise . reject ( err ) ; } const sampleKey = sampleStore . toKey ( constants . objectType . sample , sampleName ) ; const absolutePath = parsedSampleName . subject . absolutePath ; const aspectName = parsedSampleName . aspect . name ; const subjKey = sampleStore . toKey ( constants . objectType . subject , absolutePath ) ; let aspectObj = { } ; let subject ; let aspect ; let sample ; let noChange = false ; return checkWritePermission ( aspectName , userName , isBulk ) . then ( ( ) => Promise . all ( [ redisClient . hgetallAsync ( subjKey ) , redisClient . hgetallAsync ( sampleStore . toKey ( constants . objectType . aspect , aspectName ) ) , redisClient . hgetallAsync ( sampleKey ) , ] ) . then ( ( responses ) => { [ subject , aspect , sample ] = responses ; if ( ! subject || subject . isPublished === 'false' ) { handleUpsertError ( constants . objectType . subject , isBulk , sampleName ) ; } if ( ! aspect || aspect . isPublished === 'false' ) { handleUpsertError ( constants . objectType . aspect , isBulk , sampleName ) ; } sampleQueryBodyObj . subjectId = subject . id ; sampleQueryBodyObj . aspectId = aspect . id ; aspectObj = sampleStore . arrayObjsStringsToJson ( aspect , constants . fieldsToStringify . aspect ) ; return checkWritePermission ( aspectObj , userName , isBulk ) ; } ) . then ( ( ) => { if ( sample && ! isSampleChanged ( sampleQueryBodyObj , sample ) ) { noChange = true ; } updateSampleAttributes ( sampleQueryBodyObj , sample , aspectObj ) ; if ( sample ) { delete sampleQueryBodyObj . name ; logInvalidHmsetValues ( sampleKey , sampleQueryBodyObj ) ; return redisClient . hmsetAsync ( sampleKey , sampleQueryBodyObj ) ; } sampleQueryBodyObj . name = subject . absolutePath + '|' + aspectObj . name ; if ( user ) { sampleQueryBodyObj . provider = user . id ; sampleQueryBodyObj . user = JSON . stringify ( { name : user . name , email : user . email , profile : { name : user . profile . name , } , } ) ; } const cmds = [ ] ; cmds . push ( redisOps . addAspectInSubjSetCmd ( absolutePath , aspectName ) ) ; cmds . push ( redisOps . addKeyToIndexCmd ( sampleType , sampleName ) ) ; cmds . push ( redisOps . setHashMultiCmd ( sampleType , sampleName , sampleQueryBodyObj ) ) ; cmds . push ( redisOps . addSubjectAbsPathInAspectSet ( aspectObj . name , subject . absolutePath ) ) ; return redisOps . executeBatchCmds ( cmds ) ; } ) ) . then ( ( ) => redisClient . hgetallAsync ( sampleKey ) ) . then ( ( updatedSamp ) => { if ( ! updatedSamp . name ) { updatedSamp . name = subject . absolutePath + '|' + aspectObj . name ; } if ( noChange ) { updatedSamp . noChange = true ; updatedSamp . absolutePath = subject . absolutePath ; updatedSamp . aspectName = aspectObj . name ; updatedSamp . aspectTags = aspectObj . tags || [ ] ; updatedSamp . aspectTimeout = aspectObj . timeout ; if ( Array . isArray ( subject . tags ) ) { updatedSamp . subjectTags = subject . tags ; } else { try { updatedSamp . subjectTags = JSON . parse ( subject . tags ) ; } catch ( err ) { updatedSamp . subjectTags = [ ] ; } } return updatedSamp ; } return cleanAddAspectToSample ( updatedSamp , aspectObj ) ; } ) . then ( ( updatedSamp ) => { if ( updatedSamp . hasOwnProperty ( noChange ) && updatedSamp . noChange === true ) { return updatedSamp ; } return cleanAddSubjectToSample ( updatedSamp , subject ) ; } ) . catch ( ( err ) => { if ( isBulk ) return err ; throw err ; } ) ; }
Upsert a sample.
Upsert a sample .
/*
   * If any of these promises throws an error, we drop through to the catch
   * block and return an error. Otherwise, we return the sample.
   */ /* Sample is not new AND nothing has changed */ // sampleQueryBodyObj updated with fields // if sample exists, just update sample // to avoid updating sample name /*
     * Otherwise the sample is new. Set the name to be the combination of
     * subject absolutePath and aspect name.
     */ // Add the provider and user fields. // redis commands for batch processing // add the aspect name to the subject-to-aspect resource mapping // add sample to the master list of sample index // create/update hash of sample. Check and log invalid Hmset values // add subject absolute path to aspect-to-subject resource mapping // Publish the sample.nochange event // skip cleanAdd... // upsertOneSample