From 7b2acf7a88efb487cb1940c1066f74d1a43de3d1 Mon Sep 17 00:00:00 2001 From: Wojtazzzz Date: Wed, 8 Feb 2023 19:46:24 +0100 Subject: [PATCH] refactor/update prisma connection --- .eslintrc | 6 ++++ api-helpers/api-hofs.ts | 4 +-- api-helpers/articles.ts | 22 ++++++------ api-helpers/prisma/db.ts | 34 ++++--------------- api-helpers/sitemap.ts | 10 +++--- app/(articles)/[displayStyle]/[page]/page.tsx | 9 ++--- app/(articles)/[displayStyle]/head.tsx | 2 +- app/(articles)/[displayStyle]/layout.tsx | 2 +- app/(content)/admin/[blogsType]/page.tsx | 2 +- app/(content)/admin/blogs/[blogId]/page.tsx | 4 +-- app/(content)/artykuly/[slug]/page.tsx | 7 +--- components/AlgoliaSearch/AlgoliaHit.tsx | 2 +- components/ArticleTile/ArticleTile.tsx | 2 +- .../ChangeBlogsList/ChangeBlogsList.tsx | 2 +- components/Pagination/Pagination.tsx | 2 +- components/Table/Table.tsx | 2 +- pages/api/sitemap.ts | 4 +-- utils/creator-utils.ts | 2 +- utils/fetchAdminBlogsList.tsx | 6 ++-- utils/fetchArticleBySlug.ts | 5 +-- utils/fetchArticlesForList.ts | 7 ++-- utils/fetchBlogsForGrid.ts | 7 ++-- utils/types/index.d.ts | 5 +++ types.ts => utils/types/types.ts | 8 ++--- 24 files changed, 61 insertions(+), 95 deletions(-) create mode 100644 utils/types/index.d.ts rename types.ts => utils/types/types.ts (65%) diff --git a/.eslintrc b/.eslintrc index a3c57751..2fab76a7 100644 --- a/.eslintrc +++ b/.eslintrc @@ -58,6 +58,12 @@ "rules": { "import/no-default-export": "off" } + }, + { + "files": ["**/*.d.ts"], + "rules": { + "no-var": "off" + } } ] } diff --git a/api-helpers/api-hofs.ts b/api-helpers/api-hofs.ts index 1a44c1f9..944edc99 100644 --- a/api-helpers/api-hofs.ts +++ b/api-helpers/api-hofs.ts @@ -4,7 +4,7 @@ import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs'; import { object } from 'yup'; import { logger } from './logger'; -import { openConnection } from './prisma/db'; +import { prisma } from './prisma/db'; import { handlePrismaError, isPrismaError } from './prisma/prisma-helper'; import type { Member, PrismaClient, UserRole } from '@prisma/client'; @@ -105,7 +105,6 @@ export const withAsync = ( logger.error(err instanceof Error ? err : { err }); return res.status(500).json(err); } - } finally { } }; }; @@ -119,7 +118,6 @@ export const withDb = ) => (req: R, res: NextApiResponse) => { try { - const prisma = openConnection(); return handler(unsafe__set(req, 'db', prisma), res); } catch (err) { if (isPrismaError(err)) { diff --git a/api-helpers/articles.ts b/api-helpers/articles.ts index 5a85635d..f00a2507 100644 --- a/api-helpers/articles.ts +++ b/api-helpers/articles.ts @@ -7,13 +7,14 @@ import { } from '../constants'; import { HTTPNotFound } from './errors'; - -import type { PrismaClient } from '@prisma/client'; +import { prisma } from './prisma/db'; // https://res.cloudinary.com/polskifrontend/image/fetch -export const getArticlesForGrid = async (prisma: PrismaClient, page: number) => { - const pageNumber = reversePageNumber(page, await getLastBlogPage(prisma)); +export const getArticlesForGrid = async (page: number) => { + const lastBlogPage = await getLastBlogPage(); + const pageNumber = reversePageNumber(page, lastBlogPage); + const blogs = await prisma.blog.findMany({ where: { isPublic: true }, skip: pageNumber * TILES_BLOGS_PER_PAGE, @@ -53,14 +54,14 @@ export const getArticlesForGrid = async (prisma: PrismaClient, page: number) => }; }; -export const getLastArticlePage = async (prisma: PrismaClient) => { +export const getLastArticlePage = async () => { const articlesCount = await prisma.article.count({ where: { blog: { isPublic: true } }, }); return Math.ceil(articlesCount / LIST_ARTICLES_PER_PAGE); }; -export const getLastBlogPage = async (prisma: PrismaClient) => { +export const getLastBlogPage = async () => { const blogCount = await prisma.blog.count({ where: { isPublic: true, lastArticlePublishedAt: { not: null } }, }); @@ -71,8 +72,9 @@ const reversePageNumber = (page: number, lastPage: number): number => { return lastPage - page; }; -export const getArticlesForList = async (prisma: PrismaClient, page: number) => { - const pageNumber = reversePageNumber(page, await getLastArticlePage(prisma)); +export const getArticlesForList = async (page: number) => { + const lastArticlePage = await getLastArticlePage(); + const pageNumber = reversePageNumber(page, lastArticlePage); const articles = await prisma.article.findMany({ skip: pageNumber * LIST_ARTICLES_PER_PAGE, @@ -112,7 +114,7 @@ export const getArticlesForList = async (prisma: PrismaClient, page: number) => }; }; -export const getArticlesSlugs = async (prisma: PrismaClient, limit?: number) => { +export const getArticlesSlugs = async (limit?: number) => { const articles = await prisma.article.findMany({ where: { blog: { isPublic: true }, @@ -129,7 +131,7 @@ export const getArticlesSlugs = async (prisma: PrismaClient, limit?: number) => return articles; }; -export const getArticleBySlug = async (prisma: PrismaClient, slug: string) => { +export const getArticleBySlug = async (slug: string) => { const article = await prisma.article.findFirst({ where: { slug, diff --git a/api-helpers/prisma/db.ts b/api-helpers/prisma/db.ts index 7e061264..f576c954 100644 --- a/api-helpers/prisma/db.ts +++ b/api-helpers/prisma/db.ts @@ -1,37 +1,15 @@ import { PrismaClient } from '@prisma/client'; -import { getConfig } from '../config'; - -// https://www.prisma.io/docs/support/help-articles/nextjs-prisma-client-dev-practices -declare global { - // allow global `var` declarations - // eslint-disable-next-line no-var -- global var required - var prisma: PrismaClient | undefined; - // eslint-disable-next-line no-var -- global var required - var prismaOpenConnections: number; -} -global.prismaOpenConnections = 0; +const getPrisma = () => { + if (process.env.NODE_ENV === 'production') { + return new PrismaClient(); + } -export const openConnection = () => { if (!global.prisma) { - // use pgbouncer - global.prisma = new PrismaClient({ - datasources: { - db: { - url: getConfig('DATABASE_POOL_URL'), - }, - }, - }); + global.prisma = new PrismaClient(); } - ++global.prismaOpenConnections; return global.prisma; }; -export const closeConnection = () => { - --global.prismaOpenConnections; - if (global.prismaOpenConnections === 0) { - return global.prisma?.$disconnect(); - } - return undefined; -}; +export const prisma = getPrisma(); diff --git a/api-helpers/sitemap.ts b/api-helpers/sitemap.ts index 7b25b81f..5f48655c 100644 --- a/api-helpers/sitemap.ts +++ b/api-helpers/sitemap.ts @@ -2,8 +2,6 @@ import { getPagesArray } from '../utils/array-utils'; import { getLastArticlePage, getLastBlogPage, getArticlesSlugs } from './articles'; -import type { PrismaClient } from '@prisma/client'; - type Item = { readonly path: string; readonly changefreq: 'daily' | 'monthly' | 'always' | 'hourly' | 'weekly' | 'yearly' | 'never'; @@ -19,11 +17,11 @@ const staticItems: readonly Item[] = [ { path: '/grid', changefreq: 'hourly', priority: 0.9 }, ]; -export async function getSitemap(prisma: PrismaClient) { +export async function getSitemap() { const [gridLastPage, listLastPage, articleSlugs] = await Promise.all([ - getLastBlogPage(prisma), - getLastArticlePage(prisma), - getArticlesSlugs(prisma), + getLastBlogPage(), + getLastArticlePage(), + getArticlesSlugs(), ]); const gridPages = getPagesArray(gridLastPage); const listPages = getPagesArray(listLastPage); diff --git a/app/(articles)/[displayStyle]/[page]/page.tsx b/app/(articles)/[displayStyle]/[page]/page.tsx index a7b8026a..9d753d31 100644 --- a/app/(articles)/[displayStyle]/[page]/page.tsx +++ b/app/(articles)/[displayStyle]/[page]/page.tsx @@ -1,10 +1,9 @@ import { getLastArticlePage, getLastBlogPage } from '../../../../api-helpers/articles'; -import { openConnection } from '../../../../api-helpers/prisma/db'; import { BlogsGrid } from '../../../../components/BlogsGrid/BlogsGrid'; import { BlogsList } from '../../../../components/BlogsList/BlogsList'; import { getPagesArray } from '../../../../utils/array-utils'; -import type { DisplayStyle } from '../../../../types'; +import type { DisplayStyle } from '../../../../utils/types/types'; const MAX_PAGES = 5; @@ -30,11 +29,9 @@ export default function HomePage({ params }: HomePageProps) { } export const generateStaticParams = async () => { - const prisma = openConnection(); - const [gridLastPage, listLastPage] = await Promise.all([ - await getLastBlogPage(prisma), - await getLastArticlePage(prisma), + await getLastBlogPage(), + await getLastArticlePage(), ]); const gridPages = getPagesArray(gridLastPage, MAX_PAGES); diff --git a/app/(articles)/[displayStyle]/head.tsx b/app/(articles)/[displayStyle]/head.tsx index 1b1875ae..cebc603c 100644 --- a/app/(articles)/[displayStyle]/head.tsx +++ b/app/(articles)/[displayStyle]/head.tsx @@ -1,6 +1,6 @@ import { HeadTags } from '../../../components/HeadTags'; -import type { DisplayStyle } from '../../../types'; +import type { DisplayStyle } from '../../../utils/types/types'; type HeadProps = { readonly params: { diff --git a/app/(articles)/[displayStyle]/layout.tsx b/app/(articles)/[displayStyle]/layout.tsx index 1c1c7ac2..e6496e90 100644 --- a/app/(articles)/[displayStyle]/layout.tsx +++ b/app/(articles)/[displayStyle]/layout.tsx @@ -1,7 +1,7 @@ import { AlgoliaSearch } from '../../../components/AlgoliaSearch/AlgoliaSearch'; import { SwitchDisplayStyle } from '../../../components/SwitchDisplayStyle/SwitchDisplayStyle'; -import type { DisplayStyle } from '../../../types'; +import type { DisplayStyle } from '../../../utils/types/types'; import type { ReactNode } from 'react'; type ArticlesLayoutProps = { diff --git a/app/(content)/admin/[blogsType]/page.tsx b/app/(content)/admin/[blogsType]/page.tsx index 6118878d..fa9d21fa 100644 --- a/app/(content)/admin/[blogsType]/page.tsx +++ b/app/(content)/admin/[blogsType]/page.tsx @@ -7,7 +7,7 @@ import { LogoutButton } from '../../../../components/LogoutButton/LogoutButton'; import { Table } from '../../../../components/Table/Table'; import { fetchAdminBlogsList } from '../../../../utils/fetchAdminBlogsList'; -import type { BlogsType } from '../../../../types'; +import type { BlogsType } from '../../../../utils/types/types'; type AdminPageProps = { readonly params: { diff --git a/app/(content)/admin/blogs/[blogId]/page.tsx b/app/(content)/admin/blogs/[blogId]/page.tsx index 5a529136..c107da04 100644 --- a/app/(content)/admin/blogs/[blogId]/page.tsx +++ b/app/(content)/admin/blogs/[blogId]/page.tsx @@ -1,4 +1,4 @@ -import { openConnection } from '../../../../../api-helpers/prisma/db'; +import { prisma } from '../../../../../api-helpers/prisma/db'; import { ButtonAsLink } from '../../../../../components/ButtonAsLink/ButtonAsLink'; import { Content } from '../../../../../components/Content/Content'; import { ContentNavigation } from '../../../../../components/Content/ContentNavigation'; @@ -42,8 +42,6 @@ export default function AdminBlogPage({ params }: AdminBlogPageProps) { } export const generateStaticParams = async () => { - const prisma = openConnection(); - const blogs = await prisma.blog.findMany(); const paths = blogs.map(({ id }) => ({ blogId: id })); diff --git a/app/(content)/artykuly/[slug]/page.tsx b/app/(content)/artykuly/[slug]/page.tsx index 6ecf893d..a9a91a87 100644 --- a/app/(content)/artykuly/[slug]/page.tsx +++ b/app/(content)/artykuly/[slug]/page.tsx @@ -1,6 +1,5 @@ import { getArticlesSlugs } from '../../../../api-helpers/articles'; import { DEFAULT_ARTICLES } from '../../../../api-helpers/general-feed'; -import { openConnection } from '../../../../api-helpers/prisma/db'; import { ArticleDate } from '../../../../components/ArticleDate/ArticleDate'; import { ButtonAsLink } from '../../../../components/ButtonAsLink/ButtonAsLink'; import { detectContentGenre } from '../../../../utils/creator-utils'; @@ -48,9 +47,5 @@ export default async function ArticlePage({ params }: ArticlePageProps) { } export const generateStaticParams = async () => { - const prisma = openConnection(); - - const articleSlugs = await getArticlesSlugs(prisma, DEFAULT_ARTICLES); - - return articleSlugs; + return await getArticlesSlugs(DEFAULT_ARTICLES); }; diff --git a/components/AlgoliaSearch/AlgoliaHit.tsx b/components/AlgoliaSearch/AlgoliaHit.tsx index f709df26..8e01b81d 100644 --- a/components/AlgoliaSearch/AlgoliaHit.tsx +++ b/components/AlgoliaSearch/AlgoliaHit.tsx @@ -3,7 +3,7 @@ import { memo } from 'react'; import { createExcerpt } from '../../utils/excerpt-utils'; import { ArticleTile } from '../ArticleTile/ArticleTile'; -import type { Article, BlogFromArticle } from '../../types'; +import type { Article, BlogFromArticle } from '../../utils/types/types'; export type Hit = { readonly objectID: string; diff --git a/components/ArticleTile/ArticleTile.tsx b/components/ArticleTile/ArticleTile.tsx index 29881cb2..875ba85b 100644 --- a/components/ArticleTile/ArticleTile.tsx +++ b/components/ArticleTile/ArticleTile.tsx @@ -8,7 +8,7 @@ import { ArticleDate } from '../ArticleDate/ArticleDate'; import Styles from './articleTile.module.scss'; -import type { ArticleFromBlog, BlogFromArticle } from '../../types'; +import type { ArticleFromBlog, BlogFromArticle } from '../../utils/types/types'; type ArticleTileProps = { readonly article: ArticleFromBlog; diff --git a/components/ChangeBlogsList/ChangeBlogsList.tsx b/components/ChangeBlogsList/ChangeBlogsList.tsx index b5a66b2a..0031fb87 100644 --- a/components/ChangeBlogsList/ChangeBlogsList.tsx +++ b/components/ChangeBlogsList/ChangeBlogsList.tsx @@ -2,7 +2,7 @@ import { useRouter } from 'next/navigation'; -import type { BlogsType } from '../../types'; +import type { BlogsType } from '../../utils/types/types'; import type { ChangeEvent } from 'react'; type ChangeBlogsListProps = { diff --git a/components/Pagination/Pagination.tsx b/components/Pagination/Pagination.tsx index ba7501cc..552717f8 100644 --- a/components/Pagination/Pagination.tsx +++ b/components/Pagination/Pagination.tsx @@ -1,6 +1,6 @@ import { ButtonAsLink } from '../ButtonAsLink/ButtonAsLink'; -import type { DisplayStyle } from '../../types'; +import type { DisplayStyle } from '../../utils/types/types'; type PaginationProps = { readonly isFirstPage: boolean; diff --git a/components/Table/Table.tsx b/components/Table/Table.tsx index 425fa012..440f9608 100644 --- a/components/Table/Table.tsx +++ b/components/Table/Table.tsx @@ -1,6 +1,6 @@ import Styles from './table.module.scss'; -import type { AdminTableBlogsRow } from '../../types'; +import type { AdminTableBlogsRow } from '../../utils/types/types'; const columns = [ ['link', 'Link do bloga'], diff --git a/pages/api/sitemap.ts b/pages/api/sitemap.ts index 87678611..6720faf2 100644 --- a/pages/api/sitemap.ts +++ b/pages/api/sitemap.ts @@ -3,8 +3,8 @@ import { getSitemap } from '../../api-helpers/sitemap'; export default withAsync( withMethods({ - GET: withDb(async (req, res) => { - const sitemap = await getSitemap(req.db); + GET: withDb(async (_req, res) => { + const sitemap = await getSitemap(); res.setHeader('Content-Type', 'application/xml; charset=utf-8'); // 900 equals revalidation time (15 minutes) diff --git a/utils/creator-utils.ts b/utils/creator-utils.ts index 92ef9d11..a1e00f84 100644 --- a/utils/creator-utils.ts +++ b/utils/creator-utils.ts @@ -1,4 +1,4 @@ -import type { Article, Blog } from '../types'; +import type { Article, Blog } from './types/types'; // Detect YouTube videos by the article URL const ytRegex = /youtu(\.be|be\.com)\//; diff --git a/utils/fetchAdminBlogsList.tsx b/utils/fetchAdminBlogsList.tsx index cdb1d101..6aff32b9 100644 --- a/utils/fetchAdminBlogsList.tsx +++ b/utils/fetchAdminBlogsList.tsx @@ -1,14 +1,12 @@ import Link from 'next/link'; -import { openConnection } from '../api-helpers/prisma/db'; +import { prisma } from '../api-helpers/prisma/db'; import { formatDate } from './date-utils'; -import type { BlogsType } from '../types'; +import type { BlogsType } from './types/types'; export const fetchAdminBlogsList = async (blogsType: BlogsType | undefined) => { - const prisma = openConnection(); - const blogs = await prisma.blog.findMany({ where: { isPublic: detectBlogsType(blogsType), diff --git a/utils/fetchArticleBySlug.ts b/utils/fetchArticleBySlug.ts index 893bafea..3a81a9ae 100644 --- a/utils/fetchArticleBySlug.ts +++ b/utils/fetchArticleBySlug.ts @@ -2,7 +2,6 @@ import { notFound } from 'next/navigation'; import { getArticleBySlug } from '../api-helpers/articles'; import { HTTPNotFound } from '../api-helpers/errors'; -import { openConnection } from '../api-helpers/prisma/db'; import { addSanitizedDescriptionToArticle } from './sanitize-utils'; @@ -12,9 +11,7 @@ export const fetchArticleBySlug = async (slug: string | undefined) => { } try { - const prisma = openConnection(); - - const article = await getArticleBySlug(prisma, slug); + const article = await getArticleBySlug(slug); const sanitizedArticle = addSanitizedDescriptionToArticle(article); return sanitizedArticle; diff --git a/utils/fetchArticlesForList.ts b/utils/fetchArticlesForList.ts index 3c979785..72523bca 100644 --- a/utils/fetchArticlesForList.ts +++ b/utils/fetchArticlesForList.ts @@ -2,18 +2,15 @@ import { notFound } from 'next/navigation'; import { getArticlesForList, getLastArticlePage } from '../api-helpers/articles'; import { HTTPNotFound } from '../api-helpers/errors'; -import { openConnection } from '../api-helpers/prisma/db'; import { addExcerptToArticle } from './excerpt-utils'; import { pageValidGuard } from './pageValidGuard'; export const fetchArticlesForList = async (page?: string) => { try { - const prisma = openConnection(); - - const lastPage = await getLastArticlePage(prisma); + const lastPage = await getLastArticlePage(); const pageNumber = pageValidGuard(page, lastPage); - const { data: articlesFromDb } = await getArticlesForList(prisma, pageNumber); + const { data: articlesFromDb } = await getArticlesForList(pageNumber); const articles = articlesFromDb.map(addExcerptToArticle); return { diff --git a/utils/fetchBlogsForGrid.ts b/utils/fetchBlogsForGrid.ts index fa48c31b..e42f9a7d 100644 --- a/utils/fetchBlogsForGrid.ts +++ b/utils/fetchBlogsForGrid.ts @@ -2,18 +2,15 @@ import { notFound } from 'next/navigation'; import { getArticlesForGrid, getLastBlogPage } from '../api-helpers/articles'; import { HTTPNotFound } from '../api-helpers/errors'; -import { openConnection } from '../api-helpers/prisma/db'; import { addExcerptToArticle } from './excerpt-utils'; import { pageValidGuard } from './pageValidGuard'; export const fetchBlogsForGrid = async (page?: string) => { try { - const prisma = openConnection(); - - const lastPage = await getLastBlogPage(prisma); + const lastPage = await getLastBlogPage(); const pageNumber = pageValidGuard(page, lastPage); - const { data: blogsFromDb } = await getArticlesForGrid(prisma, pageNumber); + const { data: blogsFromDb } = await getArticlesForGrid(pageNumber); const blogs = blogsFromDb.map((blog) => { return { diff --git a/utils/types/index.d.ts b/utils/types/index.d.ts new file mode 100644 index 00000000..28e2a5a1 --- /dev/null +++ b/utils/types/index.d.ts @@ -0,0 +1,5 @@ +import type { PrismaClient } from '@prisma/client'; + +declare global { + var prisma: PrismaClient; +} diff --git a/types.ts b/utils/types/types.ts similarity index 65% rename from types.ts rename to utils/types/types.ts index 3685421e..a776b59e 100644 --- a/types.ts +++ b/utils/types/types.ts @@ -1,7 +1,7 @@ -import type { fetchAdminBlogsList } from './utils/fetchAdminBlogsList'; -import type { fetchArticlesForList } from './utils/fetchArticlesForList'; -import type { fetchBlogsForGrid } from './utils/fetchBlogsForGrid'; -import type { addSanitizedDescriptionToArticle } from './utils/sanitize-utils'; +import type { fetchAdminBlogsList } from '../fetchAdminBlogsList'; +import type { fetchArticlesForList } from '../fetchArticlesForList'; +import type { fetchBlogsForGrid } from '../fetchBlogsForGrid'; +import type { addSanitizedDescriptionToArticle } from '../sanitize-utils'; export type SanitizedArticle = ReturnType; export type Article = Awaited>['articles'][number];