diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..172e059 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +DIRECT_URL= +DATABASE_URL= \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1b6457c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" +} diff --git a/README.md b/README.md index e215bc4..cad7c5e 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,85 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# Prisma Accelerate Hacker News Clone -## Getting Started +This project showcases how to use Prisma ORM with Prisma Accelerate, leveraging caching and on-demand cache invalidation, in a Next.js application to build a minimal Hacker News clone. -First, run the development server: +This app retrieves and caches the [top 20 latest posts](/app/page.tsx#L8) with a long Time-to-Live ([TTL](https://www.prisma.io/docs/accelerate/caching#time-to-live-ttl)). The cache is invalidated on-demand whenever a post is [upvoted](/app/actions/addVotes.ts) or a [new post is added](/app/submit/actions/addPost.ts). + + + +## Prerequisites + +To successfully run the project, you will need the following: + +- The **connection string** of a PostgreSQL database +- Your **Accelerate connection string** (containing your **Accelerate API key**) which you can get by enabling Accelerate in a project in your [Prisma Data Platform](https://pris.ly/pdp) account (learn more in the [docs](https://www.prisma.io/docs/platform/concepts/environments#api-keys)) + +## Getting started + +### 1. Clone the repository + +Clone the repository, navigate into it and install dependencies: + +``` +git clone git@github.com:prisma/prisma-examples.git --depth=1 +cd prisma-examples/accelerate/accelerate-hacker-news +npm install +``` + +### 2. Configure environment variables + +Create a `.env` in the root of the project directory: ```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev +cp .env.example .env ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +Now, open the `.env` file and set the `DATABASE_URL` and `DIRECT_URL` environment variables with the values of your connection string and your Accelerate connection string: + +```bash +# .env -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +# Accelerate connection string (used for queries by Prisma Client) +DATABASE_URL="__YOUR_ACCELERATE_CONNECTION_STRING__" -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +# Database connection string (used for migrations by Prisma Migrate) +DIRECT_URL="__YOUR_DATABASE_CONNECTION_STRING__" +``` -## Learn More +Note that `__YOUR_DATABASE_CONNECTION_STRING__` and `__YOUR_ACCELERATE_CONNECTION_STRING__` are placeholder values that you need to replace with the values of your database and Accelerate connection strings. Notice that the Accelerate connection string has the following structure: `prisma://accelerate.prisma-data.net/?api_key=__YOUR_ACCELERATE_API_KEY__`. -To learn more about Next.js, take a look at the following resources: +### 3. Run a migration to create the `Post` table + +The Prisma schema file contains a single `Post` model. You can map this model to the database and create the corresponding `Post` table using the following command: + +``` +npx prisma migrate dev --name init +``` + +### 4. Generate Prisma Client for Accelerate + +When using Accelerate, Prisma Client doesn't need a query engine. That's why you should generate it as follows: + +``` +npx prisma generate --no-engine +``` + +### 5. Start the app + +You can run the app with the following command: + +``` +npm run dev +``` -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +You should now be able to: -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +- See the most recent post at http://localhost:3000 and upvote it by clicking the ▲ button. +- Submit a new post by navigating to http://localhost:3000/submit. -## Deploy on Vercel +When you make changes, it might take a few seconds to invalidate the cache and display the latest changes. -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +## Resources -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +- [Accelerate Speed Test](https://accelerate-speed-test.vercel.app/) +- [Accelerate documentation](https://www.prisma.io/docs/accelerate) +- [Prisma Discord](https://pris.ly/discord) \ No newline at end of file diff --git a/app/actions/clearCache.ts b/app/actions/clearCache.ts new file mode 100644 index 0000000..5a9d73d --- /dev/null +++ b/app/actions/clearCache.ts @@ -0,0 +1,12 @@ +"use server"; + +import prisma from "@/lib/db"; + +export async function clearCache() { + await prisma.$accelerate.invalidate({ + tags: ["posts"], + }); + + console.log("Cleared cached posts"); + return; +} diff --git a/app/page.tsx b/app/page.tsx index 1752a35..34ab048 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,39 +1,48 @@ import { Post } from "@/components/Posts"; import prisma from "@/lib/db"; -import Link from "next/link"; +import js_ago from "js-ago"; +import { clearCache } from "./actions/clearCache"; export default async function Home() { - const posts = await prisma.post.findMany({ - take: 20, - orderBy: { - createdAt: "desc", - }, - cacheStrategy: { - ttl: 120, - tags: ["posts"], - }, - }); + const { info, data } = await prisma.post + .findMany({ + take: 20, + orderBy: { + createdAt: "desc", + }, + cacheStrategy: { + ttl: 120, + tags: ["posts"], + }, + }) + .withAccelerateInfo(); - return ( - <> -
Showing cached data from: {js_ago(info.lastModified)}
+ )} + + +{vote} points
++ {vote} points |{" "} + {" "} +