Cyclic dependency with Postgres - postgresql

I have two entities called User and Ad and the relation is 1:M, when I need to create a new Ad, I need to pass the announcer_id together.
Ad.ts
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
JoinColumn,
} from 'typeorm';
import User from './User';
#Entity('ads')
class Ad {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
announcer_id: string;
#ManyToOne(() => User)
#JoinColumn({ name: 'announcer_id' })
announcer: User;
}
export default Ad;
User.ts
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
} from 'typeorm';
#Entity('users')
class Ad {
#PrimaryGeneratedColumn('uuid')
id: string;
#Column()
name: string;
#Column()
email: string;
#Column()
password: string;
#CreateDateColumn()
created_at: Date;
#UpdateDateColumn()
updated_at: Date;
}
export default Ad;
CreateAdService.ts
import { getCustomRepository } from 'typeorm';
import Ad from '../models/Ad';
import AdsRepository from '../repositories/AdsRepository';
interface IRequest {
announcer_id: string;
title: string;
description: string;
price: number;
n_room: number;
n_bathroom: number;
garage: boolean;
}
class CreateAdService {
public async execute({
announcer_id,
title,
description,
price,
n_room,
n_bathroom,
garage,
}: IRequest): Promise<Ad> {
const adsRepository = getCustomRepository(AdsRepository);
const priceNegative = adsRepository.isNegative(price);
if (priceNegative) {
throw new Error("You can't create an announcement with negative price.");
}
const ad = adsRepository.create({
announcer_id,
title,
description,
price,
n_room,
n_bathroom,
garage,
});
await adsRepository.save(ad);
return ad;
}
}
export default CreateAdService;
The Error
{
"error": "Cyclic dependency: \"Ad\""
}

Related

TypeORMError: alias was not found

I'm trying to make API pagination for GET /authors.
I have bidirectional many to many relation between authors and books table.
I found that problem is when using creatingQueryBuilder() in combination with .leftJoinAndSelect() and .skip() I get TypeORMError: ""authors"" alias was not found. Maybe you forgot to join it?. But I'm not sure how to solve it.
My database look like this:
library=# select * from authors;
id | first_name | last_name | birth_date | created_at | updated_at
----+------------+-----------+------------+----------------------------+----------------------------
library=# select * from books;
id | title | isbn | pages | created_at | updated_at
----+------------------+-----------------------+-------+----------------------------+----------------------------
library=# select * from books_authors
books_id | authors_id
----------+------------
(4 rows)
Entities look like this:
import { Exclude } from 'class-transformer';
import { BookEntity } from 'src/book/entities/book.entity';
import {
Entity,
PrimaryGeneratedColumn,
Column,
BeforeInsert,
ManyToMany,
} from 'typeorm';
#Entity({ name: 'authors' })
export class AuthorEntity {
#Exclude()
#PrimaryGeneratedColumn()
id: number;
#Column()
firstName: string;
#Column()
lastName: string;
#Column({ type: 'date', nullable: true })
birthDate: Date | null;
#Exclude()
#Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
createdAt: Date;
#Exclude()
#Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
updatedAt: Date;
#ManyToMany(() => BookEntity, (book) => book.authors)
books: BookEntity[];
#BeforeInsert()
updateTimestamp() {
this.updatedAt = new Date();
}
}
import { Exclude } from 'class-transformer';
import { AuthorEntity } from 'src/author/entities/author.entity';
import {
Entity,
PrimaryGeneratedColumn,
Column,
BeforeInsert,
ManyToMany,
JoinTable,
} from 'typeorm';
#Entity({ name: 'books' })
export class BookEntity {
#Exclude()
#PrimaryGeneratedColumn()
id: number;
#Column()
title: string;
#Column()
isbn: string;
#Column()
pages: number;
#Exclude()
#Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
createdAt: Date;
#Exclude()
#Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
updatedAt: Date;
#ManyToMany(() => AuthorEntity, (author) => author.books)
#JoinTable({ name: 'books_authors' })
authors: AuthorEntity[];
#BeforeInsert()
updateTimestamp() {
this.updatedAt = new Date();
}
}
Service method looks like this:
async findAll(
pageOptionsDto: PageOptionsDto,
filterAuthorDto: FilterAuthorDto,
): Promise<PageDto<AuthorEntity>> {
const builder = this.dataSource
.getRepository(AuthorEntity)
.createQueryBuilder('authors');
if (filterAuthorDto?.firstName) {
builder.where('"authors"."first_name" LIKE :firstName', {
firstName: `%${filterAuthorDto.firstName}%`,
});
}
if (filterAuthorDto?.lastName) {
builder.andWhere('"authors"."last_name" LIKE :lastName', {
lastName: `%${filterAuthorDto.lastName}%`,
});
}
// This part of code is problematic
builder
.innerJoinAndSelect('authors.books', 'books')
.orderBy('"authors"."created_at"', pageOptionsDto.order)
.skip(pageOptionsDto.skip)
.take(pageOptionsDto.perPage);
const total = await builder.getCount();
const { entities } = await builder.getRawAndEntities();
const pageMetaDto = new PageMetaDto({ total, pageOptionsDto });
return new PageDto(entities, pageMetaDto);
}
Just remove the double quotation inside the string, it's redundant and makes typeorm get confused and couldn't find related defined alias.
...
.orderBy('authors.created_at', pageOptionsDto.order)
...

How to find user by location with posgreSQL and Graphql?

I dont' know where to start, I tried follow a answer by import Geometry from Geojson.
User.ts file
import { Geometry } from "geojson";
import { Field, ObjectType } from "type-graphql";
import {
BaseEntity,
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
} from "typeorm";
#ObjectType()
#Entity()
export class User extends BaseEntity {
#Field()
#PrimaryGeneratedColumn()
id!: number;
#Column({ unique: true })
userId!: string;
#Field(type => Geometry)
#Column({ nullable: true })
location: Geometry;
#Field()
#CreateDateColumn()
createdAt: Date;
}
but I got a error with PosgreSQL
DataTypeNotSupportedError: Data type "Object" in "User.location" is not supported by "postgres" database.
and a error with Graphql
'Geometry' only refers to a type, but is being used as a value here.

Error retrieving data from DB using typeorm and type-graphql

I'm using type-graphql in conjunction with typeorm, apollo-server-express and postgreSQL. I have a User and a Customer entity in a 1:n relationship, meaning one user can have multiple customers.
I can create users and customers just fine, but when attempting to retrieve the user associated to a customer using Apollo Server playground, I get an error message stating "Cannot return null for non-nullable field Customer.user."
When I check the database, the associated user id on the customer table is definitely not null (see attached image).
query {
customers {
customerId
customerName
user {
userId
}
}
}
Does anyone know what I'm doing wrong?
User.ts
import { Field, ID, ObjectType } from "type-graphql";
import { BaseEntity, Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm";
import { Customer } from "./Customer";
#ObjectType()
#Entity("users")
export class User extends BaseEntity {
#Field(() => ID)
#PrimaryGeneratedColumn("uuid")
userId: string;
#Field()
#Column({ unique: true })
email: string;
#Column({ nullable: false })
password: string;
#Field(() => Customer)
#OneToMany(() => Customer, customer => customer.user)
customers: Customer[]
}
Customer.ts
import { Field, ID, ObjectType } from "type-graphql";
import { BaseEntity, Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
import { User } from "./User";
#ObjectType()
#Entity("customers")
export class Customer extends BaseEntity {
#Field(() => ID)
#PrimaryGeneratedColumn("uuid")
customerId: string;
#Field()
#Column()
customerName: string;
#Field(() => User)
#ManyToOne(() => User, user => user.customers)
user: User;
}
CustomerResolver.ts
export class CustomerResolver {
#Query(() => [Customer])
async customers():Promise<Customer[]> {
try {
return await Customer.find();
} catch (error) {
console.log(error);
return error;
}
}
....
Setup / Version
Node: v14.17.0
"apollo-server-express": "^2.24.0",
"type-graphql": "^1.1.1",
"typeorm": "0.2.32"
postgreSQL: 13.2
In your resolver change the find operation like below:
return Customer.find({
relations: ["user"]
});
You should write a #FieldResolver which will fetch customers based on root user data.
https://typegraphql.com/docs/resolvers.html#field-resolvers

How to map joined table column to an entity's field in TypeORM

There are two entities as follow:
// user.entity.ts
#Entity()
export class User extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
#RelationId((user: User) => user.group)
groupId: number;
#Column()
fullName: string;
#Column()
email: string;
#Column()
passwordHash: string;
#ManyToOne(type => Group, group => group.users)
#JoinColumn()
group: Group;
isOwner: boolean;
}
// group.entity.ts
#Entity()
export class Group extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#Column({ default: false })
isOwner: boolean;
#OneToMany(type => User, user => user.group)
users: User[];
}
I'd like to map the isOwner value of Group to isOwner of User
I tried:
async findOneById(id: number): Promise<User> {
return await User.createQueryBuilder('user')
.leftJoinAndMapOne('user.isOwner', 'user.group', 'group')
.select(['user.id', 'user.fullName', 'user.email', 'group.isOwner'])
.getOne();
}
the result was:
It is possible to achieve that by using #AfterLoad() or with JS or with raw query.
BUT
Is it possible to implement that using the orm on the query level?
Something like that could be as a solution:
findOneById(id: number): Promise<User> {
return User.createQueryBuilder('user')
.leftJoinAndMapOne('user.isOwner', 'user.group', 'group')
.select(['user.id', 'user.fullName', 'user.email', 'group.isOwner AS user.isOwner']) // or probably 'group.isOwner AS user_isOwner'
.getOne();
}
And you could look at this answer, hope it would be helpful

Angular 2: Create objects from a class

Hello I'm wondering if it's possible to create a class where you implement an interface and from there you send the data get from .get service to create a new object. Something like this
import { Component, OnInit } from '#angular/core';
import { User} from '../interfaces/user';
import {UserService} from '../services/user.service';
import { UserClass } from '../classes/user-class'
#Component({
selector: 'up-pros',
templateUrl: './pros.component.html',
providers: [UserService]
})
export class ProsComponent implements OnInit {
public users :User[];
public term: string;
constructor(private _httpService: UserService) { }
ngOnInit() {
console.log(UserClass)
this.term= 'INSTRUCTOR';
this._httpService.searchUsers(this.term)
.subscribe(
data => {this.users = new UserClass(data), console.log(data)},
error => alert(error + ' Error Get')
);
}
}
where my UserClass code is something like next one
import { User } from '../interfaces/user';
import { Address } from "../interfaces/address";
export class UserClass implements User {
public id: number
public name: string
public password: string
public lastNameA: string
public lastNameB: string
public photo: string
public telephone: string
public email: string
public userType: string
public active: string
public score: number
public createdAt: string
public updatedAt: string
public Address: Address
constructor ( id: number,
password: string,
name: string,
lastNameA: string,
lastNameB: string,
photo: string,
telephone: string,
email: string,
userType: string,
active: string,
score: number,
createdAt: string,
updatedAt: string,
Address: Address) {
this.name = name
this.password = password
this.lastNameA = lastNameA
this.lastNameB = lastNameB
this.photo = photo
this.telephone = telephone
this.email = email
this.userType = userType
this.active = active
this.score = score
this.createdAt = createdAt
this.updatedAt = updatedAt
this.Address = Address
}
}
and by the last, the interface:
import { Address } from "./address"
export interface User {
name: string;
password: string;
lastNameA: string;
lastNameB: string;
photo: string;
telephone: string;
email: string;
userType: string;
active: string;
score: number;
createdAt: string;
updatedAt: string;
Address: Address;
}
Is this possible? because if I try to do this Im getting the next error at pros-component.ts:
Supplied parameters do not match any signature of call target.
[default] Checking finished with 1 errors
My service:
import {Injectable} from '#angular/core';
import {Http, Headers} from '#angular/http';
import 'rxjs/add/operator/map';
import { User } from '../interfaces/user';
#Injectable()
export class UserService {
url= 'http://localhostapi/users';
constructor(private _http: Http){}
getUsers(){
return this._http.get(this.url)
.map(res => res.json());
}
searchUsers(term : string ){
return this._http.get('http://localhostapi/listas?user='+term)
.map(res => res.json());
}
searchUser(term : string ){
return this._http.get('http://localhostapi/users/'+term)
.map(res => res.json());
}
postUsers(user: User){
var headers = new Headers ();
headers.append('Content-Type','application/json');
return this._http.post(this.url, user, {headers: headers})
.map(res => res.json());
}
updateUsers(user: User, term: string){
var headers = new Headers ();
headers.append('Content-Type','application/json');
return this._http.put(this.url+"/"+term, user, {headers: headers})
.map(res => res.json());
}
}
If the structure of data matches the list of UserClass, you can simply do
this._httpService.searchUsers(this.term)
.subscribe(
data => {
this.users = data as User[];
console.log(data)
},
error => alert(error + ' Error Get')
);