简体   繁体   中英

refactor if statements to remove redundancy

I am supposed to refactor the below code and I did that (see image).
My lead is still not happy with it LOL.

const { appTargetId, appUserTargetId, appUserId } = buildIndexKeys(input);
    const fromDate = moment(input.requestDate)
      .subtract(retention, 'days')
      .toISOString();

    if (input.targetId && !input.userId) {
      // with target id and no user id
      let query = this.model
        .query('appTargetId')
        .eq(appTargetId)
        .where('createDate')
        .ge(fromDate)
        .where('status')
        .not()
        .eq(NotificationStatus.Delete);
      /* istanbul ignore next */
      if (input.subApplicationId) {
        query = query.filter('subApplicationId').eq(input.subApplicationId);
      }
      return query.exec();
    } else if (input.userId && !input.targetId) {
      // with user id and no target id
      return this.model
        .query('appUserId')
        .eq(appUserId)
        .where('createDate')
        .ge(fromDate)
        .where('status')
        .not()
        .eq(NotificationStatus.Delete)
        .exec();
    } else {
      // user id + target id
      return this.model
        .query('appUserTargetId')
        .eq(appUserTargetId)
        .where('createDate')
        .ge(fromDate)
        .where('status')
        .not()
        .eq(NotificationStatus.Delete)
        .exec();
    }


在此处输入图像描述

How else can I write this?? Spent so many hours trying to move, mend and bend this piece of code.
Anyone out there with a better solution??

I think this strikes a good balance between terseness and clarity.

For 1/pair of arrows) I think the index/indexstring variables are kind of cumbersome, so I just built it into the if statement.

For 2) I personally find the.where().not().eq() chains and comparable much clearer/easier to read on a single line than spread out like that.

For 3) you can consolidate that to a single return.

const { appTargetId, appUserTargetId, appUserId } = buildIndexKeys(input);
const fromDate = moment(input.requestDate)
   .subtract(retention, 'days').toISOString();

// Since the point of this function is query-building, we need it available through the whole thing.
let query;

// Single ifs are clearer
if (input.targetId) {
   if (input.userId) {
      query = this.model.query('appUserTargetId').eq(appUserTargetId);
   } else {
      query = this.model.query('appTargetId').eq(appTargetId);
   }
} else {
   query = this.model.query('appUserId').eq(appUserId);
}

// This part is common
query = query
   .where('createDate').ge(fromDate)
   .where('status').not().eq(NotificationStatus.Delete);

// Not sure if this depends on being conditioned on all 3 or if just subApplicationId would suffice
/* istanbul ignore next */
if (input.subApplicationId && input.targetId && !input.userId) {
   query = query.filter('subApplicationId').eq(input.subApplicationId);
}

// Execute the query
return query.exec();

Here is a bit better optimized version of it. Avoiding multiple if loops and shorter code.

const { appTargetId, appUserTargetId, appUserId } = buildIndexKeys(input);

const fromDate = moment(input.requestDate)
      .subtract(retention, 'days')
      .toISOString();
const index = (input.targetId ? (input.userId ? {"appUserTargetId" : appUserTargetId} : {"appTargetId": appTargetId}) : {"appUserId" : appUserId};

let query = this.model
        .query(Object.keys(index)[0])
        .eq(Object.values(index)[0])
        .where('createDate')
        .ge(fromDate)
        .where('status')
        .not()
        .eq(NotificationStatus.Delete);
if (input.subApplicationId) {
    query = query.filter('subApplicationId').eq(input.subApplicationId);
}

return query.exec();

If the reviewer is not in favour of single line multiple ternary operator, you could try one of these two options.

(targetId && userId && {"appUserTargetId" : appUserTargetId}) || (targetId && {'appTargetId' : appTargetId}) || (userId && {'appUserId': appUserId})

[OR]

Do Object Oriented Javascript (OOJS). Create a base class and 3 extended classes. Each of the 3 extended class correspond to the if case. Here is the details on the basics of OOJS

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS

Try this:

    const { appTargetId, appUserTargetId, appUserId } = buildIndexKeys(input);
    const fromDate = moment(input.requestDate)
      .subtract(retention, 'days')
      .toISOString();

    let indexString;
    let index;

    if (input.targetId && !input.userId) {
      // with target id and no user id
      indexString = 'appTargetId';
      index = appTargetId;
      /* istanbul ignore next */
    } else if (input.userId && !input.targetId) {
      // with user id and no target id
      indexString = 'appUserId';
      index = appUserId;
    } else {
      // user id + target id
      indexString = 'appUserTargetId';
      index = appUserTargetId;
    }

    let query;
    if (input.subApplicationId) {
      query = query.filter('subApplicationId').eq(input.subApplicationId);
    } else {
      query = this.model
          .query(indexString)
          .eq(index)
          .where('createDate')
          .ge(fromDate)
          .where('status')
          .not()
          .eq(NotificationStatus.Delete)
    }

    return query.exec(); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM