NestJS/TypeORM: Cannot read property 'createQueryBuilder' of undefined - javascript

Calling 'localhost:3000/contacts' (with or without parameters) at postman returns me this error and i don't know why. My backend is connected to a PostgreSQL db.
TypeError: Cannot read property 'createQueryBuilder' of undefined
at ContactsRepository.Repository.createQueryBuilder (...\Documents\Visual Studio Code Projects\funds-backend-nestjs\node_modules\typeorm\repository\Repository.js:17:29)
at ContactsRepository.getContacts (...\Documents\Visual Studio Code Projects\funds-backend-nestjs\dist\contacts\contacts.repository.js:17:34)
at ContactsService.getContacts (...\Documents\Visual Studio Code Projects\funds-backend-nestjs\dist\contacts\contacts.service.js:24:39)
at ContactsController.getContacts (...\Documents\Visual Studio Code Projects\funds-backend-nestjs\dist\contacts\contacts.controller.js:25:37)
at ...\Documents\Visual Studio Code Projects\funds-backend-nestjs\node_modules\#nestjs\core\router\router-execution-context.js:38:29
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async ...\Documents\Visual Studio Code Projects\funds-backend-nestjs\node_modules\#nestjs\core\router\router-execution-context.js:46:28
at async ...\Documents\Visual Studio Code Projects\funds-backend-nestjs\node_modules\#nestjs\core\router\router-proxy.js:9:17
My code looks like this:
#EntityRepository(Contact)
export class ContactsRepository extends Repository<Contact> {
async getContacts(filterDto: GetContactsFilterDto): Promise<Contact[]> {
const { name, search } = filterDto;
// const query = this.createQueryBuilder('contacts');
const query = await this.createQueryBuilder()
.select('contacts')
.from(Contact, 'contacts');
if (name) {
query.andWhere('contacts.name = :name', { name });
}
if (search) {
query.andWhere(
'(contacts.email LIKE :search OR contacts.telephone LIKE :search)',
{ search: `%${search}%` },
);
}
const contacts = await query.getMany();
return contacts;
}
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
#Entity({ name: 'contacts' })
export class Contact extends BaseEntity {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
email: string;
#Column()
html_de: string;
#Column()
html_en: string;
#Column()
name: string;
#Column()
telephone: string;
}
export class ContactsController {
constructor(private contactsService: ContactsService) {}
#Get()
getContacts(
#Query(ValidationPipe) filterDto: GetContactsFilterDto,
): Promise<ContactDto[]> {
return this.contactsService.getContacts(filterDto);
}
#Injectable()
export class ContactsService {
constructor(
#InjectRepository(ContactsRepository)
private contactsRepository: ContactsRepository,
) {}
async getContacts(filterDto: GetContactsFilterDto): Promise<Contact[]> {
return this.contactsRepository.getContacts(filterDto);
}
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { ContactsController } from './contacts.controller';
import { ContactsRepository } from './contacts.repository';
import { ContactsService } from './contacts.service';
#Module({
controllers: [ContactsController],
imports: [TypeOrmModule.forFeature([ContactsRepository])],
providers: [ContactsRepository, ContactsService],
exports: [ContactsRepository, ContactsService],
})
export class ContactsModule {}
Somebody know how i can fix this? Regards

ContactsRepository should only be used in the TypeOrmModule.forFeature() and not added to the providers or exports array. When it is added here, the injection token for ContactsRepository no longer points to the proper instance and Nest creates the class, but doesn't have it properly extend Repository as that code is all managed by TypeORM

Related

error TS2740 Type 'DeepPartial<Quiz>[]' is missing the following properties from type 'Question': id, question, hasId, save, and 4 more

I don't know how to fix this error. Does anyone know what I need to fix to get this code to work?
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { CreateQuestionDto } from './dto/create-question.dto';
import { Question } from './question.entity';
import { QuestionRepository } from './question.repository';
#Injectable()
export class QuestionService {
constructor(
#InjectRepository(QuestionRepository)
private questionRepository: QuestionRepository,
) {}
async createQuestion(question: CreateQuestionDto): Promise<Question> {
return await this.questionRepository.save(question);
}
}
Returns the following error:
src/modules/quiz/question.service.ts:15:5 - error TS2740: Type 'DeepPartial[]' is missing the following properties from type 'Question': id, question, hasId, save, and 4 more.
15 return await this.questionRepository.save(question);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/modules/quiz/question.service.ts:15:47 - error TS2769: No overload matches this call.
Overload 1 of 4, '(entities: DeepPartial[], options?: SaveOptions): Promise<(DeepPartial & Quiz)[]>', gave the following error.
Argument of type 'CreateQuestionDto' is not assignable to parameter of type 'DeepPartial[]'.
Type 'CreateQuestionDto' is missing the following properties from type 'DeepPartial[]': length, pop, push, concat, and 29 more.
Overload 2 of 4, '(entity: DeepPartial, options?: SaveOptions): Promise<DeepPartial & Quiz>', gave the following error.
Type 'CreateQuestionDto' has no properties in common with type 'DeepPartial'.
15 return await this.questionRepository.save(question);
Question entity:
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
#Entity('questions')
export class Question extends BaseEntity {
#PrimaryGeneratedColumn()
id: string;
#Column({
type: 'varchar',
})
question: string;
}
Question repository:
import { EntityRepository, Repository } from 'typeorm';
import { Quiz } from './quiz.entity';
#EntityRepository(Quiz)
export class QuestionRepository extends Repository<Quiz> {}
CreateQuestion dto:
import { IsNotEmpty, Length } from 'class-validator';
export class CreateQuestionDto {
#IsNotEmpty()
#Length(3, 255)
question: string;
}
Question repository:
import { EntityRepository, Repository } from 'typeorm';
import { Quiz } from './quiz.entity';
#EntityRepository(Quiz)
export class QuestionRepository extends Repository<Quiz> {}
The problem is that your QuestionRepository is pointing to another entity (Quiz).
Change it to:
export class QuestionRepository extends Repository<Question> {}
That way you can avoid the any clause and use the dto directly on the save call.
async createQuestion(question: CreateQuestionDto): Promise<Question> {
return await this.questionRepository.save(question);
}

convert returned Observables to custom class array in angular

Hello folks I will keep my question very simpler by showing code
I am using Json placeholder site for the fake rest Api
I have a user class Object
I want to convert returned Observable to the
custom class object array.
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
import { Users } from './users.model';
#Injectable({
providedIn: 'root'
})
export class UsersService {
private url = "https://jsonplaceholder.typicode.com";
constructor(private http:HttpClient) {
console.log(this.getUsers());
}
getUsers():Observable<Users[]>{
return this.http.get<Users[]>(`${this.url}/posts`);
}
}
The above is my service
export class Users {
email: string;
id: number;
name: string;
phone: string;
username: string;
}
above is my class I haven't included all properties
In my typescript file I have code like.
constructor(private _usersService:UsersService) {
}
ngOnInit(): void {
this._usersService.getUsers().subscribe(data=>this.users=data);
console.log(this.users);
}
Now the things I want is
how to convert returned observable in my custom class object?
I don't have all the fields so how is it possible to map only those fields which I want?
Hope my question is clear..!!
so this answer takes advantage of map() which is imported from rxjs.
before subscribing we are going to pipe a map() function into the observable stream and then map() each element from that array into a new object that fits our User interface
then we subscribe and the data we get then will be an array that fits our User interface
ngOnInit(): void {
this._usersService.getUsers()
.pipe(map(data => {
return data.map(item => {
const user: User = {
name: item.name,
email: item.email,
}
return user
})
}))
.subscribe(data=>this.users=data);
console.log(this.users);
}
You can do like below, in the User class have a constructor and return User while mapping
import { Component, VERSION, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { map } from 'rxjs/operators';
export class User {
email: string;
id: number;
name: string;
phone: string;
username: string;
constructor( user: User ) {
Object.assign( this, user );
}
}
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
name = 'Angular ' + VERSION.major;
constructor(private http: HttpClient){}
ngOnInit() {
this.http.get<User[]>("https://jsonplaceholder.typicode.com/users")
.pipe(
map( data => {
return data.map( ( user ) => {
return new User( {
email: user['email'],
id: user['id'],
name: user['name'],
phone: user['phone'],
username: user['username'],
} );
} );
} ),
)
.subscribe( (users : User[]) => console.log(users) );
}
}
Working stackblitz

NESTJS - How to send an object with an array and an object

i'm having a trouble with nest. What I want is a little bit difficult, and i don't know how to do that. First, with the ID of a site, I retrieve the users from this site and i want to be able to make a pagination, a sort by order (desc or asc i don't care) and to filtrate the results by value (a string). And in the output, i want to make an object with an array of the results and the synthesis. Example :
{
results : [{audit}],
syhthesis: {pageNumber: number, numberOfResults: number}
}
Honnestly, i've been trying for a while but i just cant understand how to do it. Here is my actual code :
the controller :
import { Controller, Get, Query, Param, Post, Body } from '#nestjs/common';
import { UserAuditService } from './user-audit.service';
import { UserAudit } from 'src/entities/user-audit.entity';
#Controller('useraudit')
export class UserAuditController {
constructor(private readonly userAuditService : UserAuditService){};
#Post("/userpersite/{:id}")
async getUsers(#Body()id: string, #Query('page') page: number): Promise<UserAudit[]>{
return this.userAuditService.getAuditsForSite(id, page)
}
}
the service :
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { UserAudit } from '../entities/user-audit.entity';
import { Repository } from 'typeorm';
#Injectable()
export class UserAuditService {
constructor(
#InjectRepository(UserAudit)
private readonly userAuditRepository : Repository<UserAudit>
){}
async getAuditsForSite(_siteId : string, page: number = 1) : Promise<UserAudit[]>{
return this.userAuditRepository
.find({
join : {
alias : "user-audit",
innerJoinAndSelect: {
user : "user-audit.who"
}
},
where : {
site : _siteId
},
take: 10,
skip: 10 * (page -1)
})
}
}
and the entity :
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { User } from './user.entity';
import { Site } from './site.entity';
#Entity('user-audit')
export class UserAudit {
#PrimaryGeneratedColumn()
id : string;
#ManyToOne(type => User, user => user.id)
who : User
#Column({ length : 100 })
action : string
#ManyToOne(type => Site, site => site.id)
site : Site
#Column({ type : 'date' })
date : Date
#Column({ length : 1000 })
before : string
#Column({ length : 1000 })
after : string
}
I have try many things in my controller, but now, i am stuck, i know i am missing something, perhaps a lot of things, so if someone can help me, it will be very thankful :)
In the UserAuditService you can use findAndCount instead of find. It will return an array with 2 elements. The first element will be the entities and the second will be the total count. Then you need to make the appropriate response object:
async getUsers(#Body()id: string, #Query('page') page: number): Promise<object>{
const [audits, total] = await this.userAuditService.getAuditsForSite(id, page)
return {
results : audits,
syhthesis: {
pageNumber: page,
numberOfResults: total,
}
}
sorry to bother you again. So i've tried it, and it doesn't work :/ I was certain this to be the solution. So I thought of something : to work with models, but again, i am stuck. Here is the new code :
the service :
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { UserAudit } from '../entities/user-audit.entity';
import { Repository } from 'typeorm';
import { UserAuditRequest } from '../entities/user-audit-request';
#Injectable()
export class UserAuditService {
constructor(
#InjectRepository(UserAudit)
private readonly userAuditRepository : Repository<UserAudit>,
private readonly userRequest: Repository<UserAuditRequest>
){}
async getAuditsForSite(_siteId : string, page: number = 1, filter: any) : Promise<any>{
const joinAndSort = this.userAuditRepository
.findAndCount({
join : {
alias : "user-audit",
innerJoinAndSelect: {
user : "user-audit.who"
}
},
where : {
site : _siteId
},
take: 10,
skip: 10 * (page -1)
})
joinAndSort
const sortElement = this.userRequest.find({
where: {
pagination: page
}
})
sortElement
const filterElement = this.userRequest.findAndCount({
where: {
filter: filter
}
})
filterElement
}
}
the controller :
import { Controller, Get, Query, Param, Post, Body } from '#nestjs/common';
import { UserAuditService } from './user-audit.service';
import { UserAudit } from 'src/entities/user-audit.entity';
import { UserAuditRequest } from '../entities/user-audit-request';
import { ResultUserAudit } from '../entities/result-user-audit';
import { Any } from 'typeorm';
#Controller('useraudit')
export class UserAuditController {
constructor(private readonly userAuditService : UserAuditService, private readonly resultUserAudit: ResultUserAudit){};
#Post("/userpersite/:id")
async postUserPerSite(#Param()id: string,#Body() request : UserAuditRequest): Promise<ResultUserAudit>{
return await this.userAuditService.getAuditsForSite(id, request.pagination.pageNumber, request.filter);
the request model :
import { Injectable } from "#nestjs/common";
#Injectable()
export class UserAuditRequest {
constructor(){}
pagination: {
resultNumber: number;
pageNumber: number;
}
sort: {
columnSorted: any;
orderBy: any;
}
filter: {
columnFilter: any;
filtervalue: string;
}
}
and the result model :
import { Injectable } from "#nestjs/common";
import { UserAudit } from "./user-audit.entity";
#Injectable()
export class ResultUserAudit {
constructor(private userAudit: UserAudit){}
result: UserAudit[];
synthesis: {
pageNumber: number,
resultNumber: number;
}
}
I am trying to get the logic for my code, but i don't know, i just can't succed :( I see what i want to do as explain in my first post (hopefully) but i am not able to do it. I hope someone will be able to help and explain. Thank you :)

EXCEPTION: Error: Uncaught (in promise): TypeError: Cannot read property '0' of null any suggestion please?

I am facing this problem since I started to learn angular2.
news.service
#Injectable()
export class NewsServices {
private news: News[] = [];
constructor(private _http: Http) {}
getSingleNews(id: string): Observable <SingleNews[]> {
return this._http.get(`http://watania.info/getNewsById/${id}`)
.map((response: Response) => response.json());
}
export interface SpecialNews {
id: string;
title: string;
url_title: string;
image: string;
category: string;
summary: string;
date_to_publish: string;
}
news.component.ts
import { ActivatedRoute, Router } from '#angular/router';
import { Component, OnDestroy, OnInit } from '#angular/core';
import { NewsServices, SingleNews } from '../../services/news.services';
import { News } from './../../services/news.services';
import { Subscription } from 'rxjs/Rx';
import { VideosPage } from './../../services/videos.service';
#Component({
selector: 'wn-single-news',
templateUrl: './single-news.component.html',
styleUrls: ['./single-news.component.css']
})
export class SingleNewsComponent implements OnInit, OnDestroy {
sub: Subscription;
private selectednews: SingleNews[]= [];
private relatedNews: News[]= [];
constructor(private _newsService: NewsServices,
private route: ActivatedRoute) {}
ngOnInit (): void {
this.sub = this.route.params.subscribe(params => {
let id = params['id'];
this._newsService.getSingleNews(id).subscribe(
selectednews => this.selectednews = selectednews);
this._newsService.getRelatedNews(id).subscribe(
relatedNews => this.relatedNews = relatedNews);
});
console.log(this.relatedNews[0])
}
ngOnDestroy() {
console.log(this.relatedNews[0])
this.sub.unsubscribe();
}
}
The problem is that when I try to use any service like the above one, in any of my component like news component, I got undefined in the console for console.log(this.relatedNews[0]) in ngOnInit, but for console.log(this.relatedNews[0]) in ngOnDestroy I got the array. Moreover I can use the same variable in my template.
<h1 class="news-header"><span></span> {{selectednews[0]?.title}}</h1>
It worked fine when use the variable in the template as shown above. but whenever I try to use it in the component I got
EXCEPTION: Error: Uncaught (in promise): TypeError: Cannot read property '0' of null
any suggestion please?
this._newsService.getRelatedNews(id).subscribe(
relatedNews => this.relatedNews = relatedNews);
});
is an async operation. You need to do your operations with relatedNews inside the callback(subscribe) like this:
this._newsService.getRelatedNews(id).subscribe(
(relatedNews) => {
this.relatedNews = relatedNews;
console.log(this.relatedNews[0]);
});
Put your console.log(this.relatedNews[0]) inside the callback of your service like this:
this._newsService.getRelatedNews(id).subscribe(
relatedNews => this.relatedNews = relatedNews);
console.log(this.relatedNews[0])
});
normally your console.log will return your object

