DEV Community

Bukunmi Odugbesan
Bukunmi Odugbesan

Posted on

Coding Challenge Practice - Question 85

The task is to implement a function to mimic the Immutability helper function.

The boilerplate code

function update(data, command) {
  // your code here
}

Enter fullscreen mode Exit fullscreen mode

The immutability helper function applies changes to data without mutating the original value by interpreting a command that describes what to change.

If the command is $set, it means to ignore the old data and replace it completely. As soon as $set is found, it is returned immediately

if ('$set' in command) {
  return command.$set;
}
Enter fullscreen mode Exit fullscreen mode

Clone the original data to ensure it isn't mutated

const result = Array.isArray(data) ? data.slice() : { ...data };
Enter fullscreen mode Exit fullscreen mode

If the command is $apply, it means a function is run on the current value, and a new value is returned. It must be a function, or it throws an error

if ('$apply' in command) {
  if (typeof command.$apply !== 'function') {
    throw new Error('$apply must be a function');
  }
  return command.$apply(data);
}
Enter fullscreen mode Exit fullscreen mode

If the command is $merge, it means shallow-merging of new properties can be done on the data. The data must be an object

if ('$merge' in command) {
  if (typeof data !== 'object' || data === null || Array.isArray(data)) {
    throw new Error('$merge can only be used on objects');
  }
  return { ...data, ...command.$merge };
}
Enter fullscreen mode Exit fullscreen mode

If the command is $push, it means items can be appended to the end of an array. Concat is used to avoid mutating the original array.

if ('$push' in command) {
  return result.concat(command.$push);
}
Enter fullscreen mode Exit fullscreen mode

If the command is $unshift, it means items can be added at the beginning of an array.

if ('$unshift' in command) {
  return { ...result, ...command.$unshift };
}
Enter fullscreen mode Exit fullscreen mode

If the command is $splice, it means the array can be modified.

if ('$splice' in command) {
  const copy = result.slice();
  command.$splice.forEach(args => {
    copy.splice(...args);
  });
  return copy;
}
Enter fullscreen mode Exit fullscreen mode

If there is no specific command, walk through each key in command and recursively apply update to the nested data

Object.keys(command).forEach(key => {
  result[key] = update(data[key], command[key]);
});
Enter fullscreen mode Exit fullscreen mode

Return the updated copy

return result;
Enter fullscreen mode Exit fullscreen mode

The final code

function update(data, command) {
  // your code here
  if('$set' in command) {
    return command.$set;
  }

  const result = Array.isArray(data) ? data.slice() : {...data};

  if('$apply' in command) {
    if(typeof command.$apply !== 'function') {
      throw new Error('$apply must be a function')
    }
    return command.$apply(data);
  }

  if('$merge' in command) {
    if(typeof data !== 'object' || data === null || Array.isArray(data)) {
      throw new Error('$merge can only be used on objects')
    }
    return {...data, ...command.$merge}
  }

  if('$push' in command) {
    return result.concat(command.$push);
  }

  if('$unshift' in command) {
    return{...result, ...command.$unshift};
  }

  if('$plice' in command) {
    const copy = result.slice();
    command.$splice.forEach(args => {
      copy.splice(...args);
    })
    return copy;
  }

  Object.keys(command).forEach(key => {
    result[key] = update(data[key], command[key]);
  })
  return result;
}

Enter fullscreen mode Exit fullscreen mode

That's all folks!

Top comments (0)