Skip to content

Commit edc739e

Browse files
committed
Refactor user search with Prisma typed SQL and remove zod validation
1 parent 1b1a1b5 commit edc739e

File tree

3 files changed

+25
-40
lines changed

3 files changed

+25
-40
lines changed

app/routes/users+/index.tsx

Lines changed: 4 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,22 @@
1+
import { searchUsers } from '@prisma/client/sql'
12
import { Img } from 'openimg/react'
2-
import { data, redirect, Link } from 'react-router'
3-
import { z } from 'zod'
3+
import { redirect, Link } from 'react-router'
44
import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'
55
import { ErrorList } from '#app/components/forms.tsx'
66
import { SearchBar } from '#app/components/search-bar.tsx'
77
import { prisma } from '#app/utils/db.server.ts'
88
import { cn, getUserImgSrc, useDelayedIsPending } from '#app/utils/misc.tsx'
99
import { type Route } from './+types/index.ts'
1010

11-
const UserSearchResultSchema = z.object({
12-
id: z.string(),
13-
username: z.string(),
14-
name: z.string().nullable(),
15-
imageId: z.string().nullable(),
16-
imageObjectKey: z.string().nullable(),
17-
})
18-
19-
const UserSearchResultsSchema = z.array(UserSearchResultSchema)
20-
2111
export async function loader({ request }: Route.LoaderArgs) {
2212
const searchTerm = new URL(request.url).searchParams.get('search')
2313
if (searchTerm === '') {
2414
return redirect('/users')
2515
}
2616

2717
const like = `%${searchTerm ?? ''}%`
28-
const rawUsers = await prisma.$queryRaw`
29-
SELECT User.id, User.username, User.name, UserImage.id AS imageId, UserImage.objectKey AS imageObjectKey
30-
FROM User
31-
LEFT JOIN UserImage ON User.id = UserImage.userId
32-
WHERE User.username LIKE ${like}
33-
OR User.name LIKE ${like}
34-
ORDER BY (
35-
SELECT Note.updatedAt
36-
FROM Note
37-
WHERE Note.ownerId = User.id
38-
ORDER BY Note.updatedAt DESC
39-
LIMIT 1
40-
) DESC
41-
LIMIT 50
42-
`
43-
44-
const result = UserSearchResultsSchema.safeParse(rawUsers)
45-
if (!result.success) {
46-
return data({ status: 'error', error: result.error.message } as const, {
47-
status: 400,
48-
})
49-
}
50-
return { status: 'idle', users: result.data } as const
18+
const users = await prisma.$queryRawTyped(searchUsers(like))
19+
return { status: 'idle', users } as const
5120
}
5221

5322
export default function UsersRoute({ loaderData }: Route.ComponentProps) {
@@ -56,10 +25,6 @@ export default function UsersRoute({ loaderData }: Route.ComponentProps) {
5625
formAction: '/users',
5726
})
5827

59-
if (loaderData.status === 'error') {
60-
console.error(loaderData.error)
61-
}
62-
6328
return (
6429
<div className="container mb-48 mt-36 flex flex-col items-center justify-center gap-6">
6530
<h1 className="text-h1">Epic Notes Users</h1>

prisma/schema.prisma

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
// learn more about it in the docs: https://pris.ly/d/prisma-schema
33

44
generator client {
5-
provider = "prisma-client-js"
5+
provider = "prisma-client-js"
6+
previewFeatures = ["typedSql"]
67
}
78

89
datasource db {

prisma/sql/searchUsers.sql

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-- @param {String} $1:like
2+
SELECT
3+
"User".id,
4+
"User".username,
5+
"User".name,
6+
"UserImage".id AS imageId,
7+
"UserImage".objectKey AS imageObjectKey
8+
FROM "User"
9+
LEFT JOIN "UserImage" ON "User".id = "UserImage".userId
10+
WHERE "User".username LIKE :like
11+
OR "User".name LIKE :like
12+
ORDER BY (
13+
SELECT "Note".updatedAt
14+
FROM "Note"
15+
WHERE "Note".ownerId = "User".id
16+
ORDER BY "Note".updatedAt DESC
17+
LIMIT 1
18+
) DESC
19+
LIMIT 50

0 commit comments

Comments
 (0)