0

I have this function, with two ifs where I want to find the user depending on which alphanumeric code I receive. How can I refactor this one with sanctuary-js?

//const code = '0011223344';
const code = 'aabbc';

const isNumberCode = code => !!/^[0-9]{10}$/.exec(code);
const isLiteralCode = code => !!/^[A-Za-z]{5}$/.exec(code);

const findUser = (criteria) => {
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        resolve('user object');
      }, 300);
    });
}

async function handler(code) {
    if (isNumberCode(code)) {
       const user = await findUser({id: code});
        return user;
    }
    if (isLiteralCode(code)) {
       const user = await findUser({identifier: code});
       return user;
    }

    return 'not found';
}

async function run() {
    const user = await handler(code);

    console.log(user)
}

run();

I can't understand how I should handle three different types: number code, literal code and not found code.

-- UPDATE

Here my functional solution (I may think so):

const Code = x => ({
  chain: f => f(x),
  fold: (e, a, f) => e(x)
});

const ErrorCode = x => ({
  fold: (e, a, f) => e(x),
  findLabel: f => ErrorCode(x)
});

const PromiseToCode = promise => ({
  fold: (e, a, f) => promise.then(x => x.fold(e, a, f))
});

const NumberCode = x => ({
  fold: (e, a, f) => a(x),
  findLabel: f => PromiseToCode(f(x, {activationCode: x}, NumberCode))
});

const LiteralCode = x => ({
  fold: (e, a, f) => f(x),
  findLabel: f => PromiseToCode(f(x, {finderCode: x}, LiteralCode))
});

const checkTypeOfCode = code => {
  if (isNumberCode(code)) {
    return NumberCode(code);
  }
  if (isLiteralCode(code)) {
    return LiteralCode(code);
  }
  return ErrorCode(code);
};

const find = async (code, criteria, type) => {
  const user = findUser();
  if (!user) {
    return ErrorCode(code);
  }
  return type(user);
};

const handler2 = (code) =>
    Code(code)
    .chain(checkTypeOfCode)
    .findLabel(find)
    .fold(
        e => 'not found',
        a => 'user object find by id',
        l => 'user object find by identifier'
    )

handler2(code).then(console.log);

But I don't know if it's good code. Also I'm asking about sanctuary-js because I think that all this object not good way to programming.

Ivan
  • 2,463
  • 1
  • 20
  • 28
  • If you don't like the if blocks you could use a switch-case. But I don't think those are any easier to read or any cleaner as code – Doug Feb 07 '19 at 12:19
  • 3
    @Doug if this code was just transformed into switch, it's going to have to use the somewhat awful reverse switch style. I don't know the exact name of the method but it's what I call it - it's when you do `switch(true)` and then each case is an evaluated expression and you *hope* at most one of the `case` statements evaluates to `true`. So, yeah - not easy to read or cleaner. – VLAZ Feb 07 '19 at 12:22
  • @Doug thank you for your comment. I update my question with my solution. But I don't know if it's good way. – Ivan Feb 07 '19 at 12:36
  • @VLAZ Good point – Ivan Feb 07 '19 at 12:37
  • What error are you getting? can you give out more details as in what you wish to accomplish here? – Neeraj Feb 07 '19 at 12:16
  • I just wondering how I can write this code more functional style. How I should handle multiple types of input with sanctuary-js or another js-fp library. – Ivan Feb 07 '19 at 12:21

2 Answers2

0

Since you are looking for a more functional restructuring, you can try this:

Divide your code into smaller, more independent sections:

  • findUser: This function is responsible to give either UserObject or Not found.
  • Create a function getCriteria, that will have all the logic as to isNumberCode or isLiteralCode etc. This will return a criteria object or undefined.
  • handler should be responsible to get criteria, and based on that return findUser's response. Any cleanup code can be kept here but this is a hub function which calls various functions and return an output. It should have bare minimum business logic.
//const code = '0011223344';
const code = 'aabbc';

const isNumberCode = code => !!/^[0-9]{10}$/.exec(code);
const isLiteralCode = code => !!/^[A-Za-z]{5}$/.exec(code);

const findUser = (criteria) => {
  return new Promise(function(resolve, reject) {
    if (!criteria) resolve('not found')
    setTimeout(function() {
      resolve('user object');
    }, 300);
  });
}

function getCriteria(code) {
  if (isNumberCode(code)) {
    return { id: code };
  }
  if (isLiteralCode(code)) {
    return { identifier: code }
  }
}

async function handler(code) {
  const user = await findUser(getCriteria(code))
  return user;
}

async function run() {
  const user = await handler(code);

  console.log(user)
}

run();
Rajesh
  • 24,354
  • 5
  • 48
  • 79
0

You can create enum for multiple type of input and use switch statement as below.

// Enum for search-parameters
var ParameterTypes = 
{
  NUMBER :1 ,
  LITERAL:2 ,
  OTHER : 3
}

function getParameterType()
{
  //responsible to get search-parameter
  return isNumberCode(code) ? ParameterTypes.NUMBER : 
    ( isLiteralCode(code) ? ParameterTypes.LITERAL : ParameterTypes.OTHER);
}

async function handler(code) 
{
    //responsible to search user
    var user;

    switch(getParameterType())    
    {
      case ParameterTypes.NUMBER : 
          user = await findUser({id: code}); 
          //console.log('number');
          break;

      case ParameterTypes.LITERAL :           
          user = await findUser({identifier: code}); 
          //console.log('literal');
          break;

      case ParameterTypes.OTHER : 
          user = 'not found';      
          //console.log('other');    
          break;
    }   

    return user;
}
Himen Suthar
  • 80
  • 1
  • 3
  • 11