sequelize with typescript can not use .create with type attributes - mysql

The IDBAttribute -
interface IDBAtribute {
readonly id: number;
readonly createdAt: Date;
readonly updatedAt: Date;
}
The User attributes -
interface IDBMoviesAttributes extends IDBAttribute {
readonly title: string;
readonly description: string;
readonly category: string;
readonly release_date: number;
readonly movie_hour_length: number;
readonly movie_minute_length: number;
readonly image_path: string;
readonly video_path: string;
}
The User model -
import { BuildOptions, DataTypes, Model, Sequelize } from "sequelize";
import { IDBUserAttributes } from "./shared/db-table";
interface UserModel extends Model<IDBUserAttributes>, IDBUserAttributes {}
class User extends Model<UserModel, IDBUserAttributes> {}
type UserStatic = typeof Model & {
new (values?: object, options?: BuildOptions): UserModel;
};
const UserFactory = (sequelize: Sequelize): UserStatic => {
return <UserStatic>sequelize.define("users", {
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
unique: true,
allowNull: false,
},
email: {
type: DataTypes.STRING(320),
allowNull: false,
unique: true,
},
username: {
type: DataTypes.STRING(26),
allowNull: false,
},
password: {
type: DataTypes.STRING(255),
allowNull: false,
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
},
});
}
export {
UserModel,
User,
UserFactory,
UserStatic,
}
I'm Using the User for .create method in sequelize like this -
User.create({
email: req.body.email,
username: req.body.username,
password: hashedPassword,
})
The error -
Argument of type '{ email: string; username: string; password: string; }' is not assignable to parameter of type 'IDBUserAttributes'.
Type '{ email: string; username: string; password: string; }' is missing the following properties from type 'IDBUserAttributes': id, createdAt, updatedAtts(2345)
I know to error is type error but i don't know any other why to the User model, is there any other way I can achive that? I don't need to create the id,createdAt, updatedAt.
How can I get the model in the correct way?

Try making id ,createdAt ,updatedAt as Optional(?) in IDBUserAttributes.
It might work
Example:
interface IDBUserAttributes {
id?: number;
createdAt?: Date;
updatedAt?: Date;
}

const newObjectData: Request['body'] = {
user_id: 1
};
and now, you can use "create" method like this;
await Model.create(newObjectData);

Related

How to correctly type the result of a findOne using typescript, sequelize and mysql?

I currently do the following search
const user: any = await UserModel.findOne({
where: {
email: email,
},
});
I'm typing with any because I need to use some table columns like user.username and user.password, but I don't want to use any.
UserModel:
const UserModel = db.define("users", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true,
},
username: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
access_level: {
type: DataTypes.INTEGER,
allowNull: false,
},
biography: {
type: DataTypes.STRING,
allowNull: true,
},
profile_image: {
type: DataTypes.BLOB("medium"),
allowNull: true,
},
});
I tried to create an userInterface to replace any but it didn't work
interface userAttributes {
id: number;
username: string;
email: string;
password: string;
access_level: number;
biography: string;
profile_image: Blob;
}
Can you help me type the result of this findOne properly, please?
I found the solution reading sequelize doc: https://sequelize.org/docs/v6/other-topics/typescript/
the code in case anyone want to see:
import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from "sequelize";
import { db } from "../database/db-connection";
class UserModel extends Model<InferAttributes<UserModel>, InferCreationAttributes<UserModel>> {
declare id: CreationOptional<number>;
declare username: string;
declare email: string;
declare password: string;
declare access_level: number;
declare biography: string;
declare profile_image: Blob | string;
declare createdAt: CreationOptional<Date>;
declare updatedAt: CreationOptional<Date>;
}
UserModel.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true,
},
username: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
access_level: {
type: DataTypes.INTEGER,
allowNull: false,
},
biography: {
type: DataTypes.STRING,
allowNull: true,
},
profile_image: {
type: DataTypes.BLOB("medium"),
allowNull: true,
},
createdAt: DataTypes.DATE,
updatedAt: DataTypes.DATE,
},
{
sequelize: db,
tableName: "users",
}
);
export { UserModel };
const user: UserModel | null = await UserModel.findOne({
where: {
id: id,
},
});

VersePerWord.belongsTo called with something that's not a subclass of Sequelize.Model

