Same class used for Entity and DTO, but it has some custom properties exposed to API but not stored in DB.
Closed this issue · 3 comments
Hello friend. Good work on this repo. I am facing an issue and would like to know your thoughts.
Let's say I have below class:
@ObjectType()
@Entity()
export class User {
@Field(() => ID)
@PrimaryGeneratedColumn('uuid')
id: string;
@Field(() => String)
@Column()
username: string;
@Column()
yearOfBirth: number;
@Field(() => Number)
age: number;
}
When I create new users, I store their year of birth in database, but clients can query user's age directly (which I calculate it in graphql resolver before returning the response to the client). However this doesn't work with your setup since your code iterates through every field and transforms it into Select query before executing it into the DB.
When I run below query:
query User($input: GetOneInput!) {
user(input: $input) {
id
username
age
}
}
I get below error:
"message": "Property "age" was not found in "User". Make sure your query is correct."
How would you approach this?
Thank you in advance.
Hello @leartbeqiraj1 , first of all, thank you for showing interest in my repository.
To summarize the issue you mentioned, you want both age
and yearOfBirth
to be stored in the database, but you don't want yearOfBirth
to be directly accessible to users via a graphql query.
As you mentioned, my code automatically reads and processes all query fields, but I don't think that's the problem here.
Lets cut to the chase, I think the reason you can't access the age
field is that it hasn't been created in your database yet.
How to resolve the issue
Here's the thing.
As you know,
- The
@Column
decorator is used to set up storage in the database through Typeorm. - The
@Field
decorator is supported by Graphql, meaning it doesn't directly access the database, it just supports Graphql on a code level.
Therefore, to achieve what you want, storing both fields in the database while preventing yearOfBirth
from being accessible via a query, the following setup seems appropriate.
@ObjectType()
@Entity()
export class User {
@Field(() => ID)
@PrimaryGeneratedColumn('uuid')
id: string;
@Field(() => String)
@Column()
username: string;
// Stored in the database but not exposed in the GraphQL schema
@Column()
yearOfBirth: number;
// Stored in the database and exposed in the GraphQL schema
@Field(() => Number)
@Column()
age: number;
}
Conclusion
I hope it works!
If there's any problem with this solution, please leave more comments!
If there are no more issues, I'll mark it as completed
in a few days!
Feel free to stop by anytime, whenever you have more issues! Thank you so much!
Hey @Ho-s, Thank you for your fast response and detailed explanation, however that's not what I exactly meant. I don't want "age" to be stored in DB, that's why I left it without @column decorator and only with @field decorator.
Here's more details:
user.entity.ts:
@ObjectType()
@Entity()
export class UserTest {
@Field(() => ID)
@PrimaryGeneratedColumn('uuid')
id: string;
@Field(() => String)
@Column()
username: string;
@Column()
yearOfBirth: number;
@Field(() => Number)
age: number;
}
So since I don't want to store "age" as a column in DB, that means I need so somehow calculate it and populate the "age" property with a value before returning the response to the user, and here's a way of doing so:
users.resolver.ts:
@Query(() => UserTest, { name: 'userTest' })
async getOneUserTest(
@Args({ name: 'input' })
qs: GetOneInput<UserTest>,
@CurrentQuery() gqlQuery: string,
) {
const user = await this.userService.getOneTest(qs, gqlQuery);
user.age = 2024 - user.yearOfBirth
return user;
}
This is usually how I deal with properties that are not stored in DB but exposed to API. But, in your case, the "age" field requested by the client, automatically get's added to the "select" object and gets queried in DB, and since "age" isn't stored as a column in my table, typeorm throws the error:
"message": "Property "age" was not found in "User". Make sure your query is correct."
I hope I was a little bit more clear of my question.
Thank you once again.
Hey @leartbeqiraj1
Thanks for the detailed explanation! It helped me discover a flaw in my logic!
The issue was with attempting to select all fields in a GraphQL query, which led to TypeORM indicating that some columns do not exist.
After identifying this, I added logic to only select existing columns!
I've submitted a PR regarding this, so if there are any issues with the PR or if you have a better solution, please feel free to leave a comment.
Thanks!