How to find user by location with posgreSQL and Graphql? - postgresql

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.

Related

Can not Query all users because of MongoDB id

I am coding a CRUD API built in TypeScript and TypeGoose.
I get an error saying,
CannotDetermineGraphQLTypeError: Cannot determine GraphQL output type for '_id' of 'User' class. Is the value, that is used as its TS type or explicit type, decorated with a proper decorator or is it a proper output value?
I have a User entity.
import { Field, ObjectType } from 'type-graphql';
import { ObjectId } from 'mongodb';
import { prop as Property, getModelForClass } from '#typegoose/typegoose';
#ObjectType()
export class User {
#Field()
readonly _id: ObjectId;
#Field()
#Property({ required: true })
email: string;
#Field({ nullable: true })
#Property()
nickname?: string;
#Property({ required: true })
password: string;
constructor(email: string, password: string) {
this.email = email;
this.password = password;
}
}
export const UserModel = getModelForClass(User);
And this is how my query resolver looks like.
#Query(() => [User])
async users() {
const users = await UserModel.find();
console.log(users);
return users;
}
How can I solve this? It seems to be like TypeGraphQL doesn't understand what the MongoDB ID is?
Im not sure about this, but maybe ObjectId.toString() help you.
MongoDB doc about ObjectId.toString()

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

Cyclic dependency with Postgres

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\""
}

Cannot delete a OneToMany record in TypeORM

I have the following schemas
#Entity()
export class Question extends BaseEntity {
#PrimaryColumn()
messageId: string;
#Column()
authorId: string;
#Column()
question: string;
#Column("varchar", { array: true })
possibleAnswers: string[];
#Column()
isAnonymous: boolean;
#OneToMany(() => Answer, (answer) => answer.question, { eager: true })
answers: Answer[];
get formattedAnswers() {
return this.possibleAnswers
.map((answer, idx) => `${numericEmojis[idx]}: **${answer}**`)
.join("\n");
}
}
#Entity()
#Unique("uc_ids", ["userId", "questionMessageId"])
export class Answer extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
userId: string;
#Column()
answerIndex: number;
#ManyToOne(() => Question, (question) => question.answers)
question: Question;
#Column({ readonly: true })
// #ts-expect-error
private readonly questionMessageId: string;
}
Whenever I try to delete like
const question = await Question.findOne(message.id);
await Question.delete(question);
I get the following error:
err: query: SELECT "Question"."message_id" AS "Question_message_id", "Question"."author_id" AS "Question_author_id", "Question"."question" AS "Question_question", "Question"."possible_answers" AS "Question_possible_answers", "Question"."is_anonymous" AS "Question_is_anonymous", "Question__answers"."id" AS "Question__answers_id", "Question__answers"."user_id" AS "Question__answers_user_id", "Question__answers"."answer_index" AS "Question__answers_answer_index", "Question__answers"."question_message_id" AS "Question__answers_question_message_id" FROM "question" "Question" LEFT JOIN "answer" "Question__answers" ON "Question__answers"."question_message_id"="Question"."message_id" WHERE "Question"."message_id" IN ($1) -- PARAMETERS: ["729340583583285289"]
err: (node:19515) UnhandledPromiseRejectionWarning: EntityColumnNotFound: No entity column "answers" was found.
Originally I was trying to setup a cascade delete so that when I remove a question, the answers are removed as well, I got the same error but even after removing the cascade delete I get the same one, how can I fix this? I am using a Postgres database with the SnakeNamingStrategy
Works for me by adding onDelete:"CASCADE" or onDelete:"SET NULL".
I have the following schemas
#Entity()
export class Question extends BaseEntity {
#PrimaryColumn()
messageId: string;
#Column()
authorId: string;
#Column()
question: string;
#Column("varchar", { array: true })
possibleAnswers: string[];
#Column()
isAnonymous: boolean;
#OneToMany(() => Answer, (answer) => answer.question, { eager: true })
answers: Answer[];
get formattedAnswers() {
return this.possibleAnswers
.map((answer, idx) => `${numericEmojis[idx]}: **${answer}**`)
.join("\n");
}
}
#Entity()
#Unique("uc_ids", ["userId", "questionMessageId"])
export class Answer extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
userId: string;
#Column()
answerIndex: number;
// set onDelete as cascade for automatically delete from parent entity
#ManyToOne(() => Question, (question) => question.answers, { cascade: true, onDelete: "CASCADE" })
question: Question;
#Column({ readonly: true })
// #ts-expect-error
private readonly questionMessageId: string;
}