Why can't this use belongsTo in TypeScript? Please help me
this is my verse model I've defined hasMany in this model
Verse Model
import {
Model,
Association,
DataTypes,
InferAttributes,
InferCreationAttributes
} from 'sequelize'
import database from '../../../infrastructure/database/mysql'
import { VersePerWord } from './VersePerWord'
const sequelize = database
export class Verse extends Model<InferAttributes<Verse>, InferCreationAttributes<Verse>> {
public id!: number
public surahId!: number
public uthmaniVerseStyle!: string
public indopakVerseStyle!: string
public verseArabicNumber!: string
public verseLatinNumber!: string
public pageNumber!: number
public juzNumber!: number
public readonly createdAt!: Date | null
public readonly updatedAt!: Date | null
declare static associations: {
verse_per_word: Association<Verse, VersePerWord>
}
}
Verse.init({
id: {
type: DataTypes.BIGINT,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
surahId: {
type: DataTypes.BIGINT,
field: 'surah_id'
},
uthmaniVerseStyle: {
type: DataTypes.TEXT,
field: 'uthmani_verse_style'
},
indopakVerseStyle: {
type: DataTypes.TEXT,
field: 'indopak_verse_style'
},
verseArabicNumber: {
type: DataTypes.STRING,
field: 'verse_arabic_number'
},
verseLatinNumber: {
type: DataTypes.STRING,
field: 'verse_latin_number'
},
pageNumber: {
type: DataTypes.INTEGER,
field: 'page_number'
},
juzNumber: {
type: DataTypes.INTEGER,
field: 'juz_number'
},
createdAt: {
field: 'created_at',
type: DataTypes.DATE,
allowNull: true
},
updatedAt: {
field: 'updated_at',
type: DataTypes.DATE,
allowNull: true
}
}, {
sequelize,
modelName: 'Verse',
tableName: 'verses',
timestamps: true
})
Verse.hasMany(VersePerWord, {
sourceKey: 'id',
foreignKey: 'verseId',
as: 'verse_per_word'
})
but in VersePerWord.ts belongTo not working
VersePerWord Model
// VersePerWord Model
import {
Model,
DataTypes,
ForeignKey, InferAttributes, InferCreationAttributes, Association
} from 'sequelize'
import database from '../../../infrastructure/database/mysql'
import { Verse } from './Verse'
const sequelize = database
export class VersePerWord extends Model<InferAttributes<VersePerWord>, InferCreationAttributes<VersePerWord>> {
declare id: number
declare verseId: ForeignKey<Verse['id']>
declare uthmaniVerseStyle: string
declare indopakVerseStyle: string
declare readonly createdAt: Date | null
declare readonly updatedAt: Date | null
declare static associations: {
verse: Association<VersePerWord, Verse>
}
}
VersePerWord.init({
id: {
type: DataTypes.BIGINT,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
verseId: {
type: DataTypes.BIGINT,
field: 'verse_id'
},
uthmaniVerseStyle: {
type: DataTypes.TEXT,
field: 'uthmani_verse_style'
},
indopakVerseStyle: {
type: DataTypes.TEXT,
field: 'indopak_verse_style'
},
createdAt: {
field: 'created_at',
type: DataTypes.DATE,
allowNull: true
},
updatedAt: {
field: 'updated_at',
type: DataTypes.DATE,
allowNull: true
}
}, {
sequelize,
modelName: 'VersePerWord',
tableName: 'verse_per_words',
timestamps: true
})
VersePerWord.belongsTo(Verse, {
targetKey: 'id',
foreignKey: 'verseId',
as: 'verse_per_word'
})
Does someone have already see an error that look like that ? I search for few days without any issue, if someone could help I'll really appreciate,
thank !

Sequelize ModelNotInitializedError, Object need to be added to a Sequelize instance

I get this error when i run my project.
ModelNotInitializedError: Model not initialized: Member "getTableName"
cannot be called. "Categorie" needs to be added to a Sequelize
instance.
User model :
import { Categorie } from './categorie.model';
import sequelize from './index'
import { Model } from 'sequelize-typescript'
interface UserAttributes {
firstname: string;
lastname: string;
email: string;
password: string;
phone: string;
address: string;
}
export class User extends Model<UserAttributes> implements UserAttributes {
public firstname!: string;
public lastname!: string;
public email!: string;
public password!: string;
public phone!: string;
public address!: string;
public getCategories!: BelongsToManyGetAssociationsMixin<Categorie>;
public addCategories!: BelongsToManyAddAssociationMixin<Categorie, number>;
public hasCategories!: BelongsToManyHasAssociationMixin<Categorie, number>;
public countCategories!: BelongsToManyCountAssociationsMixin;
public createCategories!: BelongsToManyCreateAssociationMixin<Categorie>;
public readonly createdAt!: Date;
public readonly updatedAt!: Date;
}
User.init({
// id: {
// type: DataTypes.INTEGER.UNSIGNED,
// autoIncrement: true,
// primaryKey: true,
// },
firstname: {
type: new DataTypes.STRING(128),
allowNull: false,
},
lastname: {
type: new DataTypes.STRING(128),
allowNull: false,
},
email: {
type: new DataTypes.STRING(128),
allowNull: false,
unique: true,
},
password: {
type: new DataTypes.STRING(128),
allowNull: false,
},
phone: {
type: new DataTypes.STRING(64),
allowNull: false,
},
address: {
type: new DataTypes.STRING(256),
allowNull: false,
},
}, {
tableName: 'User',
sequelize
})
User.belongsToMany(Categorie, {through: 'User_Cat'});
Categorie.belongsToMany(User, {through: 'User_Cat'});
sequelize.sync();
Categorie model :
import { BelongsToManyAddAssociationMixin, BelongsToManyCountAssociationsMixin, BelongsToManyCreateAssociationMixin, BelongsToManyGetAssociationsMixin, BelongsToManyHasAssociationMixin, DataTypes } from 'sequelize';
import sequelize from './index'
import { Model } from 'sequelize-typescript'
import { Unit } from './unit.model';
interface CategorieAttributes {
index: number;
title: string;
img: string;
label: string;
eval_intro: string;
eval_mid: string;
}
export class Categorie extends Model<CategorieAttributes> implements CategorieAttributes {
public index!: number;
public title!: string;
public img!: string;
public label!: string;
public eval_intro!: string;
public eval_mid!: string;
public getUnits!: BelongsToManyGetAssociationsMixin<Unit>;
public addUnits!: BelongsToManyAddAssociationMixin<Unit, number>;
public hasUnits!: BelongsToManyHasAssociationMixin<Unit, number>;
public countUnits!: BelongsToManyCountAssociationsMixin;
public createUnits!: BelongsToManyCreateAssociationMixin<Unit>;
public readonly createdAt!: Date;
public readonly updatedAt!: Date;
}
Categorie.init({
// id: {
// type: DataTypes.INTEGER.UNSIGNED,
// autoIncrement: true,
// primaryKey: true,
// },
index: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: true,
},
title: {
type: new DataTypes.STRING(256),
allowNull: false,
},
img: {
type: new DataTypes.STRING(256),
allowNull: true,
},
label: {
type: new DataTypes.TEXT,
allowNull: false,
},
eval_intro: {
type: new DataTypes.STRING(256),
allowNull: true,
},
eval_mid: {
type: new DataTypes.STRING(256),
allowNull: true,
}
}, {
tableName: 'Categorie',
sequelize
})
Categorie.belongsToMany(Unit, { through: 'Cat_Unit' });
Unit.belongsToMany(Categorie, { through: 'Cat_Unit' });
sequelize.sync();
relation file :
interface UserCatAttributes {
id: number;
UserId: number;
CategorieId: number;
prog: number;
}
export class UserCat implements UserCatAttributes {
public id!: number;
public UserId!: number;
public CategorieId!: number;
public prog!: number;
public readonly createdAt!: Date;
public readonly updatedAt!: Date;
}
And my main file :
import express from 'express';
import { Express } from "express-serve-static-core";
import { Sequelize } from 'sequelize';
import { User } from './models/user.model';
import { Categorie } from './models/categorie.model';
import { Unit } from './models/unit.model';
import { UserCat } from './models/user_cat.model';
import { initRoutes } from './routes/index';
import { sequelize_config } from './config/sequelizeConfig';
import passport from 'passport';
import cors from 'cors';
const port: number = 8080;
class Beyond {
public app: Express;
public sequelize: Sequelize;
constructor() {
this.initApp()
}
initApp() {
this.initExpress()
this.initSequelize()
}
initExpress() {
this.app = express();
this.app.use(cors({
optionsSuccessStatus: 200
}))
this.app.use(express.json());
this.app.use(passport.initialize());
this.app.use(passport.authenticate('session'));
initRoutes(this.app);
this.app.listen(port, () => {
console.log("Serveur à l'écoute sur le port : ", port)
})
}
async initSequelize() {
this.sequelize = new Sequelize(
sequelize_config.db_name,
sequelize_config.db_user,
sequelize_config.db_pw,
sequelize_config.sequelize_info as any
);
await this.sequelize.authenticate().then(() => {
console.log("Connexion ok")
}).catch(err => {
console.log("err connexion : ", err)
})
}
}
export const beyond = new Beyond();
All i want to do is a many to many relation, where User can have many Categorie and Categorie many User.
What driving me crazy is everything was working perfectly before idk what event, the tables where created and all the backend has been made with thooses models
ex
export async function getCatByUserId(id: number): Promise<Array<Categorie>> {
const user = await User.findByPk(id, { include: Categorie });
return await user.getCategories();
}
and since then no way to make it works. I'am far for being a pro so any help is appreciated.
You need to remove cross-references from model modules and define functions to register associations and call them after all your models will be registered in Sequelize instance.
See my answer here to get an idea of how to do it.

Sequelize Typescript Association Foreign Key issue

I implemented Sequelize TypeScript database ORM using MS SQL. Insert query and update query is working fine. While fetching data I try to associate the Model but its throwing error:
error - message: Foreign key for \"ScheduleModel\" is missing on \"EventModel\"
Parent table: schedule
export interface ScheduleAttribute {
name: string;
eventId: string;
notes: string;
events: EventAttributes[];
createdBy: string;
}
export interface CreateScheduleAttributes extends Omit<ScheduleAttribute, 'id'> {}
#ObjectType({ simpleResolvers: true })
#Table({
tableName: 'schedule',
})
export class ScheduleModel extends Model<ScheduleModel> implements ScheduleAttribute {
#PrimaryKey
#Field(() => ID)
#Column({ defaultValue: DataType.UUIDV4 })
id: string;
#Field({ nullable: false })
#Column({ field: 'name', allowNull: false })
name: string;
#PrimaryKey
#Field(() => String, { nullable: true })
#ForeignKey(() => EventModel)
#Column
eventId: string;
#Field(type => [EventModel])
#HasMany(()=>EventModel)
events: EventModel[];
#Field({ nullable: true })
#Column({ field: 'createdBy', allowNull: true })
createdBy: string;
}
Child table:
export interface EventAttributes {
eventname: string;
eventDate: string;
eventType: string;
}
export interface CreateEventAttribute extends Omit<EventAttributes, 'id'> {}
#ObjectType({ simpleResolvers: true })
#Table({
tableName: 'events',
})
export class EventModel extends Model<EventModel> implements EventAttributes {
#PrimaryKey
#Field(() => ID)
#Column({ defaultValue: DataType.UUIDV4 })
id: string;
#Field({ nullable: false })
#Column({ field: 'eventname', allowNull: false })
eventname: string;
#Field({ nullable: false })
#Column({ field: 'eventDate', allowNull: false })
eventDate: string;
#Field({ nullable: false })
#Column({ field: 'eventType', allowNull: false })
eventType: string;
#BelongsTo(() => ScheduleModel, { foreignKey: 'eventId' })
events: ScheduleModel;
}
Insert query is working fine. When try to get records it's throwing for below error:
error - message: Foreign key for \"ScheduleModel\" is missing on \"EventModel\"
I wrote following GetAPI:
sObj = await ScheduleModel.findAll({
include: [
{
model: EventModel,
},
]
});
return sObj
Please help some to resolve it. Thanks in advance.
At least you need to indicate the same foreignKey option with the same value on both sides:
export class ScheduleModel extends Model<ScheduleModel> implements ScheduleAttribute {
// other fields here
#Field(type => [EventModel])
#HasMany(()=>EventModel, { foreignKey: 'eventId' })
events: EventModel[];
// other fields here

how to create how to create many to many relationship in typeorm, [NestJS]

How can I save data in manytomany relationship??
(user, book (MTM))
here is a many-to-many relationship between the user and the book.
My service is not correct.
Also, my code doesn't work.
The data is stored in the book table.
I need your help, everything
Thank you in advance.
My Stack => NestJs, TypeORM, MySQL
There are my entities.
enter image description here
user.entity
#Entity('User')
export class User {
#PrimaryGeneratedColumn()
id!: number;
#Column()
real_name!: string;
#Column()
nick_name!: string;
#Column()
#IsEmail()
email!: string;
#Column()
password!: string;
#Column()
phone_number!: string;
#Column()
image_url: string;
#BeforeInsert()
async hashPassword() {
this.password = await argon2.hash(this.password, {type: argon2.argon2id, hashLength: 40});
}
}
book.entity
#Entity('Book')
export class Book {
#PrimaryGeneratedColumn()
id!: number;
#Column()
title: string;
#Column()
image_url: string;
#Column()
contents: string;
#Column({ type: 'datetime'})
datetime: string;
#ManyToMany(() => User)
#JoinTable()
users: User[];
}
book.controller.ts
#UseGuards(JwtAuthGuard)
#Post('bpc')
savebpc(#Req() req: any, #Query('title') bookTitle: string){
return this.BookService.addBpc(req, bookTitle);
}
book.service.ts
async addBpc(req: any, bookTitle: string): Promise<any>{
const userId = req.user.id;
const bookId = await getRepository('Book')
.createQueryBuilder('book')
.where({title:bookTitle})
.getRawOne()
if (!bookId){
throw new NotFoundException('Not_found_book');
}
const user = await getRepository('User')
.createQueryBuilder('user')
.where({id: userId})
.getRawOne()
//bookId.user.push(user);
//await this.bookRepository.save(bookId);
let userdata = new User();
userdata.id = user.user_id;
userdata.real_name = user.user_real_name;
userdata.nick_name = user.user_nick_name;
userdata.email = user.user_email;
userdata.password = user.user_password;
userdata.image_url = user.user_image_url;
console.log(userdata);
let bookBpc = new Book();
bookBpc.title = bookId.book_title;
bookBpc.image_url = bookId.book_image_url;
bookBpc.contents = bookId.book_contents;
bookBpc.datetime = bookId.book_datetime;
bookBpc.users = [user];
console.log(bookBpc);
await this.bookRepository.create([bookBpc]);
return 'suceess';
}
you need to add the manytomany relation in both user and book, here is an exemple using express and typeorm but its the samething with nestjs
user entity :
#Entity()
export class User {
#PrimaryGeneratedColumn()
id: number;
#Column({ type: 'varchar', nullable: false, unique: true })
username: string;
// we need to add a default password and get it form the .env file
#Column({ type: 'varchar', nullable: true, default: '' })
password: string;
#Column({ type: 'varchar', nullable: true })
firstname: string;
#Column({ type: 'varchar', nullable: true })
lastname: string;
#Column({ type: 'varchar', nullable: false })
email: string;
#Column({ type: 'boolean', nullable: true, default: false })
connected: boolean;
#CreateDateColumn({ name: 'created_at' })
createdAt: Date;
#UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
// new properties
#Column({ name: 'login_attempts', type: 'int', default: 0, nullable: true })
loginAttempts: number;
#Column({ name: 'lock_until', type: 'bigint', default: 0, nullable: true })
lockUntil: number;
//Many-to-many relation with role
#ManyToMany((type) => Role, {
cascade: true,
})
#JoinTable({
name: "users_roles",
joinColumn: { name: "userId", referencedColumnName: "id" },
inverseJoinColumn: { name: "roleId" }
})
roles: Role[];
}
role entity :
#Entity()
export class Role {
#PrimaryGeneratedColumn()
id: number;
#Column({ type: 'varchar', nullable: false, unique: true })
profile: string;
#Column({ type: 'varchar', nullable: false })
description: string;
//Many-to-many relation with user
#ManyToMany((type) => User, (user) => user.roles)
users: User[];
#CreateDateColumn({ name: 'created_at' })
createdAt: Date;
#UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
}
and this is how to save data in user_role :
let entity = await this.userRepository.create(data); //here you create new dataobject that contain user columns
let entity2 = { ...entity, roles: data.selectedRoles } // you have to add the association roles here
const user = await this.userRepository.save(entity2);