How to save Column with #Afterload , Nested Relations TypeORM - nested

I want to put the number of posts in my user profile entity.
user_profile.entity.ts
#Entity()
#Unique(['username'])
export class UserProfile {
/** Columns */
#PrimaryGeneratedColumn('uuid')
readonly id: string;
#Column('timestamptz')
#CreateDateColumn()
readonly created_at: Date;
#Column('timestamptz')
#UpdateDateColumn()
readonly updated_at: Date;
#ApiProperty()
#Column({ length: 255 })
#IsString()
#Length(3, 50)
username: string;
#Column()
post_count: number;
#ApiProperty({ readOnly: true })
#Column('uuid')
#IsUUID('4')
user_id: string;
#ApiProperty({ readOnly: true })
#Column({ default: 0, nullable: true })
#IsOptional()
exp?: number;
#ApiProperty({ readOnly: true })
#Column({ default: 1, nullable: true })
#IsOptional()
level?: number;
/** Relations */
#OneToOne((type) => User, (user) => user.profile, { onDelete: 'CASCADE' })
#JoinColumn({ name: 'user_id', referencedColumnName: 'id' })
user: User;
// ** Hooks
#AfterLoad()
updatePostCount() {
this.post_count = this.user.posts.length;
}
}
user.entity.ts
#Entity()
#Unique(['email'])
#Check(`
COALESCE((provider = 'local')::integer, 0)
+
COALESCE(LENGTH(social_id::text)::boolean::integer, 0)
= 1
`)
export class User {
/** Columns */
#ApiProperty()
#PrimaryGeneratedColumn('uuid')
readonly id: string;
#ApiProperty()
#Column('timestamptz')
#CreateDateColumn()
readonly created_at: Date;
#ApiProperty()
#Column('timestamptz')
#UpdateDateColumn()
readonly updated_at: Date;
#ApiProperty()
#Column({ length: 255 })
#IsEmail()
email: string;
/** Relations */
#OneToMany((type) => Post, (post) => post.author)
posts: Post[];
#ApiProperty()
#OneToOne((type) => UserProfile, (userProfile) => userProfile.user, {
cascade: true,
})
profile: UserProfile;
#AfterLoad()
asdfasdf() {
console.log('유저 entity :');
}
}
post.entity.ts
#Entity()
export class Post {
/** Columns */
#PrimaryGeneratedColumn('uuid')
readonly id: string;
#Column('timestamptz')
#CreateDateColumn()
readonly created_at: Date;
#Column('timestamptz')
#UpdateDateColumn()
readonly updated_at: Date;
#ApiProperty()
#Column({ length: 255 })
#IsString()
title: string;
#ApiProperty()
#Column('text')
#IsString()
contents: string;
#ApiProperty({ readOnly: true })
#Column('uuid')
#IsUUID('4')
user_id: string;
/** Relations */
#ManyToOne((type) => User, (user) => user.posts, {
cascade: true,
// eager: true,
onDelete: 'CASCADE',
})
#JoinColumn({ name: 'user_id', referencedColumnName: 'id' })
author: User;
}
users.service.ts
async getMyUser(user_id: string) {
const test = await this.userProfileRepository
.createQueryBuilder('user_profile')
.leftJoinAndSelect('user_profile.user', 'user')
.leftJoinAndSelect('user.posts', 'posts')
.where('user.id = :id', { id: user_id })
.getOne();
return test;
}
async getUserProfile(user_id: string): Promise<UserProfileResponseDto> {
try {
const user = await this.userRepository
.createQueryBuilder('user')
.leftJoinAndSelect('user.profile', 'user_profile')
.leftJoinAndSelect('user.followers', 'followers')
.leftJoinAndSelect('user.following', 'following')
.leftJoinAndSelect('user.posts', 'posts')
.where('user.id = :id', { id: user_id })
.getOne();
if (!user) {
throw new Error();
}
return {
profile: user.profile,
followers: user.followers.length,
following: user.following.length,
posts: user.posts.length,
};
} catch (err) {
throw new BadRequestException('Invalid user_id');
}
}
In user_profile entity, I used #Afterload,
When I use userPrifileRepository(getMyUser), the output is good,
but if I use userRepository(getUserProfile), it doesn't come out. (this.user or this.user.posts.length was printed as undefined.)
And even if the output was good, it could not be saved.
this.post_count = this.user.posts.length

Related

getting graphql error Cannot return null for non-nullable field Account.groups. How to resolve?

I have a problem, when launching a query "Cannot return null for non-nullable field Account.groups".
I have graphql resolver:
#Resolver(of => Account)
export class AccountResolver {
constructor(
#Inject(AccountService) private accountService: AccountService,
) { }
#Query(returns => [Account], {
description: `To get all client's accounts`
})
#UseGuards(AuthGuard)
async accounts(
#Context('clientId') clientId: string,
): Promise<Account[]> {
return await this.accountService.getAllAccounts(clientId);
}
}
And model:
#ObjectType()
#Entity()
export class Account {
#Field()
#PrimaryGeneratedColumn('uuid')
id: string;
#Field()
#Column('text', {
default: ''
})
firstName: string;
#Field()
#Column('text', {
default: ''
})
lastName: string;
#Field()
#Column('text', {
nullable: true,
default: ''
})
avatar: string;
#Field()
#Column('text', {
unique: true,
})
username: string;
#Column('text', { nullable: false })
#Exclude({ toPlainOnly: true })
password: string;
#Field()
#Column({
type: 'varchar',
length: 300,
enum: Roles,
nullable: false
})
role: Roles
#Field()
#Column('text', { nullable: false, unique: true })
email: string;
#Field()
#Column({
default: false
})
emailVerified: boolean;
#Field()
#Column('text', { nullable: true, default: ''})
verificationLink: string;
#OneToMany(() => KitTask, kitTask => kitTask.account)
kitTasks: KitTask[];
#OneToMany(() => Trace, trace => trace.account)
traces: Trace[];
#Field(type => Client)
#ManyToOne(() => Client, client => client.accounts, { onDelete: 'CASCADE' })
client: Client;
#Field(type => Group)
#ManyToMany(() => Group, group => group.accounts)
#JoinTable()
groups: Group[];
}
I'm trying to launch query:
query accounts{
accounts{
id
firstName
lastName
avatar
username
role
email
emailVerified
client {
name
}
groups {
id
}
}
And getting the following error:
What is wrong?

How to Select Some Fields From Relations in Typeorm Relations

I need to Select Some fields from relations in Nest.js TypeOrm .
For Example My Entity is :
#Entity()
export class Chat {
#PrimaryGeneratedColumn()
public id: number;
#Column()
public orderId: number;
#Column({ default: ChatStatus.Active })
public status: ChatStatus;
#Column()
public userId: number;
#ManyToOne(() => User, (user) => user.chats, { nullable: true })
#JoinColumn({ name: 'userId' })
public user: User;
}
Any In My Service :
async findAll(dataSearch) {
return await this.chatRepository.find({
relations: ['user'],
});
}
I Want Just Select "name" , "avatar" from user relation but This select all Columns.
Thanks
#Column({ type: "timestamp", default: () => 'CURRENT_TIMESTAMP',
select: false
})
updated_at: Timestamp;
Example
#Column({ type: "timestamp", default: () => 'CURRENT_TIMESTAMP', select: false })

Typeorm cannot create relations between tables

Have got error 'Cannot read properties of undefined (reading 'joinColumns')'
How to implement: user can have only one assigned role with permissions to resources?
I used sequilize before, in typeorm I'm newbee
user_roles table entity:
#Entity({ name: 'user_roles' })
export class UserRoleEnitity extends DateAudit implements IUserRole {
#Column('varchar')
name: string;
#Column('varchar', {
nullable: true,
})
description?: string;
#Column('boolean', {
name: 'is_active',
default: false
})
isActive?: boolean;
#OneToMany(() => RolePermissionsEnitity, permission => permission.id)
permissions: IUserRolePermission[];
}
and users entity:
#Entity({ name: 'users' })
export class UserEnitity extends DateAudit implements IUser {
#JoinColumn({ name: 'role_id' })
roleId: string;
#OneToMany(() => UserRoleEnitity, role => role.id)
role: UserRoleEnitity;
#Column('varchar', {
unique: true,
})
username: string;
#Column('varchar')
password: string;
#Column('varchar', {
nullable: true,
})
email?: string;
#Column('varchar', {
name: 'mobile_number',
nullable: true,
})
modileNumber?: string;
#Column('varchar', {
nullable: true,
})
name?: string;
#Column('varchar', {
nullable: true
})
position?: string;
#Column({
name: 'is_verified',
default: true
})
isVerified?: boolean;
#Column('timestamp', {
name: 'password_modified_at',
default: new Date()
})
passwordModifiedAt?: Date;
}
and role_permissions
#Entity({ name: 'user_role_permissions' })
export class RolePermissionsEnitity extends DateAudit implements IUserRolePermission {
#JoinColumn({ name: 'role_id' })
roleId: string;
#ManyToOne(() => UserRoleEnitity)
role: IUserRole;
#Column({
type: 'enum',
enum: Actions,
default: Actions.READ
})
action: Actions;
#JoinColumn({ name: 'resource_id' })
resourceId: string;
#ManyToOne(() => ResourceEntity, resource => resource.id)
resource: IResource;
}
When i query repository like this:
const userEntity = await this._userRepository.findOne({
where: {
username,
},
relations: ['role']
});
Your parent entity should not refer to an ID, you should have a relation to a field that defines your user entity.
like this :
UsersRoleEntity
#OneToMany(() => RolePermissionsEnitity, permission => permission.role)
permissions: IUserRolePermission[];
UsersEntity
#OneToMany(() => UserRoleEnitity, role => role.id)
role: UserRoleEnitity;
You don't need to use JoinColumn() in ManyToOne and OneToMany relations.
You can find more information here:
TypeORM Relations Documentation

Nestjs TypeORM syntax error at or near "AND"

I am building a UserService class in my system, and declaring which should be a simple 'find' method, but I'm receiving the error as shown in the image bellow:
This is my service method:
#Injectable()
export class UsersService {
...
async findByRA(academicRegister: string) {
return await this.userRepository.findOne({
where: { academicRegister: academicRegister },
});
}
...
}
This is my controller:
#Controller('users')
export class UsersController {
...
#Get('ra/:ra')
findByRa(#Param('ra') ra: string) {
return this.usersService.findByRA(ra);
}
...
}
This is my User entity, and if I change eager to false, the error does not happen, however I don't get the data from the child entities, which I need
#Entity()
export class User {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
#ApiProperty({ enum: UserRole, enumName: 'UserRole' })
userRole: UserRole;
#Column()
academicRegister: string;
#Column()
password: string;
#OneToOne(() => Coordinator, (coordinator) => coordinator.user, {
eager: true,
nullable: true,
cascade: ['insert', 'update', 'soft-remove', 'recover'],
})
coordinator?: Coordinator;
#OneToOne(() => Monitor, (monitor) => monitor.user, {
eager: true,
nullable: true,
cascade: ['insert', 'update', 'soft-remove', 'recover'],
})
monitor?: Monitor;
#CreateDateColumn()
creationDate: Date;
#DeleteDateColumn()
deletionDate?: Date;
#Column({ nullable: true })
deletedBy?: string;
}
These are the related columns in the child entities:
export class Coordinator {
...
#Column({ nullable: true, unique: true })
userId: string;
#OneToOne(() => User, (user) => user.coordinator, {
orphanedRowAction: 'nullify',
cascade: ['insert', 'update', 'soft-remove', 'recover'],
})
user: User;
...
}
export class Monitor {
...
#Column({ nullable: true, unique: true })
userId: string;
#OneToOne(() => User, (user) => user.monitor, {
orphanedRowAction: 'nullify',
cascade: ['insert', 'update', 'soft-remove', 'recover'],
})
user: User;
...
}
Eager relations are loaded automatically each time you load entities
from the database.
When You will be loading your Coordinator or Monitor entity you don't need to have manually call for your relations it will be done automatically.
You must be accessing your entities in wrong way.

How to do INNER JOIN in typeorm (postgresql)

I have this two entities:
#Entity()
export class Member {
#PrimaryColumn({ name: 'room_id' })
roomId: number;
#PrimaryColumn()
email: string;
#Column({ name: 'is_room_owner' })
isRoomOwner: boolean;
#Column('timestamp without time zone', { name: 'joined_at', nullable: true })
joinedAt: Date | null;
#CreateDateColumn({ name: 'created_at' })
createdAt: Date;
#ManyToOne(() => Room, room => room.members)
#JoinColumn({ name: 'room_id' })
room: Room;
}
#Entity()
export class Room {
#PrimaryGeneratedColumn({ name: 'room_id' })
roomId: number;
#Column()
name!: string;
#Column()
permanent!: boolean;
#Column()
active!: boolean;
#CreateDateColumn({ name: 'created_at' })
createdAt: Date;
#UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
#OneToMany(() => Member, member => member.room, { cascade: true })
members: Member[];
}
I would like to get the rooms by the member's email and filter if they are active.
Basically in sql it would be something like this:
select "room".*, "member".* from room "room"
inner join member "member" on "member".roomId = "room".roomId
where "room".active = :active and "member".email = :email;
It should include the members.
I am getting used to typeorm so thanks a lot for any help!
The query can be constructed using query builder as follows -
async getRoomsByMember(active: boolean, email: string): Promise<any[]> {
return await getRepository(Room)
.createQueryBuilder('room')
.innerJoinAndSelect('room.member', 'member')
.where("room.active = :active", {active: active})
.andWhere("member.email = :email", { email: email })
.getMany();
}

Resources