Cannot find namespace error for model in Angular2/TypeScript

The FeaturedCategories model
export class FeaturedCategories {
categories: Array<{ id: number, title: string, graphic: string, categorycards: Array<{}> }>;
}
Also tried this:
export class FeaturedCategories {
id: number;
title: string;
graphic: string;
categorycards: Object[];
}
The Component
import { Component, ChangeDetectionStrategy, ViewEncapsulation } from '#angular/core';
import { ApiService } from '../shared/services/api.service';
import { FeaturedCategories } from '../shared/models/home/featuredcategories';
#Component({
changeDetection: ChangeDetectionStrategy.Default,
encapsulation: ViewEncapsulation.Emulated,
selector: 'home',
styleUrls: [ './home.component.css' ],
templateUrl: './home.component.html'
})
export class HomeComponent {
testFeaturedCategories: Array<FeaturedCategories>;
constructor(private api: ApiService) {
// we need the data synchronously for the client to set the server response
// we create another method so we have more control for testing
this.universalInit();
}
universalInit() {
console.log('universalInit...')
this.api.getFeatured()
.subscribe(categories => {
console.log('categories', categories);
this.testFeaturedCategories = categories
});
}
}
This will work: testFeaturedCategories: Array<{}>;
However I'm trying to use TypeScript to let my App know what type of model to expect.
This causes the error above:
testFeaturedCategories: FeaturedCategories.categories;
And if I just try this: testFeaturedCategories: FeaturedCategories;
I get a type [{}] is not assignable error.
UPDATE
So I noticed that when I commented out all the keys in my FeaturedCategories model finally the error goes away and
featuredCategories: FeaturedCategories[]; will work.
However now this is just an empty object without keys to expect :(
export class FeaturedCategories {
// id: number;
// title: string;
// graphic: string;
// categorycards: Object[];
}
this is working fine for me.
export class MyComponent {
categories: FeaturedCategories[] = [{
id: 1,
title: "",
graphic: "",
categorycards: [{}]
}];
}
export class FeaturedCategories{
id: number;
title: string;
graphic: string;
categorycards: Object[];
}
My problem was trying to type my Array, instead of just using the Typed objects that exist in the larger Array.
Also had a problem in my service, originally I had this:
/**
* Get featured categories data for homepage
* /wiki
*/
getFeatured(): Observable<[{}]> {
return this.http.get(`${this.getFeaturedUrl}/home`)
// .do(res => console.log('getFeatured res', res.json()))
.map(res => res.json())
.catch(this.handleError);
}
I did not need or could even use a type for my larger Categories array, what I needed was a smaller type for the exact Objects that exist in that larger Array:
export class FeaturedCategory {
id?: number;
type: string;
title: string;
graphic?: string;
video?: string;
categorycards: Array<{}>;
}
So now with the correct Type of Objects inside my Array I added it to the service:
getFeatured(): Observable<[FeaturedCategory]> {
return this.http.get(`${this.getFeaturedUrl}/home`)
.map(res => res.json())
.catch(this.handleError);
}
Now back in my Component I imported the single Typed Object
import { FeaturedCategory } from '../shared/models/home/featuredcategory';
Then typed the variable:
featuredCategories: Array<FeaturedCategory>;
And finally in ngOnInit
ngOnInit() {
this.api.getFeatured()
.subscribe(categories => {
console.log('categories', categories);
this.featuredCategories = categories;
});
}
No more errors :)

Categories

Resources