IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

NodeJS Discussion :

Contexte 'this' et Circular object = mauvaise architecture ?


Sujet :

NodeJS

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2013
    Messages
    65
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2013
    Messages : 65
    Points : 39
    Points
    39
    Par défaut Contexte 'this' et Circular object = mauvaise architecture ?
    Bonjour!

    Je dois faire une api json rpc et j'ai deux problèmes:
    • un circular object (est-ce vraiment un probleme ?)
    • plusieurs classes (des repos) et j'ai des difficulté pour utiliser 'this' dans le repo


    Je penses que ces problèmes viennent du fait que j'ai mal architecturer l'appli.. ?

    Comment mon serveur fonctionne :
    Pour le l'architecture DB je me suis inspiré de pg-promise-demo
    1. ./server/server.js récupère les méthode exposée dans ./db/index.js
    2. ./db/index.js 'regroupe' toutes les methods de chaque repo dans une objet avec 'Object.assign()'
    3. Chaque repo possede une propriete 'methods' qui lui permet d'exposer ses methodes (je dois utiliser bind(this) sinon la méthode ne connait pas les propriétés de la classe)



    Mon problème de circular object :
    Dans chaque repo j'ai une propriete 'db' qui y est injectée depuis db/index.js je lui ajoute les repos grace a une fonction de pg-promise (lignes 9 à 12) du coup dans cette propriété j'ai :
    • toutes les méthodes de pg-promise (logique)
    • tous les repos (incluant lui-meme)

    Exemple avec DevicesRepository.db :
    - pg-promise functions
    - les autres repos (RolesRepository, ...)
    - DevicesRepository


    Mon problème de contexte 'this' :
    Dans la fonction 'add', 'this.db' est connu parce que je bind 'this' à la fonction (ligne 15)
    Par contre dans le 'this.db.tx', le contexte devient 'this.db', donc par exemple this.Collections n'est plus connu

    Je suppose que cela signifie que ces problèmes sont liés et que j'ai mal architecturé l'appli ?
    Si oui comment auriez-vous fait ?

    Merci d'avance!

    Un peu de code :
    ./db/repos/devices.js
    Code JAVASCRIPT : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    'use strict';
     
    const cs = {}; // Reusable ColumnSet objects.
     
    var Collections = {};
     
    class DevicesRepository {
      constructor(db, pgp) {
        this.db = db;
        this.pgp = pgp;
     
        this.Collections = createColumnsets(pgp);
     
        this.methods = {
            'devices.insert': this.add.bind(this),
        }
      }
     
      async add(params) {
        console.log(this); //here this = DevicesRepository
        var device = params.data.device;
     
        return this.db.tx(function* (transaction) {
          console.log(this); // here this = transaction = DevicesRepository.db
          //insert a System (returning the inserted ID)
          const system = yield transaction.systems.add(params);
          device.systemid = system.systemId;
     
          const query = this.pgp.helpers.insert(device, this.Collections.insert);
          if(params.return) query += " RETURNING *";
     
          return transaction.one(query);
        })
        .then(data => {
          Log(`INSERTED device ${JSON.stringify(data)}`);
          return data;
        })
        .catch(ex => {
          throw new Error(ex);
        });
      }
    }
     
    /* hidde, for brevity */
     
    module.exports = DevicesRepository;

    ./db/repos/index.js
    Code JAVASCRIPT : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    'use strict';
     
    module.exports = {
    	// other repo are required with the same way
      Devices: require('./devices'),
    };

    ./db/index.js
    Code JAVASCRIPT : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    'use strict';
     
    const repos = require('./repos'); // ./repos/index.js
    const config = require('./conf');
     
    // pg-promise initialization options:
    const initOptions = {
        extend(obj, dc) {
            obj.roles = new repos.Roles(obj, pgp);
            obj.shells = new repos.Shells(obj, pgp);
            obj.systems = new repos.Systems(obj, pgp);
            obj.devices = new repos.Devices(obj, pgp);
        }
    };
     
    // Load and initialize pg-promise:
    const pgp = require('pg-promise')(initOptions);
     
    // Create the database instance:
    const db = pgp(config);
     
    const methods = Object.assign({},
        db.roles.methods,
        db.shells.methods,
        db.systems.methods,
        db.devices.methods,
    );
     
     
    module.exports = {
      methods
    }

    ./server/server.js
    Code JAVASCRIPT : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    const http = require('http');
    const Database = require('../db'); //  ./db/index.js
     
    const methods = Database.methods;
     
    const requestHandler = (req, res) => {
      // some lines are hidden for brevity
      const body = [];
      req.on('data', (chunk) => {
        body.push(chunk);
      }).on('end', () => {
        const bodyStr = Buffer.concat(body).toString();
     
        let request = JSON.parse(bodyStr);
     
        requestProcessor(request).then((response) => {
          sendResponse(res, response);
        });
      });
    }
     
    async function requestProcessor(request) {
      let response = { /* some props */ };
     
      try {
        response.result = await Promise.resolve(methods[request.method](request.params));
      } catch (err) {
        // hidden for brevity
      }
     
      return response;
    }
     
    const server = http.createServer(requestHandler);
    server.listen(port, (err) => {
      if(err) {
        return console.log(('something bad happened', err);
      }
      console.log((`server is listening on ${port}`);
    })

  2. #2
    Expert éminent sénior
    Avatar de Marco46
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2005
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2005
    Messages : 4 413
    Points : 19 609
    Points
    19 609
    Par défaut
    Si oui comment auriez-vous fait ?
    Je n'aurais pas utilisé this. L'usage de classe ici est tout aussi inutile. Tu verras c'est bien plus simple.
    Un problème avec Git ? Essayez la FAQ, sinon posez votre question sur le forum.



    "Toute personne croyant qu'une croissance exponentielle peut durer indéfiniment dans un monde fini est soit un fou, soit un économiste."
    Kenneth E. Boulding

    "Les richesses naturelles sont inépuisables, car, sans cela, nous ne les obtiendrions pas gratuitement. Ne pouvant être ni multipliées ni épuisées, elles ne sont pas l’objet des sciences économiques."
    Jean-Baptiste Say, Traité d'économie politique, 1803.

    "/home/earth is 102% full ... please delete anyone you can."
    Inconnu

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2013
    Messages
    65
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2013
    Messages : 65
    Points : 39
    Points
    39
    Par défaut
    D'accord,

    Dans quel(s) cas ca peut être utile d'utiliser des classes en JS ?

    J'ai refait tous les repos comme ci-dessous. Vois-tu quelque chose que je pourrai faire mieux ?
    ./db/repos/roles.js
    Code JAVASCRIPT : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    'use strict';
     
    var Database = null, pgp = null, Collections = null;
     
    async function add(params) {
      var query = pgp.helpers.insert(params.data, Collections.insert);
      if(params.return) query += " RETURNING *";
     
      return Database.any(query)
                      .then(data => { return data; })
                      .catch(ex => { throw new Error(ex); });
    }
     
    async function   getSingleRole(params) {
      const query = `Select * from Roles where roleId=${params.data.id}`;
     
      return Database.one(query)
              .then(data => { return data; })
              .catch(ex => { throw new Error(ex); });
    }
     
    async function toto(params) {
      return Database.shells.toto(params);
    }
     
    function createColumnsets() {
      let cs = {};
      // create all ColumnSet objects only once:
      if (!cs.insert) {
        const table = new pgp.helpers.TableName({table: 'roles', schema: 'public'});
     
        cs.insert = new pgp.helpers.ColumnSet(['name'], { table });
        cs.update = cs.insert.extend(['?roleId']);
      }
      return cs;
    }
     
    const expose = {
      'roles.insert': add,
      'roles.getById': getSingleRole
    }
     
    const RolesRepository = {
      expose,
      add: add,
      getSingleRole: getSingleRole
    };
     
    module.exports = (db) => {
      Database = db;
      pgp = db.$config.pgp;
      Collections = createColumnsets();
     
      return RolesRepository;
    }

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2013
    Messages
    65
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2013
    Messages : 65
    Points : 39
    Points
    39
    Par défaut Utilisation des classes obligatoire
    Je re-post pour corriger et donner la "vraie" solution.
    Après avoir avancé un peu plus il s'avère que l'utilisation des classes dans les repos est obligatoire sinon nous il y a un problème avec les transactions de pg-promise (problème qui bloque complétement l'API tant quelle n'est pas redemarrée...).

    1. ./db/repos/index.js require tout les fichiers
    2. ./db/index.js require le repos (chargement de tous les repos) dans la 'const repos'
      2.1 La librairie pg-promise permet "d'étendre" la base avec des repos, cet événement est appelé à l'initialization de l'appli et à chaque fois qu'on effectue une tâche/transaction
      2.2 Les taches/transactions utilisent des 'SAVEPOINT', je penses qu'utiliser 'new' permet d'éviter qu'un savepoint se retrouve dans un "mauvais contexte" et bloque la librairie


    ./db/index.js
    Code JAVASCRIPT : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    'use strict';
     
    const promise = require('bluebird');
     
    const repos = require('./repos');
    const config = require('./conf');
     
    // pg-promise initialization options:
    const initOptions = {
        promiseLib: promise,
        extend(obj, dc) {
            obj.systems = new repos.Systems(obj, pgp);
            obj.devices = new repos.Devices(obj, pgp);
        }
    };
     
    const pgp = require('pg-promise')(initOptions);
    const db = pgp(config);
     
    const methods = /* hidden for brevity */
     
    module.exports = {
      methods
    }

    ./db/repos/index.js
    Code JAVASCRIPT : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    'use strict';
     
    module.exports = {
      Systems: require('./systems'),
      Devices: require('./devices'),
    };

    ./db/repos/devices.js
    Code JAVASCRIPT : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    'use strict';
     
    class DevicesRepository {
      constructor(db, pgp) {
        this.Database = db;
        this.pgp = pgp;
     
        this.Collections = createColumnsets(pgp);
     
        this.expose = {
          'devices.insert': this.insertOne.bind(this),
          'devices.getById': this.getOne.bind(this)
        }
      }
     
      /* hidden for brevity */
     
      insertOne(params) {
        // this = DevicesRepository
        return this.Database.tx('Insert-New-Device', async t => {
          // this = t = pg-promise context
          let system = null, disks = null, cpus = null;
     
          const query = t.devices.makeInsertQuery(params.data.device) + " RETURNING *";
          let device = await t.one(query);
     
          if(params.data.system) {
            params.data.system.deviceid = device.deviceid;
            system = await t.systems.insertOne(params);
          }
     
          return {device, system, disks, cpus};
        })
        .catch(ex => {
          throw ex;
        });
      }
    }
     
    function createColumnsets(pgp) { /* hidden for brevity */ }
     
    module.exports = DevicesRepository

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [eXo Portal] Probleme avec les contextes
    Par yleny33 dans le forum Portails
    Réponses: 1
    Dernier message: 11/05/2009, 14h43
  2. problem avec context null
    Par Elise49 dans le forum Développement de jobs
    Réponses: 1
    Dernier message: 17/04/2009, 10h42
  3. un probleme de contexte avec tomcat 5.5
    Par saidgrd dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 11/04/2009, 14h09
  4. Réponses: 2
    Dernier message: 02/01/2007, 11h19
  5. [POO] Probleme avec $this
    Par cubepiege dans le forum Langage
    Réponses: 5
    Dernier message: 01/03/2006, 15h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo