この
今回の
本当で
ちょっとした
データベースを 使うべきか
どのまず
自前で
そこで
がっくりした。
さて、
そうなると
早速、
どうしても
ORM を 使うか
どのTypeScript の
Prisma の
また、
例えば、
const findById = async ({ id }: { id: number }) => await db.select().from(countries).leftJoin(cities, eq(cities.countryId, countries.id)).where(eq(countries.id, id));
const country = findById({ id: 10 });
↓
SELECT *FROM countriesLEFT JOIN cities ON cities.countryId = countries.idWHERE countries.id = 10;
ほぼ SQL を
SQL は
使った API リクエスト
tRPC をデータ取得・更新を
今
例えば、
export const postRouter = { bySlug: publicProcedure.input(z.object({ slug: z.string() })).query(({ ctx, input }) => { return ctx.db.query.posts.findFirst({ where: eq(schema.posts.slug, input.slug), }); }),
incrementViews: publicProcedure.input(z.object({ slug: z.string() })).mutation(({ ctx, input }) => { return ctx.db .insert(schema.posts) .values({ slug: input.slug, views: 1 }) .onConflictDoUpdate({ target: [schema.posts.slug], set: { views: increment(schema.posts.views), updatedAt: new Date() }, }); }),} satisfies TRPCRouterRecord;
それぞれが
type PostRouter = { bySlug: QueryProcedure<{ input: { slug: string }; output: { slug: string; views: number; createdAt: Date; updatedAt: Date } | undefined; }>; incrementViews: MutationProcedure<{ input: { slug: string }; output: NeonHttpQueryResult<never> }>;};
使って 保護された プロシージャを 定義する
Auth.js をtRPC では
色々試してみたかったので@auth/drizzle-adapter
を
ただ、
さて、
export const protectedProcedure = t.procedure.use(({ ctx, next }) => { if (!ctx.session?.user) { throw new TRPCError({ code: 'UNAUTHORIZED' }); } return next({ ctx: { session: { ...ctx.session, user: ctx.session.user }, }, });});
上記の
使い方はpublicProcedure
はprotectedProcedure
export const authRouter = createTRPCRouter({ getSession: publicProcedure.query(({ ctx }) => { return ctx.session; }),
getSecretMessage: protectedProcedure.query(() => { return 'you can see this secret message!'; }),});
処理
コンポーネント側のAPI エンドポイントの
Next.js は
当初は
- 戻る
ボタン等の リロードが 発生しない ページ遷移では PV が インクリメントしない - 別タブから
戻ってきた 時に 最新の PV に 更新されない
Client Component に
以下が
export const ViewCounter = ({ slug }: { slug: string }) => { const utils = api.useUtils();
const { mutate } = api.post.incrementViews.useMutation({ onSuccess: async () => await utils.post.bySlug.invalidate({ slug }), });
const { data } = api.post.bySlug.useQuery({ slug }); const views = data?.views;
React.useEffect(() => mutate({ slug }), [mutate, slug]);
if (!views) return <ViewCounterSkeleton />;
return <p className='font-sans text-sm text-muted-foreground'>{views.toLocaleString()} views</p>;};
export const ViewCounterSkeleton = () => <Skeleton className='h-4 w-14' />;
tRPC にはuseEffect
からmutate
関数が
こういった
データが
一つの 選択肢
もうPV の
Upstashの今回は → 実装した)。
ただし、
Redis の
ただし、
後述する tRPC ではまた 違った 書き方と なる。 ↩