Separate sequelize models in separate folders and join all together - javascript

I have a complicated task to do. I need to separate my sequelize models in separate folders inside the models folder, just like this structure:
├── node_modules
├── src
| └── models
| ├──settings
| | ├── user.js
| | └── location.js
| ├──stock
| | ├── stock.js
| | └── products.js
| └── index.js
Today, I have all models in models root folder, together with index.js, in a way that I can call every model from controllers as
const { users, stock } = require("../../models")
The code inside index.js is like this:
"use strict"
const fs = require("fs")
const path = require("path")
const Sequelize = require("sequelize")
const basename = path.basename(__filename)
const env = process.env.NODE_ENV || "development"
const envConfigs = require("../config/config")
const config = envConfigs[env]
const db = {}
let sequelize
if (config.url) {
sequelize = new Sequelize(config.url, config)
} else {
sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
)
}
fs.readdirSync(__dirname)
.filter((file) => {
return (
file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js"
)
})
.forEach((file) => {
const model = require(path.join(__dirname, file))(
sequelize,
Sequelize.DataTypes
)
db[model.name] = model
})
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db)
}
})
db.sequelize = sequelize
module.exports = db
This was automaticly created using sequelize-cli.
I think that I need some search inside index.js and concatenate folders and files into Model variable inside index.js, in such a way that I can use the models like "model.settings.user" to do associations or calling the objects in controllers.

Finally, I was able to get the index.js working properly! This is the code for anyone that need it (having this code in the index.js, it will search in all folders and put all models name files into const "model"
"use strict"
const fs = require("fs")
const path = require("path")
const Sequelize = require("sequelize")
const basename = path.basename(__filename)
const env = process.env.NODE_ENV || "development"
const envConfigs = require("../config/config")
const config = envConfigs[env]
const db = {}
let sequelize
if (config.url) {
sequelize = new Sequelize(config.url, config)
} else {
sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
)
}
const files = []
const sortDir = (maniDir) => {
const folders = []
const CheckFile = (filePath) => fs.statSync(filePath).isFile()
const sortPath = (dir) => {
fs.readdirSync(dir)
.filter((file) => file.indexOf(".") !== 0 && file !== "index.js")
.forEach((res) => {
const filePath = path.join(dir, res)
if (CheckFile(filePath)) {
files.push(filePath)
} else {
folders.push(filePath)
}
})
}
folders.push(maniDir)
let i = 0
do {
sortPath(folders[i])
i += 1
} while (i < folders.length)
}
sortDir(__dirname)
files.forEach((file) => {
const model = require(file)(sequelize, Sequelize.DataTypes)
db[model.name] = model
})
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db)
}
})
db.sequelize = sequelize
module.exports = db

Related

const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes) - TypeError: require(...) is not a function

I am beginner in web dev and trying to create a project using Mysql, Node.js with Express. Facing this TypeError issue while using Sequalize. Can someone please explain it to me and help me find a solution?
"sequelize": "^6.19.0"
"sequelize-cli": "^6.4.1"
/models/user.js:
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define('User', {
name: DataTypes.STRING,
username: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING,
});
return user;
};
/models/index.js:
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(`${__dirname}/../../config/config.js`)[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter((file) => (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'))
.forEach((file) => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
error:
[nodemon] starting `node ./src/api/server.js`
/home/back-end/src/models/index.js:25
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
^
TypeError: require(...) is not a function
at /home/back-end/src/models/index.js:25:54
at Array.forEach (<anonymous>)
at Object.<anonymous> (/home/back-end/src/models/index.js:24:4)
at Module._compile (internal/modules/cjs/loader.js:1068:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1097:10)
at Module.load (internal/modules/cjs/loader.js:933:32)
at Function.Module._load (internal/modules/cjs/loader.js:774:14)
at Module.require (internal/modules/cjs/loader.js:957:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Object.<anonymous> (/home/back-end/src/services/usersService.js:1:18)
[nodemon] app crashed - waiting for file changes before starting...
From experience, I encountered this after I added a file that is not a model in the 'models' directory. Supposedly one can only add model files to the 'models' directory, as index.js checks every file in the whole directory.
I have actually been struggling with this problem for a while now. What worked for me is that I used the ES6 class referred to as (extend Model in the Sequelize documentation) to create my table instead of the (Sequelize.define). I am honestly still not sure why, but you can find how to create a table in sequelize with the Extend Model in the Sequelize documentation.
In your index.js file, You should just use this format and it will solve your error
const fs = require('fs')
const path = require('path')
const Sequelize = require('sequelize')
const config = require('../config/config')
const db = {}
const sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
);
fs
.readFileSync(__dirname)
.filter((file) =>
file !== 'index.js'
)
.forEach((file) => {
const model = require(path.join(__dirname, file))(sequelize,Sequelize.DataTypes)
db[model.name] = model
})
db.sequelize = sequelize
db.Sequelize = Sequelize
module.exports = db

How do you dynamically module.export all files in a folder?

I'm trying to dynamically export modules. I'm close but can't figure out how to fix my syntax.
Hard coded:
// index.js inside folder 'models'
const { User } = require('./User');
const { Token } = require('./Token');
const { Session } = require('./Session');
module.exports = {
User,
Token,
Session,
};
Dynamically coded (doesn't work):
// index.js inside folder 'models'
const fs = require('fs');
const path = require('path');
module.exports = () => {
fs.readdirSync(__dirname).forEach((file) => {
if (file === 'index.js') return false;
const fullName = path.join(__dirname, file);
if (file.toLowerCase().indexOf('.js')) {
// I think this somehow needs to be destructured like
// `return {require(fullName)}` or
// `require(fullName)[fullName]` I think
require(fullName);
}
});
};
Elsewhere in my code, I initialize it based on the folder name:
// server.js
require('./models')();
Your dynamic export will not work because you are not returning anything to the exported function.
Try this code as your dynamic model export file
// index.js inside folder 'models'
const fs = require('fs')
const path = require('path')
const models = {}
fs.readdirSync(__dirname)
.filter(file => file !== 'index.js')
.forEach(file => {
const fullName = path.join(__dirname, file)
if (file.toLowerCase().endsWith('.js')) {
// Removes '.js' from the property name in 'models' object
const [filename] = file.split('.')
models[filename] = require(fullName)[filename]
}
})
module.exports = models
This approach no longer exports a function so your require in server.js should now look like this
// server.js
require('./models');

AuthenticationController always throws error, TypeError: Cannot read property 'create' of undefined

I have an issue with the Authenticati onController used with sequelize and sqlite
When I test the POST request using postman, it always gives status 400 with the response
{
error: 'Something is wrong'
}
This is the log
::1 - - [21/Jul/2020:15:40:33 +0000] "POST /register HTTP/1.1" 400 30 "-" "PostmanRuntime/7.26.1"
Here is the code of AuthenticationController
const {User} = require('../models')
module.exports = {
async register(req, res){
try {
const user = await User.create(req.body)
res.send(user.toJSON())
} catch (error) {
console.log(error)
res.status(400).send({
error: 'Something is wrong'
})
}
}
}
User model code
module.exports = (sequelize, DataTypes) =>
sequelize.define('User', {
email: {
type: DataTypes.STRING,
unique: true
},
password: DataTypes.STRING
})
models index code
const fs = require('fs')
const path = require('path')
const Sequelize = require('sequelize')
const config = require('../config/config')
const db = {}
const sequelize = new Sequelize(
config.db.database,
config.db.user,
config.db.password,
config.db.options
)
fs
.readdirSync(__dirname)
.filter((file)=>{
file != 'index.js'
})
.forEach((file)=>{
const model = require(path.join(__dirname, file))(
sequelize,
Sequelize.DataTypes
);
// const model = sequelize.import(path.join(__dirname,file))
db[model.name] = model
})
db.sequelize = sequelize
db.Sequelize = Sequelize
module.exports = db
routes code
const AuthenticationController = require('./controllers/AuthenticationController');
module.exports = (app) => {
app.post('/register',
AuthenticationController.register)
}
Earlier, it was throwing an error of "TypeError: Cannot read property 'create' of undefined"
But when I restarted the server, that was fixed. But I have no clues as to why the try block fails.
Anyone could throw some light on this? Thank you
Here is the revised code for /models/index.js
const fs = require('fs')
const path = require('path')
const Sequelize = require('sequelize')
const config = require('../config/config')
const db = {}
const sequelize = new Sequelize(
config.db.database,
config.db.user,
config.db.password,
config.db.options
)
fs.readdirSync(__dirname)
// .filter((file) => {
// file != "index.js";
// })
.filter(
(file) =>
file.indexOf(".") !== 0 && file !== "index.js" && file.slice(-3) === ".js"
)
.forEach((file) => {
const model = require(path.join(__dirname, file))(
sequelize,
Sequelize.DataTypes
);
// const model = sequelize.import(path.join(__dirname,file))
db[model.name] = model;
});
db.sequelize = sequelize
db.Sequelize = Sequelize
module.exports = db
The filter block was updated as shown in the revised, with the help of the link
https://www.codota.com/code/javascript/functions/sequelize/Sequelize/import
The 2 things that were changed are
Replaced the 'sequelize.import' with 'require'
Updated the 'filter' block as shown.
Here is the result:
Thanks to crumkev for the insight which led me find the answer.

Apollo/Express server is not working in nx.dev environment

I'm trying to create a simple graphql backend using apollo-server-express.
Doing this in a expressJS application (Github repo) is working as expected:
Executing the query
query {
search {
result
}
}
at localhost:4000/graphql returns result as expected.
resolver
module.exports = {
Query: {
search: async (obj, { name, value }) => {
return 'result'
}
}
}
Now I would like to use this expressJS backend in a nx.dev environment (Github repo). I set up the same thing here, but running the server and executing the query in the graphQL playground returns null.
I don't see what is going wrong.
This is my structure:
main.ts
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const typeDefs = require('./graphql/types')
const resolvers = require('./graphql/resolvers')
const app = express();
const server = new ApolloServer({ typeDefs, resolvers });
server.applyMiddleware({ app });
app.listen({ port: 4000 }, () =>
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
)
structure
+-- graphql
| +-- author
| | +-- author.resolvers.js
| | +-- author.graphql
| +-- search
| | +-- search.resolvers.js
| | +-- search.graphql
| +-- resolvers.js <<< Merges all `*.resolvers.*` files
| +-- types.js <<< Merges all `*.graphql` files
resolvers.js
const path = require('path');
const { mergeResolvers } = require('#graphql-tools/merge');
const { loadFilesSync } = require('#graphql-tools/load-files');
const resolversArray = loadFilesSync(path.join(__dirname, "./**/*.resolvers.*"));
module.exports = mergeResolvers(resolversArray);
types.js
const path = require('path');
const { loadFilesSync } = require('#graphql-tools/load-files');
const { mergeTypeDefs } = require('#graphql-tools/merge');
const typesArray = loadFilesSync(path.join(__dirname, './**/*.graphql'))
module.exports = mergeTypeDefs(typesArray, { all: true })
graphql/search/search.graphql
type Query {
search(name: String, value: String): [String]
}
graphql/search/search.resolvers.js
module.exports = {
Query: {
search: async (obj, { name, value }) => {
return 'result'
}
}
}

How do I require something from index.js in the same directory?

I have the following file structure:
models/
index.js
something.js
user.js
In index.js (this is generated by Sequalize and importing stuff from here works in other directories):
'use strict';
var fs = require('fs');
var path = require('path');
var Sequelize = require('sequelize');
var basename = path.basename(module.filename);
var env = process.env.NODE_ENV || 'development';
var config = require(__dirname + '/../config/config')[env];
var db = {};
if (config.use_env_variable) {
var sequelize = new Sequelize(process.env[config.use_env_variable]);
} else {
var sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(function(file) {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(function(file) {
var model = sequelize['import'](path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(function(modelName) {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db; // <<< I want to import that in something.js
user.js:
'use strict';
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
username: { type: DataTypes.STRING, allowNull: false, unique: true },
password: { type: DataTypes.STRING, allowNull: false },
}, {
classMethods: {
associate() {},
},
});
return User;
};
something.js:
'use strict';
// this all logs an empty object
console.log(require('./index'));
console.log(require('.'));
console.log(require('./'));
console.log(require('../models'));
console.log(require('../models/'));
console.log(require('../models/index'));
module.exports = (sequelize, DataTypes) => {
const Something = sequelize.define('Something', {
name: DataTypes.STRING,
}, {
classMethods: {
associate(models) {
},
},
});
return Something;
};
If I require db from files in other directories it works so I guess it's not a problem with exporting.
How can I require db in something.js so it's not undefined?
const neededStuff = require('./'); // the best
or:
const neededStuff = require('./index');
or:
const neededStuff = require('../models/');
Turns out it was a circular dependency. index.js was importing stuff from something.js and then I tried to import index.js in something.js.
If module A requires('B') before it has finished setting up it's exports, and then module B requires('A'), it will get back an empty object instead what A may have intended to export.
http://selfcontained.us/2012/05/08/node-js-circular-dependencies/
But you can use methods from another model in sequelize with sequelize.models.Something.

Categories

Resources