Sequelize association functions not available - IntellIj issue - javascript

Update
This morning I wanted to use another inbuilt sequelize function and suddenly the belongsTo() and hasMany() functions were available and working on some models -not all! These models have all exactly the same pattern and only differ in name.
For example hasOne is not available for topicClass
I didn't change anything else. Except I restarted intelliJ. I did restart it before I opened this question and always had the same issue. So I think this issue is IDE based! Still would appreciate a tip how to avoid this
I have an APP using sequelize with SQLite.
When I want to setup the associations in my db-controller.js it tells me that the association functions like belongsTo and hasmany from the docu are not available.
When I execute the setupAssociations function and check the db later there are the models but no associations set.
Here the db-controller.js (more info from my side after the models at the bottom!)
const Sequelize = require('sequelize')
const userModel = require('../model/user')
const subjectModel = require('../model/subject')
// eslint-disable-next-line no-unused-vars
const initUser = userModel.user.initUser()
// eslint-disable-next-line no-unused-vars
const initSubject = subjectModel.subject.initSubject()
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: './user.sqlite',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
logging: false
})
sequelize.sync()
function setupAssociations(){
// user + subject
userModel.user.userClass.hasMany(subjectModel.subject.subjectClass)
subjectModel.subject.subjectClass.belongsTo(userModel.user.userClass)
// subject + topic
}
function testAssociations(){
setupAssociations()
}
testAssociations()
and my two models
const Sequelize = require('sequelize')
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: '../controller/user.sqlite',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
logging: false
})
sequelize.sync()
/**
* User Model
*/
class User extends Sequelize.Model {
}
/**
* Init user model
*/
function initUser () {
//TODO optional realize with sequelize.transaction
User.init(
// attributes
{
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.STRING,
allowNull: false
},
title: {
type: Sequelize.STRING,
allowNull: false
},
password: {
type: Sequelize.TEXT,
allowNull: false
}
},
// options
{
sequelize,
modelName: 'user'
}
)
}
/**
* Makes functions available globally
*/
exports.user = {
initUser: initUser,
userClass: User
}
and Subject
const Sequelize = require('sequelize')
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: '../controller/user.sqlite',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
logging: false
})
sequelize.sync()
/**
// * Subject Model
*/
class Subject extends Sequelize.Model {
}
/**
* Initialises subject model
*/
function initSubject () {
Subject.init(
// attributes
{
subjectName: {
type: Sequelize.STRING,
allowNull: false
}
},
// options
{
sequelize,
modelName: 'subject'
}
)
}
/**
* Makes functions globally available
*/
exports.subject = {
initSubject: initSubject,
subjectClass: Subject
}
If I create another class like class TestClass extends Sequelize.Model in the user.js file and call hasMany with belongsTo within the initUser function and check the db after, then everything is as I want it to.
So what I do here wrong please?

I figured out that I had from another project a script running adding to the comment of the export function
#type {{initTopic: (function(): Promise<*>), topicClass: Topic}}
This caused the issue. Removing it made all sequelize functions appearing again.

Related

SQLError: Table 'Projeto_EP.categoria' doesn't exist

