precursor Δημοσ. 21 Απριλίου 2019 Μέλος Δημοσ. 21 Απριλίου 2019 2 ώρες πριν, ajaxmonkey4hire είπε Ναι. Αν θέλεις να το χρησιμοποιείς και από άλλα modules μπορείς να κάνεις το εξής: 'use strict' const mongodb = require('mongodb'); const MongoClient = mongodb.MongoClient; var mongo; class Mongo{ constructor(server){ this.server = server; this.client = null; } connect(cb, opts){ opts = opts||{poolSize: 10, autoReconnect:true, useNewUrlParser: true}; MongoClient.connect(this.server, opts, (e, dbClient)=>{ this.client = e?null:dbClient; cb(e, this.client); }); } use(cb, dbName){ if (cb){ if (this.client&&this.client.isConnected()){ cb(this.client.db(dbName)); }else{ this.connect((e, client)=>{ cb(e?null:client.db(dbName)); }); } } } } module.exports.getMongoDb = function(server){ mongo = mongo||new Mongo(server); return mongo; } κάνεις ένα require εκεί που θέλεις να το χρησιμοποιήσεις και καλείς το getMongoDb('το σερβερ σου') αν υπάρχει το mongo σου το επιστρέφει ειδάλλως καλεί το constructor, το φτιάχνει και μετά σου το επιστρέφει. Αυτό είναι αρκετά κοντά σε αυτό που προσπαθώ να πετύχω, ωστόσο επειδή θα ήθελα να αποφύγω να χαλάσω τη δομή που ακολουθώ για όλα τα modules, και πιο συγκεκριμένα να έχω μόνο μεταβλητές έξω από την κλάση που έχουν να κάνουν με τα imports (δηλ. ό,τι κάνω require), όπως τα δύο πρώτα constants που έχεις βάλει (αλλά όχι και την var mongo), και να έχω μόνο ένα απλό module.exports = TheClass; που να κάνει export την ίδια την κλάση... ... θέλω να σε ρωτήσω αν υπάρχει τρόπος να γίνεται εσωτερικά στην κλάση με κάποια μέθοδο, κάποιον getter ίσως; Με static get ίσως; Και αν δεν είναι εφικτό κάτι τέτοιο, τότε έτσι όπως έχεις το module.exports γίνεται να κάνει από default export την κλάση, και με διαφορετικό τρόπο (π.χ. getMongoDb) να κάνει export το function(server); ώστε στο αρχικό module (bootstrap) που κάνω τη σύνδεση να μπορώ να κάνω τα εξής: const Database = require("../core/database"); // ... const db = new Database("..."); db.connect("..."); και σε όλα τα υπόλοιπα modules να κάνω το εξής: const db = require("../core/database").getDb; db.someMethod();
PC_MAGAS Δημοσ. 21 Απριλίου 2019 Δημοσ. 21 Απριλίου 2019 9 ώρες πριν, precursor είπε @PC_MAGAS επειδή με μπερδεύουν όλα αυτά περί mongoDB ας το προσεγγίσουμε με τον δικό μου κώδικα (για να καταλάβω καλύτερα τι θα αλλάξω/προσθέσω). Συγνώμη για το πρήξιμο 😳 Για να συμπληρωθεί η όλη εικόνα, η κλάση Database όπως την περιγράψαμε: "use strict"; const Sequelize = require("sequelize"); class Database { constructor(...) { } connect(DB_DIALECT, DB_USERNAME, DB_PASSWORD, DB_HOST, DB_PORT, DB_NAME) { this.sequelize = new Sequelize(DB_DIALECT + "://" + DB_USERNAME + ":" + DB_PASSWORD + "@" + DB_HOST + ":" + DB_PORT + "/" + DB_NAME, { operatorsAliases: false, logging: false, define: { charset: 'utf8' } }); // Successful connection or not? this.sequelize.authenticate().then(() => { console.log("Successfully connected to the database."); }).catch((err) => { console.log("Unable to connect to the database: " + err); }); } // CRUD } module.exports = Database; Οπότε που πρέπει να "κουμπώσω" και τι για να είναι προσβάσιμο από όλα τα controllers (και συνεπώς και από models) το Database object που έκανε το connection 🤔 Όπως το περιγράφεις στο Bootstrap κούμπωσε τo new Database() και μετά πέρνα το instance σαν Depedency στον constructor κάθε Object. Μετά εντός του class Database τοποθέτησε μια μέθοδο Use που θα παίρνει σαν όρισμα μια callback και μέσω callback θα λαμβάνει το error στο πρώτο όρισμα αυτής και σαν δεύτερο όρισμα το this.sequelize . 1
ajaxmonkey4hire Δημοσ. 21 Απριλίου 2019 Δημοσ. 21 Απριλίου 2019 10 ώρες πριν, precursor είπε Αυτό είναι αρκετά κοντά σε αυτό που προσπαθώ να πετύχω, ωστόσο επειδή θα ήθελα να αποφύγω να χαλάσω τη δομή που ακολουθώ για όλα τα modules, και πιο συγκεκριμένα να έχω μόνο μεταβλητές έξω από την κλάση που έχουν να κάνουν με τα imports (δηλ. ό,τι κάνω require), όπως τα δύο πρώτα constants που έχεις βάλει (αλλά όχι και την var mongo), και να έχω μόνο ένα απλό module.exports = TheClass; που να κάνει export την ίδια την κλάση... ... θέλω να σε ρωτήσω αν υπάρχει τρόπος να γίνεται εσωτερικά στην κλάση με κάποια μέθοδο, κάποιον getter ίσως; Με static get ίσως; Και αν δεν είναι εφικτό κάτι τέτοιο, τότε έτσι όπως έχεις το module.exports γίνεται να κάνει από default export την κλάση, και με διαφορετικό τρόπο (π.χ. getMongoDb) να κάνει export το function(server); ώστε στο αρχικό module (bootstrap) που κάνω τη σύνδεση να μπορώ να κάνω τα εξής: const Database = require("../core/database"); // ... const db = new Database("..."); db.connect("..."); και σε όλα τα υπόλοιπα modules να κάνω το εξής: const db = require("../core/database").getDb; db.someMethod(); Την var mongo έξω από την class δεν μπορείς να την αποφύγεις αν θέλεις να χρησιμοποιησης την ίδια instance από διαφορετικά modules. Μπορείς να έχεις πολλαπλα exports άλλα όχι και default με αυτά. 1
ajaxmonkey4hire Δημοσ. 21 Απριλίου 2019 Δημοσ. 21 Απριλίου 2019 Στις 20/4/2019 στις 5:21 ΠΜ, precursor είπε Καλησπέρα Θα ήθελα τη βοήθειά σας επειδή όσο και αν ψάχνω στο Google δεν έχω καταφέρει κάτι. Φτιάχνω ένα web app σε Node.js και χρησιμοποιώ το Sequelize ORM για να συνδεθώ στη βάση δεδομένων (PostgreSQL, αν και δεν έχει ιδιαίτερη σημασία αυτό). Το φτιάχνω με αρχιτεκτονική MVC και επειδή είμαι συνηθισμένος στις κλάσεις (από Java και C#) και μπερδεύομαι εύκολα με κώδικα χωρίς κλάσεις, θέλω τα πάντα να είναι αυστηρά μέσα σε κλάσεις! Δηλαδή κάθε module (δηλ. αρχείο .js) να έχει πάνω-πάνω τα requires του μετά να ακολουθεί όλος ο κώδικας μέσα σε class Example {...} και τέλος ένα module.exports = Example; Το πρόβλημα είναι ότι δεν μπορώ σχεδόν ποτέ να βρω ολοκληρωμένα παραδείγματα με κλάσεις - πάντα κάτι θα λείπει ή θα υπάρχει σπαγγέτι κώδικας και μπερδεύομαι και δεν μπορώ να ενώσω τα κομμάτια... Αν κάποιος γνωρίζει λοιπόν, θα ήθελα οδηγίες για να πετύχω το εξής: "use strict"; const Sequelize = require("sequelize"); class Database { constructor() { } ... } module.exports = Database; 1) Πού και πώς πρέπει να βάλω το db = new Sequelize(...); ώστε να έχω μόνο ένα instance και δηλ. μόνο μία σύνδεση με τη βάση δεδομένων και να μην καταλήγω να κάνω new σύνδεση σε κάθε request;;; 2) Και πέρα από την κλάση Database, στις υπόλοιπες κλάσεις πώς καλώ και παίρνω το db (διατηρώντας φυσικά μία σύνδεση);;; Υπόψη ότι όλες οι υπόλοιπες κλάσεις θα έχουν την ίδια μορφή. Σκεφτόμουν αρχικά μήπως έβαζα το new Sequelize μέσα σε μια μέθοδο static get db() αλλά μετά κατάλαβα ότι έτσι θα κάνω νέα σύνδεση κάθε φορά που καλώ την Database.db 3) Τέλος, όσον αφορά τις ρυθμίσεις options που βάζω μέσα στο new Sequelize, με λίγα λόγια τι κάνουν τα min, max και acquire του pool π.χ. αν περιμένω να έχω 1000 users online τι πρέπει να προσέξω για να έχω αρκετά διαθέσιμα connections; Αναρωτιέμαι για ποιον λόγο φτιάχνεις την wrapper class. Προσωπικά την χρησιμοποιώ στην mongo για δυο λόγους: 1. Αποφεύγω τα πολλαπλα connect που κοστίζουν χρόνο 2. Κάνω query result caching μέσα στην wrapper class Και τα δυο κάνουν την εφαρμογή πιο γρήγορη και ικανοποιούν the need for speed. Το "στύλε" είναι, για έμενα, δευτερεύουσας σημασίας. Προτιμώ πάντα αυτό που δινει την καλύτερη performance και ας μην είναι πάντα το "ομορφότερο"
precursor Δημοσ. 21 Απριλίου 2019 Μέλος Δημοσ. 21 Απριλίου 2019 1 ώρα πριν, ajaxmonkey4hire είπε Την var mongo έξω από την class δεν μπορείς να την αποφύγεις αν θέλεις να χρησιμοποιησης την ίδια instance από διαφορετικά modules. Μπορείς να έχεις πολλαπλα exports άλλα όχι και default με αυτά. Μπορώ τουλάχιστον με πολλαπλά exports - με δύο συγκεκριμένα - με το ένα να παίρνω την κλάση και με το άλλο το function που επιστρέφει το instance; Δηλαδή να μπορώ να κάνω require("../core/database").getClass και require("../core/database").getDb ; 3 λεπτά πριν, ajaxmonkey4hire είπε Αναρωτιέμαι για ποιον λόγο φτιάχνεις την wrapper class. Χάνομαι εύκολα στον κώδικα και πονοκεφαλιάζω (ειδικά όταν επιστρέφω σε κάτι που έφτιαξα μετά από καιρό) αν δεν τον βλέπω με κλάσεις... ¯\_(ツ)_/¯ 7 ώρες πριν, PC_MAGAS είπε Μετά εντός του class Database τοποθέτησε μια μέθοδο Use που θα παίρνει σαν όρισμα μια callback και μέσω callback θα λαμβάνει το error στο πρώτο όρισμα αυτής και σαν δεύτερο όρισμα το this.sequelize . Δηλαδή κάπως έτσι; // Το use που είχες βάλει με τις αλλαγές που μου είπες (αν το έκανα σωστά) use(cb) { if(!this.sequelize){ return cb(err); } cb(null,this.sequelize); } // Ένα ακόμα use του ajaxmonkey4hire use(cb, dbName){ if (cb){ if (this.client && this.client.isConnected()){ cb(this.client.db(dbName)); } else { this.connect((e, client)=>{ cb(e?null:client.db(dbName)); }); } } } Με τη μέθοδο use, απ' ό,τι καταλαβαίνω, μπορώ να βλέπω αν υπάρχει σύνδεση στη βάση, αν δεν υπάρχει να λαμβάνω error και αν υπάρχει να λαμβάνω το this.sequelize handler σωστά; Και αν θέλω κάνω και επανασύνδεση αντί να βγάλω ένα σκέτο error. Σωστά όλα αυτά; Θα σου πω ψέματα όμως αν πω ότι κατάλαβα πώς θα είναι αυτό το callback που θα πρέπει να περάσω αν και έχω μια μικρή ιδέα: https://stackoverflow.com/questions/31780872/what-is-cb-in-node Δεν μπορώ αντί για την use να βάλω κάποιον getter; set sequelize(object) { this._sequelize = object; } get sequelize() { // if no error return this._sequelize; // else errors, reconnect etc. } 7 ώρες πριν, PC_MAGAS είπε Όπως το περιγράφεις στο Bootstrap κούμπωσε τo new Database() και μετά πέρνα το instance σαν Depedency στον constructor κάθε Object. Οκ. Κάτι ακόμα πάνω σε αυτό. Ο Express μου δίνει τη δυνατότητα να περνάω μεταβλητές στο response object με το res.locals. Μιας και στον constructor του κάθε controller περνάω τα res, req και next και μιας και θα ήθελα να αποφύγω να περάσω και το instance ή περισσότερα arguments... ... θα ήταν καλή ιδέα να βάλω το instance στο res.locals ή όχι; Δηλαδή: res.locals.db = db; Bootstrap.loadController(req, res, next); Σας ευχαριστώ πολύ για τη βοήθεια
PC_MAGAS Δημοσ. 21 Απριλίου 2019 Δημοσ. 21 Απριλίου 2019 50 λεπτά πριν, precursor είπε Δεν μπορώ αντί για την use να βάλω κάποιον getter; Well υποθέσαμε ότι το connection είναι ασύγχρονο έτσι δεν θα μπορείς να παίζεις εύκολα μπάλα με getter και setter. Βάση του Documentation http://docs.sequelizejs.com/manual/usage.html getter και setter μπορείς να παίξεις λόγο ότι η function για τα queries είναι promices. Από την άλλη έχω απορία η προσεγγίσεις μας πως θα γίνουν ευκόλως unit testable. Ακόμη εύκολα γλιτώνεις το callback hell κάπως έτσι πχ. έστω ο κώδικας: const someObjWithCallbackFunc= new SomeObj(); someObjWithCallbackFunc.functionWithCallbackAsParameter((err,params)=>{ //Doing stuff }); Στον κώδικα: const maFunction=(err,params)=>{ //Doing stuff }; const someObjWithCallbackFunc= new SomeObj(); someObjWithCallbackFunc.functionWithCallbackAsParameter(maFunction); Δηλαδή κάνε τις functions σου από ανώνυμες, well όσο ποιο επώνυμες είναι δυνατόν. Ακόμα φρόντισε οι function/μέθοδοι να είναι όσο ποιο "αυτόνομες" δυνατόν περνώντας σαν παράμετρο ότι χρειάζεται. Δηλαδή να σκέφτεσαι κάθε λογικό module σαν ένα αυτόνομο κομμάτι που ότι τρίτο παίρνει θα το παίρνει μέσω παραμέτρων, έτσι θα γίνετε πιο εύκολο προς αυτοματοποιημένο test (unit test).
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα