I've got a problem using tree entity. I'm using typeORM with nestjs.
My entity is this:
#Entity()
#Tree('closure-table')
export class PermissionEntity {
#PrimaryGeneratedColumn()
id: number;
#Column({ nullable: true, unique: true })
key: string;
#Column({ nullable: true })
displayName?: string;
#TreeChildren()
children: PermissionEntity[];
#TreeParent()
parent: PermissionEntity;
}
In my module I added the entity this way :
#Module({
imports: [
UsersModule,
RolesModule,
TypeOrmModule.forFeature([PermissionEntity]),
],
providers: [
{
provide: 'PERMISSION_SERVICE',
useClass: PermissionsService,
},
{
provide: 'APP_GUARD',
useClass: JwtAuthGuard,
},
],
controllers: [PermissionsController],
})
export class PermissionsModule {}
The codes below is my service file:
export class PermissionsService {
constructor(
#InjectRepository(PermissionEntity)
private readonly permissionRepository: TreeRepository<PermissionEntity>,
#Inject('USER_SERVICE') private readonly userService: UsersService,
#Inject('ROLES_SERVICE') private readonly rolesService: RolesService,
) {}
async create(registerPermissionDto: RegisterPermissionDto) {
this.permissionRepository.create(registerPermissionDto);
return this.permissionRepository.save(registerPermissionDto);
}
async getUserPermissions(userId: number, ownerId: number) {
return this.permissionRepository.findTrees();
}
}
When getUserPermissions() service is called this error occures in console:
[Nest] 10644 - 08/12/2022, 8:15:44 PM ERROR [ExceptionsHandler] this.permissionRepository.findTrees is not a function
I've searched every where and I could not succeed in finding a solution ! Is there a bug with nestJs and typeORM Tree entity ? Or do we have working example ?
use like this:
first inject this
#InjectDataSource()
private readonly dataSource: DataSource,
then:
this.dataSource.getTreeRepository(PermissionEntity).findTrees();
Related
When I used person Service in the Organisation Service, I got the error like this:
Nest can't resolve dependencies of the PersonService (PersonModel, ?). Please make sure that the argument at index [1] is available in the OrganizationModule context.
Organization.service.ts
#Injectable()
export class OrganizationService {
constructor(
#InjectModel('Organization') private readonly organizationModel: Model<Organization>,
#Inject(forwardRef(() => UsersService))
private readonly usersService: UsersService,
private readonly mailerService: MailerService,
#Inject(forwardRef(() => PersonService))
private readonly personService: PersonService,
) {}
Organization.module.ts
#Module({
imports: [
RateLimiterModule.register({ type: 'Memory', points: 100, duration: 60 * 5, keyPrefix: 'organization' }),
MongooseModule.forFeature([
{ name: 'Organization', schema: OrganizationSchema },
{ name: 'User', schema: UserSchema },
{ name: 'Person', schema: PersonSchema },
]),
PassportModule.register({ defaultStrategy: 'jwt', session: false }),
forwardRef(() => UsersModule),
forwardRef(() => PersonModule),
],
exports: [OrganizationService],
controllers: [OrganizationController],
providers: [OrganizationService, UsersService, PersonService]
})
Person.module.ts
#Module({
imports: [
RateLimiterModule.register({ type: 'Memory', points: 100, duration: 60 * 5 }),
MongooseModule.forFeature([
{ name: 'Person', schema: PersonSchema },
{ name: 'User', schema: UserSchema },
]),
PassportModule.register({ defaultStrategy: 'jwt', session: false }),
forwardRef(() => UsersModule),
],
exports: [PersonService],
controllers: [PersonController],
providers: [PersonService, UsersService]
})
export class PersonModule {
public configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes(PersonController);
consumer
.apply(SiteMiddleware)
.forRoutes(PersonController);
}
}
What is the error in this code?
You shouldn't re-add dependencies to providers arrays. You already define the PersonService provider in the PersonModule, and the PersonModule properly exports that provider, so all that needs to happen is the OrganizationModule needs to have PersonModule in the imports.
By putting PersonService in the OrganizationModule's providers, Nest will try to recreate the provider in the context of the OrganiztionModule, meaning it will need access to getModelToken('Person') and UsersService as other providers in the current context.
The nestjs class-validator does not work.
For example, if I send a post request with a number for LoginId, I get a normal response.
import { IsNumber, IsString } from 'class-validator';
export class LoginUserDto {
#IsString()
loginId: string;
#IsString()
password: string;
}
class-validator needs to work with Pipe.
You can refer to the following code to inject APP_PIPE or see the nestjs/pipe doc.
import { Module, ValidationPipe } from '#nestjs/common';
import { APP_PIPE } from '#nestjs/core';
import { AppController } from './app.controller';
import { AppService } from './app.service';
#Module({
imports: [],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_PIPE,
useValue: new ValidationPipe({
whitelist: true,
}),
},
],
})
export class AppModule {}
Class Validator should work I am Using it for a long time.
I think in your case it treats LoginId(number, your input) as a string
Try Class Transformer
import { IsNumber, IsString, IsNotEmpty() } from 'class-validator';
import { Type } from 'class-transformer';
export class LoginUserDto {
#IsNotEmpty()
#IsString()
#Type(()=>String)
loginId: string;
#IsString()
#IsNotEmpty()
password: string;
}
My controller has a argument is a InjectModel, code:
constructor(
#InjectModel(Poll) private readonly model: ReturnModelType<typeof Poll>,
){
}
and the Poll code is:
import { prop, modelOptions, getModelForClass } from '#typegoose/typegoose';
import { ApiProperty, ApiPropertyOptions } from '#nestjs/swagger';
#modelOptions({
schemaOptions: {
timestamps: true
}
})
export class Poll {
#ApiProperty({
})
#prop({required: true})
title: string
#prop({required: true})
description: string
#prop()
poll: number
#prop({select: false})
userId: string
#prop()
userName: string
}
Jest code:
import { Poll } from '#libs/db/models/poll.model';
const module: TestingModule = await Test.createTestingModule({
imports: [PollsModule],
controllers: [PollsController],
providers: [
{
provide: getModelForClass(Poll),
useValue: getModelForClass(Poll)
},
]
}).compile();
and I get this error:
Nest can't resolve dependencies of the PollsController (?). Please make sure that the argument PollModel at index [0] is available in the PollsModule context.
Potential solutions:
- If PollModel is a provider, is it part of the current PollsModule?
- If PollModel is exported from a separate #Module, is that module imported within PollsModule?
#Module({
imports: [ /* the Module containing PollModel */ ]
})
poll is in a global model as 'DbModel', and DbModel is in the appModel. so the testModel need imports the DbModel, and then fix !
I'm having issues adding a second entity into my Nest project. It works fine with just one entity Video, but now when I have added another User, I get the error No repository for "User" was found. Looks like this entity is not registered in current "default" connection? on compilation.
What am I doing wrong here?
database.module.ts
import { Module } from "#nestjs/common";
import { TypeOrmModule } from "#nestjs/typeorm";
import { ConfigModule } from "../config/config.module";
import { ConfigService } from "../config/config.service";
import { Video } from "../videos/video.entity";
import { User } from "../auth/user.entity";
#Module({
imports: [
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
type: 'postgres' as 'postgres',
host: configService.dbHost,
port: configService.dbPort,
username: configService.dbUsername,
password: configService.dbPassword,
database: configService.dbName,
entities: [Video, User],
synchronize: true
}),
inject: [ConfigService]
})
]
})
export class DatabaseModule {}
user.entity.ts
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from "typeorm";
Entity()
export class User extends BaseEntity {
#PrimaryGeneratedColumn()
id: number
#Column()
username: string;
#Column()
password: string;
}
Sorry.. typo by me. Forgot to decorate the entity properly. Should be #Entity()
After configured cache globally like the docs, the CacheInterceptor throws an error if i use it outside the app.module.
app.module.ts
const cacheConfig = {
store: redisStore,
host: 'localhost',
port: 6379
}
#Module({
imports: [
CacheModule.register(cacheConfig),
CustomerModule,
],
providers: [
{
provide: APP_INTERCEPTOR,
useClass: CacheInterceptor
}
]
})
export class AppModule {}
customer.module.ts
#Module({
imports: [TypeOrmModule.forFeature([CustomerRepository]), TypeOrmModule.forFeature([User])],
controllers: [CustomerController]
})
export class CustomerModule {}
customer.controller.ts
#Controller('customer')
export class CustomerController {
constructor(
#InjectRepository(CustomerRepository) private customerRepository: CustomerRepository,
#InjectRepository(User) private userRepository: Repository<User>
) {}
#Get()
#UseInterceptors(CacheInterceptor)
async get(): Promise<any> {
const user = await this.userRepository.findOne({ where: { id: 1 }, relations: ['customer'] })
console.log(user.customer.name)
const customer = await this.customerRepository.findOne({ where: { id: 1 }, select: ['id', 'name'] })
return { customer: customer.name, email: user.email }
}
}
I would like using the CacheInterceptor along any modules without import the CacheModule each one.
Nest can't resolve dependencies of the APP_INTERCEPTOR (UUID: 6aa42c77-1bac-4098-b217-1b01eb268240) (?, Reflector). Please make sure that the argument at index [0] is available in the CustomerModule context.
If you have { provide: APP_INTERCEPTOR, useClass: CacheInterceptor } you don't need to add in the #UseInterceptors() decorator in your controller. You should have the CahceInterceptor working by default with the rest of the set up