I'm trying to build an API using node.js, with sequelize as ORM.
I'm having a problem with the model.create (controller Categoria) of classes that have relationships.
These are the migrations:
migration 'categorias':
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('categorias', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
nome: {
type: Sequelize.STRING,
},
created_at: {
allowNull: false,
type: Sequelize.DATE,
},
updated_at: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('categorias');
},
};
migration 'ensaios':
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('ensaios', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
idCategoria: {
type: Sequelize.INTEGER,
allowNull: false,
references: { model: 'categorias', key: 'id' },
},
nome: {
type: Sequelize.STRING,
},
created_at: {
allowNull: false,
type: Sequelize.DATE,
},
updated_at: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('ensaios');
},
};
These are the corresponding models:
model 'Categoria':
import Sequelize, { Model } from 'sequelize';
export default class Categoria extends Model {
static init(sequelize) {
super.init({
nome: Sequelize.STRING,
}, {
sequelize,
});
}
static associate(models) {
Categoria.hasMany(models.Ensaio, { foreignKey: 'idCategoria' });
}
}
model 'Ensaio':
import Sequelize, { Model } from 'sequelize';
export default class Ensaio extends Model {
static init(sequelize) {
super.init({
nome: Sequelize.STRING,
}, {
sequelize,
});
}
static associate(models) {
Ensaio.belongsTo(models.Categoria, { foreignKey: 'idCategoria' });
}
}
My app.js:
import dotenv from 'dotenv';
dotenv.config();
import express from 'express';
import categoria from './src/routes/categoria';
import './src/database';
class App {
constructor() {
this.app = express();
this.middlewares();
this.routes();
}
middlewares() {
this.app.use(express.urlencoded({ extended: true }));
this.app.use(express.json());
}
routes() {
this.app.use('/', categoria);
}
}
export default new App().app;
The route 'categoria':
import { Router } from 'express';
import Categoria from '../controllers/Categoria';
const router = new Router();
router.get('/', Categoria.index);
export default router;
The index file that starts sequelize and models
import Sequelize from 'sequelize';
import databaseConfig from '../config/database';
import Categoria from '../models/Categoria';
import Ensaio from '../models/Ensaio';
const models = [Categoria, Ensaio];
const connection = new Sequelize(databaseConfig);
models.forEach((model) => model.init(connection));
finally, the controller Categoria:
import Categoria from '../models/Categoria';
class CategoriaController {
async index(req, res) {
const novaCategoria = await Categoria.create({
nome: 'Farmácia',
});
res.json(novaCategoria);
}
}
export default new CategoriaController();
So, I'm trying to insert an example category into the database, in order to test my API done so far.
However, even having done the migrations correctly, and created the tables (categorias and ensaios), I'm getting an error message that says: "Table 'Projeto_EP.categoria' doesn't exist".
And what I'm finding strange is that the error message appears the name of the table in the singular (categoria) and the table in the database is in the plural (categorias).
I'm really new to programming, and all I've done so far is with the help of videos and classes... I apologize for not having constructed the question in the best way possible. I've been trying to solve this problem for a long time, I hope this amazing community can help me. Thank you very much !
I created a migration (alunos) without any relationships. I migrated it to my database, made the model (Aluno) and used it in my controller to try to insert a 'aluno' example in the database. So in the controller I used Aluno.create() and got success, without any error message. This leads me to believe that I am having problems with the associations between the Essay and Category models.
I hope this information is of help in solving my problem. I thank you all.

Typescript export default always executing

As a beginner in node js I cannot wrap my head around following problem.
import { createSchema, Type, typedModel } from "ts-mongoose";
const CompanySchema = createSchema(
{
companyName: Type.string({ required: true, unique: true })
},
{
timestamps: true
}
);
const Company = typedModel("Company", CompanySchema);
export { CompanySchema, Company };
This all works just fine until one point. When attempting to import this file.
import {CompanySchema, Company} from "./Company";
It executes typeModel method and stores the schema as expected. However, any other import of this file Company.ts reruns this method typeModel again. Which then fails because I can register schema with the name only once. How could I prevent of reruning this and still keep access to this object?
What would be general approach to this in order to keep access to both CompanySchema and Company object(as they will be later used in another schema as a reference)?
I don't know what the createSchema and typedModel are( if they are functions created by you or part of mongoose, the versions of mongoose ive worked with didnt have these functions )
...but I think you should not "createSchema" but define it instead.
e.g
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// define schema
const messageSchema = Schema({
sender: { type: Schema.Types.ObjectId, ref: 'User' },
recipient: { type: Schema.Types.ObjectId, ref: 'User' },
createdAt: { type: Date, default: Date.now },
deletedAt: { type: Date, default: undefined },
readAt: { type: Date, default: undefined},
message: { type: String, maxlength: 5000 }
});
// create a model based on that schema
const Message = mongoose.model('Message', messageSchema);
// Export the message model ... not the schema
module.exports.Message = Message;

Is it possible to define fields at the schema level that are calculated from another field using mongoose?

