My prisma model
model Todo {
id Int #default(autoincrement()) #id
title String
content String
status TodoStatus #default(IN_PROGRESS)
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
The api call
app.get("/todos/:id", async (req: Request, res: Response) => {
const id = parseInt(req.params.id); // this line
const todo = await prisma.todo.findFirst({
where: { id },
});
res.json(todo);
});
Do I have to always parseInt the id? because by default req.params is a string type, and obviously my Todo primary key is int. I don't see any online resources parsing the int and then only passing to the Prisma query, it feels a bit odd to always parsing the req.params.id to int all the time in every api call.
You can use
prisma.todo.findUnique({
where: { id: +id }
});
Note that you have to specify the field you want to find.
You can use Express Query Parser to automatically parse strings to valid types.
This would automatically convert query params to the valid type.
Example:
// without this parser
req.query = {a: 'null', b: 'true', c: {d: 'false', e: '3.14'}}
// with this parser
req.query = {a: null, b: true, c: {d: false, e: 3.14}}
Related
I'm a newbie in Prisma, and I'm confused with the findUniqueOrThrow method, where I'm trying to get user record by unique email value. For some reason, the error I get after sending a request to this endpoint refers to a other findUniqueOrThrow method, but with an id selection. Can someone help, how can if fix it?
schema.prisma
model User {
id Int #id #default(autoincrement())
firstName String?
lastName String?
email String? #unique
password String?
phone String?
roles Role[] #default([CUSTOMER])
isBanned Boolean? #default(false)
comments Comment[]
token String?
createdAt DateTime? #default(now())
updatedAt DateTime? #updatedAt
}
user.service.ts
#Injectable()
export class UserService {
constructor(private prisma: PrismaClient) {}
async findUserByEmail(email: string): Promise<User> {
try {
const user = await this.prisma.user.findUniqueOrThrow({
where: {
email: email,
},
});
return user;
} catch (e) {
console.log(e);
}
user.controller.ts
#Get('user/findByEmail')
async getUserByEmail(#Body() data: EmailDto) {
return await this.userService.findUserByEmail(data.email);
}
Error:
error
Route order in your user controller matters. Make sure you have the GET route to get user by email above the GET route for getting user by id.
The goal is simple, I want to query enum field in the where clause. Example
prisma version is: "prisma": "3.11.0"
schema.prisma
model Todo {
id Int #default(autoincrement()) #id
title String
content String
status TodoStatus #default(IN_PROGRESS)
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
enum TodoStatus {
IN_PROGRESS
DONE
}
api call
app.get('/todos', (req, res){
const { status } = req.query
const todos = await prisma.todo.findMany({
where: { status: status },
orderBy: {
id: "asc",
},
});
res.json(todos);
})
Frontend I use Next.js and it is a select option
example
<select
id="todo"
name="todo"
onChange={(e) => setSelectedStatus(e.target.value as Status)}
>
{[Status.IN_PROGRESS, Status.DONE].map((status: Status) => {
return (
<option value={status}>{todoStatusToString[status]}</option>
);
})}
</select>
The enum value from Next.js
export enum Status {
IN_PROGRESS = "IN_PROGRESS",
DONE = "DONE",
ALL = "ALL",
}
export const todoStatusToString = {
[Status.IN_PROGRESS]: "In progress",
[Status.DONE]: "Done",
[Status.ALL]: "All",
};
the req.query will be sent from clientside in this format
localhost:3000/todos?status=DONE
{ status: "DONE" }
or
localhost:3000/todos?status=IN_PROGRESS
{ status: "IN_PROGRESS" }
I know that Prisma is built-in to be typesafe. So my assumption is because the data that we get from the frontend is a string type while the enum on Prisma is looking for either IN_PROGRESS or DONE specifically if we send "DECLINED" to status where clause it will spit the same error.
Any help would be appreciated!
In this case you need to cast the type.
You can do it like this
where: { status: status as unknown as TodoStatus}
Let's say I have this schema:
model User {
id String #id #default(cuid())
name String
email String
profile Profile?
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
model Profile {
id Int #id #default(autoicrement())
bio String?
avatar String?
user User #relation(fields: [userId], references: [id], onDelete: Cascade)
userId String #unique
}
Now what I want to archive is, if a user's profile is updated, for example, a bio field is updated, I want the updatedAt field on User model to automatically reflect that and get updated too to the current timestamp.
Any guide, hint or suggestion will be much appreciated!!
The easiest way would be to make some wrapper function I think, for example:
const updateUserProfile = (id, data) => {
return prisma.profile.update({
where: {
id
},
data: {
...data,
user: {
update: {
updatedAt: new Date()
}
}
}
})
}
I Have Created two File
index.js
const {ApolloServer,gql} = require('apollo-server');
const fs = require('fs');
const path = require('path');
const typedefs = gql`
type Query {
info: String!
ask: [Person!]
}
type Person {
name: String!
age: Int!
}
`;
const resolvers = {
Query: {
info: () => `Hello World from Linux Fan`,
ask: () => {
return [fs.readFileSync(__dirname+path.join('/db.db'),'utf-8')]
}
}
}
const server = new ApolloServer({
typedefs,
resolvers
}).listen().then(({url}) => console.log(url)).catch(err => console.log(err));
and one More File for storing Database
db.db
{
name:"Linux Age",
age: 19
}
But The Problem is everytime I make a query for fetching name and age like
{
info
ask{
name
}
}
There is a problem which exist and say
"Cannot return null for non-nullable field Person.name"
How to Solve ??
According to Node.js documentation (https://nodejs.org/api/fs.html#fs_fs_readfilesync_path_options), fs.readFileSync() returns a String or Buffer. From the schema, however, ask() returns an array of type Person which is an object. The result of fs.readFileSync() should be converted to object before returning:
ask: () => {
const person = JSON.parse(JSON.stringify(
fs.readFileSync(__dirname + path.join('/db.db'), 'utf-8').toString()
));
return [person];
}
Notice that I called JSON.stringify() before parsing it with JSON.parse(). The reason is the file db.db has a javascript object (keys, nanely name and age, without double quotes around them) and not a JSON object (keys with quotes as shown below):
{
"name":"Linux Age",
"age": 19
}
Otherwise, JSON.parse() would have a problem parsing the invalid JSON format:
{
name:"Linux Age",
age: 19
}
In addition, toString() after calling readFileSync() is needed to convert a Buffer to a string:
fs.readFileSync(__dirname + path.join('/db.db'), 'utf-8').toString()
I use graphql-tools library and makeExecutableSchema function to make my schema by passing schema and resolver to it
here is my schema:
type Trip {
code: String!
driver: User!
vehicle: Vehicle!
destination: Location!
passengers(page: Int, count: Int): [User!]!
}
type Query {
trip(id: String!): Trip
}
and here is my resolver:
// some imports...
export default {
Query: {
async trip(_, { id }, ctx, info) {
const trip = await Trip.findById(id);
// const page = ???, count = ???
// work on fetch data...
return result;
},
};
how can I get page and count which are defined as nested argument for passengers?
You should define a resolver for the type Trip, such as:
export default {
Query: {
async trip(_, { id }, ctx, info) {
const trip = await Trip.findById(id);
// const page = ???, count = ???
// work on fetch data...
return result;
},
Trip: {
async passengers(trip, { page, count }, ctx, info) {
...
},
}
};
In GraphQL, it's not the concept of "nested fields of a type", but just combinations of "the type of a field". The trip field of type Query has the Trip type, so when you want to work with the passengers field, it should be considered as a field under the Trip type, not a nested field of the Query type.