Sequelize and Node.js: Issue with Module.Exports and Table Models - javascript

I am working on installing multiple databases in one server. To start this process, I am assigning one database in the index.js export object such that I will be able to add another DB as I build up the system. Below is the description of the issue.
When I run the server.js file, the .sync function for the database db1 syncs Table1 and Table2 and then begins listening on its port. Its clear the server.js file is receiving the module.exports = db through the var db = require('./models'). However in the file models/Table1.js the server throws an error TypeError: Cannot read property 'Table1' of undefined. I did check the console output for db in the models/Table1.js and it's empty, so its clear module.exports = db is not being accessed in this model.
Can someone provide a solution to correct this issue?
The partial code for the Table1.js model and other files listed above is below:
models/Table1.js
var db = require('./.')
[...]
var new_instance = db.db1.Table1.build({...})
server.js
var db = `require('./models')`
[...]
db.db1.sync(function(err) {});
models/index.js
var sq = new Sequelize(dbname, user, password, config);
db['db1'] = {
Sequelize: Sequelize,
sequelize: sq,
Table1: sq.import(__dirname + '/...'),
Table2: sq.import(__dirname + '/...')
}
module.exports = db;

The module.exports = db is being accessed, but you have created a cyclic dependency between models/index.js and models/Table1.js due to the fact that in the Table1.js model you require index.js file and in the index.js file you perform sequelize.import() call which performs require(path) to include the model definition, so in your case it calls require('./Table1.js') - there comes the cyclic dependency.
You should consider putting the var new_instance = db.db1.Table1.build({...}) somewhere else in order to avoid this situation. Files with model definitions should be only used to create the Model definitions, try to avoid performing additional operations.
Take a look at this question - How to deal with cyclic dependencies in Node.js to find out how you can deal with this kind of situations.
EDIT
According to your comment let's consider simple example with below structure
- script.js
- models
- index.js
- Table1.js
In script.js
var db = require('./models');
var new_instance = db.db1.Table1.build({...});
It can be done if you would not require the script.js inside any of the files placed inside models directory.

Related

What is exports.local used for in node.js

Exports.local Node js sample code
I am using passport-local-mongoose in my node js Application and I come across exports.local for passport authentication. I couldn't understand it function. Please check the image above
In your case here there is nothing special about local keyword, it is just the name of the variable that is used to export the passport local authentication strategy configuration, so you can call it in other files using require, so here in your example, you have this logic written in authenticate.js, so to use it in any other file you will have to call it using the following:
const { local } = require('./authenticate'); // identify the right path to authenticate.js
enter code here
The CommonJS (CJS) format is used in Node.js and uses require and module.exports to define dependencies and modules. The npm ecosystem is built upon this format. In your case exports.local creates a new module and export it for the use elsewhere.
Example
user.js
const getName = () => {
return 'Jim';
};
exports.getName = getName;
index.js
const user = require('./user');
console.log(`User: ${user.getName()}`);
Output
User: Jim

How to ensure valid dependency graph within my application architecture

tl;dr:
Is it possible to reinforce / guarantee (using a library or something else) that a .js file will only have access to a specific subset of modules?
For instance: If the .js file is on the folder /controllers it's only allowed to have access to specific global modules (ex: express) and import from specific folders (ex: ../repositories). Anything outside this list is not allowed
Rationale behind:
In a large project with many developers it is almost inevitable that someone will invade layers. For example: within an action of an MVC controller, access the database via db driver / SQL without going through a repository or a more sofisticated abstraction.
const express = require('express');
const router = express.Router();
const pg = require('pg');
const path = require('path');
const connectionString = process.env.DATABASE_URL;
router.get('/api/v1/todos', (req, res, next) => {
const results = [];
pg.connect(connectionString, (err, client, done) => {
const query = client.query('SELECT * FROM items ORDER BY id ASC;');
query.on('row', (row) => { results.push(row); });
query.on('end', () => {
done();
return res.json(results);
});
});
});
This very basic example, just to illustrate the problem. In fact, in a multi layered / multi modules system, things are actually a bit more complicated and it's quite common to see invalid dependency graphs appearing as the project grows.
I know that part of the problem is solved with team training, but I wonder if there is any way to systematically reinforce this. Maybe something close to no-restricted-imports or no-restricted-modules on ESLint.
edit:
ESLint references.

How to make object references available in Node modules?

I have an Express.js web app. In the main app.js file, I require() a bunch of third party dependencies. Recently I've started extracting parts of my app.js code into separate modules, e.g.
// in app.js
var users = require('./modules/users');
// and then e.g.
// users.add(doc);
Inside my modules, I sometimes need to use objects that are available in my main app.js file and I'm wondering what's the best way to pass references to those object to my modules.
My current approach:
// in app.js
// pass needed object references in initialization step
users.init([db, logger]);
and
// in modules/users.js
var db, logger;
exports.init = function (deps) {
db = deps[0];
logger = deps[1];
};
Does this approach make sense? Is there a better way to perform this?
Sure, just use modules! :)
// db.js
// create db instance here rather than in app.js
module.exports = db;
And
// logger.js
// create logger instance here rather than in app.js
module.exports = logger;
Then
// app.js
var db = require('./db');
And
// lib/somewhere.js
var db = require('../db');
This way you're able to rely on the CommonJS dependency injection system rather than on doing the dependency injection all by yourself (passing references around instead of requireing a module into yours).
The reason why this works as expected is that modules are only interpreted once, so if you instantiate everything once as opposed to using a factory function, it just works.
You should just be able to require modules as normal:
// users.js
var db = require('./db');
exports.init = function() {
// use db in here
};
However, sometimes this isn't possible and you will need to explicitly pass in the module.
One way to do it is to pass in dependencies when you require the module:
// users.js
module.exports = function(db, logger) {
return {
init: function() { /* use db and logger in here */}
};
}
// app.js
var db = ...;
var logger = ...;
var users = require('./users')(db, logger);
users.init();
This is the pattern that I personally prefer, I think it's cleaner to pass dependencies into the require than into some init method like you have in your example.
You'll see this done in ExpressJS code quite a lot, for example when we have all our routes in another file and need to pass our app instance around:
require('./routes')(app);
If you need something to be initialized specifically in app.js rather than their own module you can export them from app.js and then require app.js:
// app.js
var db = require("db"),
logger = require("logger");
// do your initialization with db and logger
module.exports = { db: db, logger: logger };
and then:
// users.js
var db = require("./app").db,
logger = require("./app").logger;
// use db and logger
This works because as #Nico mentioned, modules are interpreted once and app.js will not be interpreted each time it is required from elsewhere.

How to loop through model files and initialize all of them?

I'm using Mongoose with MongoDb and I'm having trouble figuring out the Javascript code to run all my Mongoose models (one model in each file inside a directory) and initialize all of them.
Basically my file structure is like this:
models
-- User.js
-- Discussion.js
-- Node.js
-- etc.js
index.js
I need an initialize function inside index.js that will run each of the functions in the models. Any ideas?
Were you thinking about something like this? This will include all the files inside models and then run the module.exports function for each of them. This will essentially initialize all your models.
(index.js)
exports.initialize = function() {
require("fs").readdirSync(__dirname + "/models").forEach(function(file) {
require('./models/' + file)();
});
};

Change current folder in Node.js

I have a file fetching some other files:
start.js
require("./users");
but the users.js file is not in the current folder but in model/.
I want to be able to run:
node start.js model
and it would assume that ./ is the same as model/ in start.js.
How do I do that?
All you need to do is to make Node.js recognize the folder model as a module.
In order to do that, you need to place a file called index.js inside the model folder.
// model/index.js
exports.users = require('./users'); // model/users.js
exports.posts = require('./posts'); // model/posts.js
// etc.
Now you can import the model module and access it's exports:
var models = require('./model');
models.users.create(); // some function exported in model/users.js
models.posts.list(); // this was exported in model/posts.js
You can add ./model dir to require.paths array:
require.paths.unshift("./model");
var
users = require("users"), // It works!
posts = require("posts");
But I want to ask you: why do you need this instead of using
var
users = require("./model/users"), // It works!
posts = require("./model/posts");
?

Categories

Resources