Is it possible to define fields at the schema level that are based off of another field using mongoose schemas?
For example, say I have this very simple schema:
const mongoose = require('mongoose')
const { Schema } = mongoose
const UserSchema = new Schema({
username: {
type: String,
required: true,
unique: true
},
username_lower: {
type: String,
// calculated: this.username.toLowerCase()
},
email: {
type: String,
required: true,
unique: true
},
email_lower: { // for case-insensitive email indexing/lookup
type: String,
// calculated: this.email.toLowerCase()
},
password: {
type: String,
required: true
},
password_acceptable: {
type: Array,
// calculated: [
// this.password.toLowerCase(),
// this.password.toUpperCase()
// this.password.removeWhiteSpace(), // just an example
// ]
}
})
const User = mongoose.model('User', UserSchema)
module.exports = User
Is there something similar to the dummy "calculated" fields (that I've commented out) that would allow automatic field creation when the new document is saved? This would be very convenient and would reduce the clutter from having to manually define these fields on my back-end routes.
Thank you very much for your help!
you can do it by Pre middleware function, for more details
UserSchema.pre('save', function(){
this.username_lower = this.username.toLowerCase();
this.email_lower = this.email.toLowerCase();
// and so on ...
next();
});

Sequelize: difference of DataTypes and Sequelize

I have seen the use of both classes for defining data types, including in the official documentation, both apparently serve the same purpose.
On a tutorial, I saw the application was using DataTypes for the Model and Sequelize for Migrations, you can exchange between them and they continue to work. Example codes:
Model using DataTypes:
module.exports = (sequelize, DataTypes) => {
const Driver = sequelize.define('Driver', {
firstName: {
type: DataTypes.STRING(50),
allowNull: false
},
Migration using Sequelize:
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Drivers', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
The second parameter in both of them is just the sequelize package itself
const Sequelize = require('sequelize');
You'll notice in your index.js of models (if you set up as suggested) that you do something like the below, where you are passing in sequelize as the second argument.
const model = require(path.join(__dirname, file))(sequelize, Sequelize);
This exposes the data types. It doesn't matter what you call it. For example
module.exports = (sequelize, asd) => {
const Driver = sequelize.define('Driver', {
firstName: {
type: asd.STRING(50),
allowNull: false
},
Same with migrations.
As stated in the docs, DataTypes is:
A convenience class holding commonly used data types.

Sequelize.INTEGER vs DataTypes.INTEGER

In code from 2016 using sequelize ORM, I see model types defined with this pattern:
module.exports = function(sequelize, DataTypes) {
const Tasks = sequelize.define("Tasks", { id: {
type: DataTypes.INTEGER,
[ ...etc.]
However in the current sequelize docs you see most prominently documented: Sequelize.INTEGER (or other type then integer).
At the same time in the current docs I find also DataTypes still documented/used: here.
On same page the Sequelize.INTEGER is used..., is that only for deferrables or something?
I tried to find whether this altered over time or something but could not find it.
When Sequelize.INTEGER is 'current solution' could I just alter above code into:
module.exports = function(sequelize, Sequelize) {
const Tasks = sequelize.define("Tasks", { id: {
type: Sequelize.INTEGER,
[ ...etc.]
Or would using Sequelize as argument somehow make this fail?
The second parameter in both of them is just the sequelize package itself You can use any of them which is on you what you want to use
const Sequelize = require('sequelize');
You'll notice in your index.js of models (if you set up as suggested) that you do something like the below, where you are passing in sequelize as the second argument.
const model = require(path.join(__dirname, file))(sequelize, Sequelize);
This exposes the data types. It doesn't matter what you call it. For example I am calling it abc in below code you can use any name
module.exports = (sequelize, abc) => {
const Driver = sequelize.define('Driver', {
firstName: {
type: abc.STRING(),
allowNull: false
},
last_name: {
type: abc.TEXT,
allowNull: true
},
email: {
type: abc.TEXT,
allowNull: false
},
password: {
type: abc.TEXT,
allowNull: true
}
Same with migrations.

Categories