5

Is there a way to throw an error if property could not be found from data.

Problem is, it is mapping undefined instead of throwing error.

const insertIntoTable = function(data) {
    return new Promise((resolve, reject) => {
        const entry = {
            Id: data.id,
            Method: data.Method,
            Status: data.PaymentStatus,
            InsertedAt: (new Date().getTime())
        }
    }).catch((error) => {
       console.log(error); 
    });
}
user88432
  • 397
  • 1
  • 4
  • 13
  • 3
    You are never resolving your promise – J. Pichardo Jun 05 '18 at 15:00
  • You have to check each property manually e.g. `if (data.id === undefined) throw new Error("mapping undefined")` Also call resolve/reject to resolve the promise. – sztrzask Jun 05 '18 at 15:01
  • 1
    You create an entry but then throw it away... Because you never use it for anything (for example return it). You also never resolve your promise. – CherryDT Sep 02 '22 at 13:26
  • Well doing `.catch((error) => { console.log(error); });` suppresses *any* error and fulfills with `undefined` instead. Just remove that part from your code completely. – Bergi Jan 02 '23 at 02:47

4 Answers4

3

You can check if the properties are undefined by comparing it to undefined. For example, if you wanted to check the id property, you could use

if(data.id === undefined){
     throw new Error();
}
Pang
  • 9,564
  • 146
  • 81
  • 122
0
const insertIntoTable = function(data) {
return new Promise((resolve, reject) => {
    if(data.id){
      const entry = {
        Id: data.id,
        Method: data.Method,
        Status: data.PaymentStatus,
        InsertedAt: (new Date().getTime())
      }
      return resolve(entry);
    }
    return reject();

    })
    .then((data) => {
        // treat your entry data
    }) 
    .catch(() => {
       throw new Error("data is undefined")
    });
}
Truong Dang
  • 3,119
  • 1
  • 15
  • 21
  • 1
    There is no need to return `resolve` or `reject`, besides OP wants to check individual properties, not just `data` – J. Pichardo Jun 05 '18 at 15:07
  • I return just for no need `else`. So, change your condition like `data.id !== undefined` – Truong Dang Jun 05 '18 at 15:09
  • You don't need else, the function's final call is to `reject` – J. Pichardo Jun 05 '18 at 15:10
  • From my understanding of promises, you aren't post to return `resolve` or `reject`. You just call them. Why do you return them? – Tyler Jun 05 '18 at 15:10
  • I knew it, but just my habit, i alway return them in my promise code...^^ – Truong Dang Jun 05 '18 at 15:11
  • 1
    @TruongDang It appears that it does change how the code works. According to [this post](https://stackoverflow.com/q/34668878/6009304), a return halts the function. Without it, the function can continue going on. Interesting... – Tyler Jun 05 '18 at 15:15
  • @Tyler Yep, Just make sure it completely break right there.. I meet a bug with nodejs in the past. My backend code still runing after response. Since, I keep habbit return to make sure it break... – Truong Dang Jun 05 '18 at 15:21
  • wants to check individual properties – user88432 Jun 05 '18 at 15:41
  • @user88432 Did you use `Lodash` ? check like this `if(!_.isEmpty(data))` to make sure your data `object` not empty – Truong Dang Jun 05 '18 at 15:46
0

First you need to correctly start your Promise, since you are not resolving it, I like to do it like so:

const insertIntoTable = function(data) {
    return Promise.resolve()
    .then(() => {
        const entry = {
            Id: data.id,
            Method: data.Method,
            Status: data.PaymentStatus,
            InsertedAt: (new Date().getTime())
        }
        // Do something with entry
    })
    .catch((error) => {
       console.log(error); 
    });
}

This way you can throw inside you validation (instead of rejecting)

You could create a validation function that checks for undefined, like so:

const validate = property => {
    if (property === undefined) throw 'data missing required property'
    return property
}

And use it like so:

const entry = {
    Id: validate(data.id),
    Method: validate(data.Method),
    Status: validate(data.PaymentStatus),
    InsertedAt: (new Date().getTime())
}

But this way you would always get the same error. You could change it to show an error based on the property name:

const getAndValidate = (data, propertyName) => {
    const property = data[propertyName]
    if (property === undefined) throw 'data missing the required property' + propertyName
    return property 
}

And use it like so:

const entry = {
    Id: getAndValidate(data, 'id'),
    Method: getAndValidate(data, 'Method'),
    Status: getAndValidate(data, 'PaymentStatus'),
    InsertedAt: (new Date().getTime())
}

This way you get the right error everytime, but I don't like to access the attributes using string names

Denis
  • 2,030
  • 1
  • 12
  • 15
-1

One way of doing it would be to take advantage of the short-circuit evaluation, and do something like:

const insertIntoTable = function(data) {
  return new Promise((resolve, reject) => {
      const entry = {
        Id: data.id || reject("data.id is undefined"),
        Method: data.Method  || reject("data.Method is undefined"),
        Status: data.PaymentStatus  || reject("data.PaymentStatus is undefined"),
        InsertedAt: (new Date().getTime())
      }
      resolve(entry);
  }).catch((error) => {
    console.log(error);
  });
}

insertIntoTable({}).then(data => console.log(data));

However, I find this hard to read, so I'm currently looking for a better alternative.

UPDATE

I had been working on a function using proxies that provides an optional or default behavior, the function is

function optional(obj, evalFunc, def) {

  // Our proxy handler
  const handler = {
    // Intercept all property access
    get: function(target, prop, receiver) {
      const res = Reflect.get(...arguments);

      // If our response is an object then wrap it in a proxy else just return
      return typeof res === "object" ? proxify(res) : res != null ? res : def;
    }
  };

  const proxify = target => {
    return new Proxy(target, handler);
  };

  // Call function with our proxified object
  return evalFunc(proxify(obj, handler));
}

And could be applied here as

const insertIntoTable = function(data) {
  return new Promise((resolve, reject) => {
      const entry = {
        Id: optional(data, t => t.Id, reject('Id is not present')),
        Method: optional(data, t => t.Method, reject('Method is not present')),
        Status: optional(data, t => t.PaymentStatus, reject('PaymentStatus is not present')),
        InsertedAt: (new Date().getTime())
      }
      resolve(entry);
  }).catch((error) => {
    console.log(error);
  });
}

insertIntoTable({}).then(data => console.log(data));

The advantage this has is that it supports deep properties access.

J. Pichardo
  • 3,077
  • 21
  • 37