0

I'm a little newbie in node.js + mysql + object oriented.

Following question here I would like the 'Content' object to use the values returned by a mysql query. What I'm doing now I find it is really redundant and possibly stupid as rows[0] itself is the object I want to use. Any better way for doing this? Or different approach if this is wrong also appreciated.

(I'm using binary uuid keys that must be hex-stringifyed again to send as resource response)

content.js:

function Content() {
  this.id = '';
  this.name = '';
  this.domain = '';
}

Content.prototype.validate = function(path, queryParams) {
  ...
  return true;
};

Content.prototype.whatever = function(apiVersion, params, callback) {
  ...
  return callback(null, newParams);
};

mysql.js:

MySQLDb.SELECT_CONTENT_ID = "SELECT id, name, domain FROM content WHERE id = UNHEX(?)";

MySQLDb.prototype.findContentByID = function(id, callback) {
  this.dbConnection.query(MySQLDb.SELECT_CONTENT_ID, [ id ],
      function(err, rows, fields) {
        var content = new Content();

        if (rows.length > 0) {
          var i = 0;
          for (var key in rows[0]) {
            if (rows[0].hasOwnProperty(key) && content.hasOwnProperty(key)) {
              // BINARY(16) --> HEX string
              if (fields[i].columnType === 254) {
                content[key] = rows[0][key].toString('hex').toUpperCase();
              } else {
                content[key] = rows[0][key];
              }
            } else {
              console.log('Column ' + key + ' out of sync on table "content"');
            }

            i += 1;
          }
        }

        callback(err, content);
      });
};

contentRes.js:

contentRes.GETWhatever = function(req, res) {
  db.findContentByID(req.params.id, function onContent(err, content) {
    if (err || !content.validate(req.path, req.query)) {
      return res.send({});
    }

    content.whatever(req.query.apiVersion, req.query.d,
        function onWhateverdone(err, params) {
          if (err) {
            return res.send({});
          }

          return res.send(params);
        });
  });
};

1 Answer 1

0

I think a lot of people would say you are doing it generally the right way even though it admittedly feels redundant.

It might feel a little cleaner if you refactored your code such that you could call the Content() constructor with an optional object, in this case rows[0] although if you were keeping it clean you wouldn't have access to the fields so you would take a different approach to the data type conversion - either by selecting the HEX representation in query or simply having your Content() know it needs to convert the id property.

Keeping it fairly simple (by which I mean ignoring making the constructor a bit more intelligent as well as any error detection or handling), you would have:

function Content(baseObj) {
  this.id = (baseObj && baseObj.id) ? baseObj.id.toString('hex').toUpperCase() : '';
  this.name = (baseObj && baseObj.name) ? baseObj.name : '';
  this.domain = (baseObj && baseObj.domain) ? baseObj.domain : '';
}

Then you could do something like this:

MySQLDb.prototype.findContentByID = function(id, callback) {
  this.dbConnection.query(MySQLDb.SELECT_CONTENT_ID, [ id ],
  function(err, rows, fields) {
    if (err) return callback(err,null);
    return callback(err, new Content(rows[0]));
  });

You 'could' also grab the rows[0] object directly, HEX the UUID more or less in situ and modify the __proto__ of the object, or under Harmony/ES6 use the setPrototypeOf() method.

MySQLDb.prototype.findContentByID = function(id, callback) {
  this.dbConnection.query(MySQLDb.SELECT_CONTENT_ID, [ id ],
  function(err, rows, fields) {
    if (err) return callback(err,null);
    var content = rows[0];
    content.id = content.id.toString('hex').toUpperCase();
    content.__proto__ = Content.prototype;
    return callback(err, content);
  });

Note, I said you 'could' do this. Reasonable people can differ on whether you 'should' do this. __proto__ is deprecated (although it works just fine in Node from what I have seen). If you take this general approach, I would probably suggest using setPrototypeOf(), and install a polyfill until you are otherwise running with ES6.

Just trying to give you a couple of other more terse ways to do this, given that I think the redundancy/verbosity of the first version is what you didn't like. Hope it helps.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Barry. I still feel it is redundant but this is how I ended doing it. In fact I inserted mysql connection in a singleton class and the rest of the classes call the mysql.query() (which is calling dbConnection.query())
You're welcome. That approach (singleton) does get rid of at least some of the redundant boilerplate. I am very sympathetic to trying to simplify/streamline the DB handling code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.