In a Next.js context, I'm trying to insert a data in a table using this code snippet :
const user = new User();
user.firstname = "John";
user.lastname = "Appleseed";
user.email = "john.appleseed#apple.com";
await user.create()
But when I inspect the log here's what I see
Basically, the data I put in the request are not written on the DB, but in a certain way Sequelize receive it (as shown in _previousData). But I don't know why there are moved from dataValues to theses _previousData
Here are the model I'm using
The core model :
export default class User {
id!: bigint
hash!: string
firstname?: string
lastname?: string
email?: string
isValidated?: boolean = false
async create(): Promise<void> {
try {
await UserEntity.create({
accountValidated: false,
firstname: this.firstname,
lastname: this.lastname,
email: this.email
});
} catch (error) {
console.error('User.create', error.message)
throw error
}
}
}
Here's the entity related to Sequelize and my PG
interface UserAttributes {
id?: bigint
hash?: string
firstname?: string
lastname?: string
email?: string
accountValidated: boolean
}
interface UserCreationAttributes extends Optional<UserAttributes, "id"> {}
export default class UserEntity extends Model<UserAttributes, UserCreationAttributes> implements UserAttributes {
public id!: bigint
public hash!: string
public firstname?: string
public lastname?: string
public email?: string
public accountValidated!: boolean
public readonly createdAt!: Date
public readonly updatedAt!: Date
public readonly accounts?: AccountEntity[]; // Note this is optional since it's only populated when explicitly requested in code
public static associations: {
accounts: Association<UserEntity, AccountEntity>;
};
}
UserEntity.init({
id: {
type: DataTypes.BIGINT,
primaryKey: true,
allowNull: false,
autoIncrement: true,
unique: true
},
hash: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
firstname: {
type: DataTypes.STRING,
allowNull: true
},
lastname: {
type: DataTypes.STRING,
allowNull: true
},
email: {
type: DataTypes.STRING,
allowNull: true,
unique: true,
validate: {
isEmail: {
msg: "This email is malformed"
}
}
},
accountValidated: {
type: DataTypes.BOOLEAN,
defaultValue: false
},
}, {
sequelize, // We need to pass the connection instance
modelName: 'User',
underscored: true,
tableName: 'blk_user',
timestamps: true
})
UserEntity.beforeValidate(user => {
user.hash = `usr_${v4()}`
})
UserEntity.beforeCreate(instance => console.log('beforeCreate', instance))
What I've tried
[x] Comment hooks
[x] Comment associations
EDIT 11/16 6:39 CET
Seems that it is linked to my way of declaring my models TS interfaces and models. I'll dig into it
Related
I want to get the prospectousId from Dto, but I am getting the below error:,
tenant.controller.ts
#Post('/promote-prospectus')
#HttpCode(HttpStatus.OK)
#ApiOperation({ summary: 'Promoting a prospectus to a tenant.' })
#ApiResponse({ status: HttpStatus.OK, description: 'successful operation', })
async promoteAProspectus(#Res() response: Response, #Body() Dto: promoteProspectousDto) {
let result = await this.tenantsService.promoteAProspectus(Dto);
return response.status(HttpStatus.CREATED).json({ message: 'Prospectous promoted as a tenant by the system.', data: result });
}
tenant.service.ts
public async promoteAProspectus(Dto: promoteProspectousDto): Promise<Tenants> {
/**
* Scopes to be implement while promoting a prospectous to a tenant.
*
* #scope 1 promote the prospectous to a tenant and construct DB.
* #scope 2 Configure all default roles for the newly created tenant.
* #scope 3 Configure administrator user. & assign the administrator role.
*
*/
let prospectus = await this.tenantsRepository.findOne({ Dto.prospectousId });
console.log('hyyyyyyyyyyyyyyyyyyyyyyyyyyy', prospectus);
if (prospectus) {
const { id } = prospectus;
// let tenant: Tenants = await this.promoteAsTenant(prospectus);
// await this.rolesService.onBoardTenantDefaultRoles(tenant.tenantDb);
// let administrator: Users = await this.onBoardAdministratorUser(RequestedBy);
// await this.allocateAdministratorRole(administrator, tenant);
return tenant;
}
throw new ConflictException(`Unable to promote.`);
}
tenant.entity.ts
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
export enum ETenantStatus {
TRIAL = 'TRIAL',
ACTIVE = 'ACTIVE',
BLOCKED = 'BLOCKED',
ARCHIVED = 'ARCHIVED',
}
#Entity({ name: `${Tenants.name}` })
export class Tenants {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column({ nullable: false })
organization: string;
#Column({ unique: false })
db: string;
#Column({ unique: true })
key: string;
#Column({ unique: true })
domain: string;
#Column({ nullable: false })
location: string;
#Column({ nullable: false })
referedBy: string;
#Column()
#CreateDateColumn({ type: 'timestamp without time zone' })
public createdAt: Date;
#Column()
#UpdateDateColumn({ type: 'timestamp without time zone' })
public updatedAt: Date;
}
dto:
import { ApiProperty, ApiPropertyOptional } from "#nestjs/swagger";
import { IsBoolean, IsNotEmpty } from "class-validator";
export class tenantsDto {
#ApiProperty({ required: true, default: '' })
#IsNotEmpty()
organization: string;
#ApiProperty({ required: true, default: '' })
#IsNotEmpty()
domain: string;
#ApiPropertyOptional({ default: '' })
notes: string;
#ApiPropertyOptional({ default: '' })
db: string;
#ApiPropertyOptional({ default: '' })
#IsNotEmpty()
key: string;
#ApiPropertyOptional({ default: '' })
location: string;
#ApiPropertyOptional({ default: '' })
referedBy: string;
#ApiPropertyOptional({ default: false })
skipDbMigration: boolean;
#ApiProperty({ default: true })
#IsBoolean()
acceptedTermsAndConditions: boolean;
}
export class promoteProspectousDto {
#ApiProperty({ required: true, default: '' })
#IsNotEmpty()
prospectousId: string;
#ApiProperty({ required: true, default: '' })
#IsNotEmpty()
key: string;
}
What to do to achieve this? Thanks in advance!
Try using the below code. findOne() is to be replaced by findOneBy() as they say in their changelog.
let prospectus = await this.tenantsRepository.findOneBy({ id: Dto.prospectousId });
See the Changelog of TypeORM for more:
findOne() signature without parameters was dropped. If you need a single row from the db you can use a following syntax:
const [user] = await userRepository.find()
findOne(id) signature was dropped. Use following syntax instead:
const user = await userRepository.findOneBy({
id: id // where id is your column name
})
Im trying to list the itens of Chamados and the respective users, but only the first chamado return the user.
Model Usuario:
export default class Usuario extends BaseModel {
#hasMany(() => Chamado)
public chamados: HasMany<typeof Chamado>
#column({ isPrimary: true })
public id: number
#column()
public nome: string
#column()
public nivel: number
#column()
public email: string
#column()
public senha: string
#column.dateTime({ autoCreate: true })
public createdAt: DateTime
#column.dateTime({ autoCreate: true, autoUpdate: true })
public updatedAt: DateTime
}
Model Chamado:
export default class Chamado extends BaseModel {
#belongsTo(() => Usuario, {
foreignKey: 'id'
})
public user: BelongsTo<typeof Usuario>
#column({ isPrimary: true })
public id: number
#column()
public titulo: string
#column()
public descricao: string
#column()
public url_erro: string
ChamadosController
// Get chamados
public async index() {
const chamados = await Chamado.query().preload('user')
return {
data: chamados,
}
}
is returning 'user' only in first result:
result from get
I am using typescript with Sequelize ORM, I have a User model which has some type definitions like so:
export interface UserAttributes {
id: number
name: string
username: string
email: string
...
}
interface UserCreationAttributes
extends Optional<
UserAttributes,
| 'id'
...
> {}
export class UserModel
extends Model<UserAttributes, UserCreationAttributes>
implements UserAttributes {
id!: number
name!: string
username!: string
email!: string
...
}
And here is the user model itself:
UserModel.init(
{
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
...
}
)
When I use the User model like so:
async function createUser({...params}) {
const user = await User.create({...params})
const {id, name, email, } = user
console.log(name, email) // returns `undefined` `undefined`
return user // id is null when returned but other values are returned
}
Also user.toJSON() returns the values, but id comes back as null. How do I rectify this issue? Also, what could be the cause of this? Thank you very much.
I'm using nodejs and typescript to build a user model. In my mongoose model I'm trying to add a match property to the email field of the Schema but I keep getting this typescript error.:
Argument of type '{ firstName: { type: any; required: [true, string]; }; lastName: { type: any; required: [true, string]; }; email: { type: any; required: [true, string]; unique: true; match: (string | RegExp)[]; }; password: { ...; }; role: { ...; }; resetPasswordToken: any; resetPasswordExpire: DateConstructor; }' is not assignable to parameter of type 'SchemaDefinition'.
Property 'email' is incompatible with index signature.
Type '{ type: any; required: [true, string]; unique: true; match: (string | RegExp)[]; }' is not assignable to type 'string | Function | Function[] | Schema<Document<any>, Model<Document<any>>> | SchemaDefinition | SchemaTypeOptions<any> | Schema<Document<any>, Model<Document<any>>>[] | SchemaTypeOptions<...>[] | SchemaDefinition[]'.
Type '{ type: any; required: [true, string]; unique: true; match: (string | RegExp)[]; }' is not assignable to type 'string'.
This is the model file:
user.ts
import mongoose, { Model, Schema } from 'mongoose';
import crypto from 'crypto';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import User from '../interfaces/User';
const userSchema: Schema = new mongoose.Schema({
firstName: {
type: String,
required: [true, 'Please enter a first name']
},
lastName: {
type: String,
required: [true, 'Please enter a last name']
},
email: {
type: String,
required: [true, 'Please enter an email'],
unique: true,
match: [
/^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/,
'Please add a valid email'
]
},
password: {
type: String,
required: [true, 'Please add a password'],
minlength: 6,
select: false
},
role: {
type: String,
enum: ['admin', 'customer'],
default: 'customer'
},
resetPasswordToken: String,
resetPasswordExpire: Date
}, {
timestamps: true
});
userSchema.pre<User>('save', async function(next) {
if (!this.isModified('password')) {
next();
}
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
});
userSchema.methods.getSignedJwtToken = function(next: any) {
// #ts-ignore
return jwt.sign({id: this._id}, process.env.JWT_SECRET, {expiresIn: process.env.JWT_EXPIRES});
};
userSchema.methods.matchPassword = async function(enteredPassword: string) {
// #ts-ignore
return await bcrypt.compare(enteredPassword, this.password);
};
userSchema.methods.getResetPasswordToken = function() {
const resetToken = crypto.randomBytes(20).toString('hex');
// #ts-ignore
this.resetPasswordToken = crypto.createHash('sha256').update(resetToken).digest('hex');
// #ts-ignore
this.resetPasswordExpire = Date.now() + 10 * 60 * 1000;
return resetToken;
}
export default mongoose.model('User', userSchema);
And this is the interface I'm using:
User.ts
import { Document } from 'mongoose';
export default interface User extends Document {
firstName: string,
lastName: string,
email: string,
password: string,
role: string,
resetPasswordToken: string,
resetPasswordExpire: Date
}
I noticed the error comes when I add the match property to the email object.
In getResetPasswordToken add this.save() before return resetToken
For mongoose schemas, you should use capitalized version of String,which is an actual value type in javascript String Object, and should not be confused with the typescript primitive string type.
I am using node sequelize library to insert data in postgress db
this is my user model in Users.ts file
export class User extends Sequelize.Model {
public id!: number;
public name: string;
public email: string;
public googleId: string;
public password: string;
// public preferredName!: string | null; // for nullable fields
// timestamps!
public readonly createdAt!: Date;
public readonly updatedAt!: Date;
async comparePassword(candidatePassword: string, callback: Function) {
try {
const isMatch = await bcrypt.compare(candidatePassword, this.password);
callback(undefined, isMatch);
} catch (err) {
callback(err);
}
}
}
User.init(
{
id: {
type: Sequelize.DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
},
name: {
type: Sequelize.DataTypes.STRING,
allowNull: false,
},
email: {
type: Sequelize.DataTypes.STRING(128),
allowNull: false,
unique: true,
},
googleId: {
type: Sequelize.DataTypes.STRING(128),
allowNull: true,
},
password: {
type: Sequelize.DataTypes.STRING(300),
allowNull: true,
},
token: {
type: Sequelize.DataTypes.STRING(300),
allowNull: true,
},
},
{
tableName: 'users',
sequelize: sequelize, // this bit is important
}
);
When i try to create a new record in the db using
await User.create({name, email, password, address});
it always return me error with invalid value with whatever input i give
Error: Invalid value { name: 'd' } at Object.escape
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/sql-string.js:65:11)
at PostgresQueryGenerator.escape
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/dialects/abstract/query-generator.js:964:22)
at PostgresQueryGenerator._whereParseSingleValueObject
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/dialects/abstract/query-generator.js:2431:41)
at PostgresQueryGenerator.whereItemQuery
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/dialects/abstract/query-generator.js:2149:19)
at Utils.getComplexKeys.map.prop
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/dialects/abstract/query-generator.js:2206:21)
at Array.map () at PostgresQueryGenerator._whereBind
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/dialects/abstract/query-generator.js:2204:43)
at PostgresQueryGenerator.whereItemQuery
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/dialects/abstract/query-generator.js:2139:19)
at Utils.getComplexKeys.forEach.prop
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/dialects/abstract/query-generator.js:2048:25)
at Array.forEach () at
PostgresQueryGenerator.whereItemsQuery
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/dialects/abstract/query-generator.js:2046:35)
at PostgresQueryGenerator.getWhereConditions
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/dialects/abstract/query-generator.js:2458:19)
at PostgresQueryGenerator.selectQuery
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/dialects/abstract/query-generator.js:1279:28)
at QueryInterface.select
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/query-interface.js:1120:27)
at Promise.try.then.then.then
(/Users/eali/learn/akasa-server/node_modules/sequelize/lib/model.js:1748:34)
at tryCatcher
(/Users/eali/learn/akasa-server/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler
(/Users/eali/learn/akasa-server/node_modules/bluebird/js/release/promise.js:512:31)
at Promise._settlePromise
(/Users/eali/learn/akasa-server/node_modules/bluebird/js/release/promise.js:569:18)
at Promise._settlePromise0
(/Users/eali/learn/akasa-server/node_modules/bluebird/js/release/promise.js:614:10)
at Promise._settlePromises
(/Users/eali/learn/akasa-server/node_modules/bluebird/js/release/promise.js:694:18)
at _drainQueueStep
(/Users/eali/learn/akasa-server/node_modules/bluebird/js/release/async.js:138:12)
at _drainQueue
(/Users/eali/learn/akasa-server/node_modules/bluebird/js/release/async.js:131:9)
My first guess would be that you forgot to add values to your property keys:
await User.create({name, email, password, address});
should be:
await User.create({name: 'john wayne', email: 'lol#example.com', password: '1234', address: 'Someplace 1'});