0

I'm using ES6 to build by Node.js app class. I want to create a db class, so I did the following :

"use strict"

var ini = require('node-ini');
var mysql = require('mysql');
let _db = new WeakMap();

// Class de base pour la base de donnée 
class Db{
    constructor () {
        ini.parse('../config/settings.ini', function(err,data){
            if(err) {
                console.log(err);
                return;
            } else {
                _db.set(this, mysql.createConnection({
                    host     : data.database_MYSQL.host,
                    user     : data.database_MYSQL.username,
                    password : data.database_MYSQL.password,
                    database : data.database_MYSQL.schema
                }));
            }
        });
    }
}

module.exports = Db;

It's the first I'm trying to store a private variable, and I looked on the web for solutions. I found the Weakmap solution that I tried to implement. But the MySQL connection won't store it with the following source code. I have this output :

_db.set(this, mysql.createConnection({
                    ^
TypeError: Invalid value used as weak map key
    at WeakMap.set (native)
    at D:\supervision\application\class\db.js:15:21
    at D:\supervision\application\node_modules\node-ini\node-ini.js:168:12
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:380:3)

So how to deal with it ?

EDIT :

Here is how caller know when it's initialised :

var db;

function instantiateDb(callback){
        db = new db_connector();
        callback(db);
}

instantiateDb(function(db){
    db.connectDatabase();
})
eush77
  • 3,870
  • 1
  • 23
  • 30
Little squirrel
  • 29
  • 2
  • 11
  • `this` is `undefined` inside the callback. Please see [How to access the correct `this` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) for a solution. However, the overall approach seems questionable. Assuming that `parse` is asynchronous, how will the caller know when the initialization is complete? – Felix Kling Apr 24 '17 at 13:38
  • The caller know it I tried to implement promise without success, so i use callback function, like in the edit – Little squirrel Apr 24 '17 at 14:14
  • And at the moment the callback is called, `ini.parse` is *not* done yet. You are basically passing an incomplete object to the callback. – Felix Kling Apr 24 '17 at 14:47

1 Answers1

0

this is undefined inside the callback, it is not referring to an instance of Db, hence you get that error. Have a look at How to access the correct `this` inside a callback? for how to solve that.

However, there is a much bigger problem here: You are performing an asynchronous operation inside the the constructor. That means whatever wants to use an instance of Db has no way of knowing when it will be fully initialized.

A better way of solving this is to have a static asynchronous method that returns a new, fully initialized instance of Db:

class Db {
  static get() {
    return new Promise((resolve, reject) => {
      ini.parse('../config/settings.ini', function(err,data){
        if (err) {
          reject(err);
        } else {
          resolve(new Db(data));
        }
      });
    });
  }

  constructor (data) {
    _db.set(this, mysql.createConnection({
      host     : data.database_MYSQL.host,
      user     : data.database_MYSQL.username,
      password : data.database_MYSQL.password,
      database : data.database_MYSQL.schema
    }));
  }
}

Which can then be used as

Db.get().then(db => {
  db.connectDatabase();
});
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143