From d77d08bdad57b4e0d180c3069c859bd3683cb1c1 Mon Sep 17 00:00:00 2001 From: abhitrueprogrammer Date: Tue, 12 Aug 2025 15:28:43 +0530 Subject: [PATCH 1/2] mongo db multiple connections fix --- src/lib/mongoose.ts | 48 +++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/lib/mongoose.ts b/src/lib/mongoose.ts index 7f129fe..7be32c3 100644 --- a/src/lib/mongoose.ts +++ b/src/lib/mongoose.ts @@ -1,27 +1,41 @@ import mongoose from "mongoose"; - -if (!process.env.MONGODB_URI) { - throw new Error("Please add your Mongo URI to .env.local"); +declare global { + // eslint-disable-next-line no-var + var mongoose: { conn: mongoose.Mongoose | null; promise: Promise | null } | undefined; // This must be a `var` and not a `let / const` } -const uri = process.env.MONGODB_URI; +let cached = global.mongoose; -let isConnected = false; +cached ??= global.mongoose = { conn: null, promise: null }; -export const connectToDatabase = async () => { - if (isConnected) { - return; - } +export async function connectToDatabase() { + const MONGODB_URI = process.env.MONGODB_URI!; - if (mongoose.connection.readyState === mongoose.ConnectionStates.connected) { - isConnected = true; - return; + if (!MONGODB_URI) { + throw new Error( + "Please define the MONGODB_URI environment variable inside .env.local", + ); } + if (cached?.conn) { + return cached.conn; + } + if (cached && !cached.promise) { + const opts = { + bufferCommands: false, + }; + cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => { + return mongoose; + }); + } try { - await mongoose.connect(uri); - isConnected = true; - } catch (error) { - throw new Error("Failed to connect to MongoDB"); + cached!.conn = await cached!.promise; + } catch (e) { + if (cached) { + cached.promise = null; + } + throw e; } -}; + + return cached?.conn; +} From 023a0ddc28f834085d91991edf1f5b00a045fe21 Mon Sep 17 00:00:00 2001 From: abhitrueprogrammer Date: Wed, 13 Aug 2025 03:28:39 +0530 Subject: [PATCH 2/2] feat: related subs --- src/app/api/related-subject/route.ts | 41 ++++++++++++++++ src/components/CatalogueContent.tsx | 73 +++++++++++++++++++++------- src/db/relatedSubjects.ts | 14 ++++++ src/interface.ts | 6 +++ 4 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 src/app/api/related-subject/route.ts create mode 100644 src/db/relatedSubjects.ts diff --git a/src/app/api/related-subject/route.ts b/src/app/api/related-subject/route.ts new file mode 100644 index 0000000..1640f9e --- /dev/null +++ b/src/app/api/related-subject/route.ts @@ -0,0 +1,41 @@ +import { NextResponse, type NextRequest } from "next/server"; +import { connectToDatabase } from "@/lib/mongoose"; +import { IRelatedSubject } from "@/interface"; +import RelatedSubject from "@/db/relatedSubjects"; + +export const dynamic = "force-dynamic"; + +export async function GET(req: NextRequest) { + try { + await connectToDatabase(); + const url = req.nextUrl.searchParams; + const subject = url.get("subject"); + const escapeRegExp = (text: string) => { + return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + }; + const escapedSubject = escapeRegExp(subject ?? ""); + + if (!subject) { + return NextResponse.json( + { message: "Subject query parameter is required" }, + { status: 400 }, + ); + } + const subjects: IRelatedSubject[] = await RelatedSubject.find({ + subject: { $regex: new RegExp(`${escapedSubject}`, "i") }, + }); + console.log("realted", subjects); + + return NextResponse.json( + { + related_subjects: subjects[0]?.related_subjects + }, + { status: 200 }, + ); + } catch (error) { + return NextResponse.json( + { message: "Failed to fetch related subject", error }, + { status: 500 }, + ); + } +} diff --git a/src/components/CatalogueContent.tsx b/src/components/CatalogueContent.tsx index a17c8ed..8891ca7 100644 --- a/src/components/CatalogueContent.tsx +++ b/src/components/CatalogueContent.tsx @@ -4,7 +4,7 @@ import { useSearchParams } from "next/navigation"; import { useCallback, useEffect, useState } from "react"; import axios, { type AxiosError } from "axios"; import { Button } from "@/components/ui/button"; -import { type IPaper, type Filters } from "@/interface"; +import { type IPaper, type Filters, IRelatedSubject, StoredSubjects } from "@/interface"; import Card from "./Card"; import { useRouter } from "next/navigation"; import Loader from "./ui/loader"; @@ -13,8 +13,8 @@ import Error from "./Error"; import { Filter } from "lucide-react"; import { Sheet, SheetContent, SheetTrigger } from "./ui/sheet"; import { Pin } from "lucide-react"; -import { StoredSubjects } from "@/interface"; import { getSecureUrl, generateFileName, downloadFile } from "@/util/download"; +import Link from "next/link"; const CatalogueContent = () => { const router = useRouter(); @@ -39,6 +39,29 @@ const CatalogueContent = () => { const [filtersPulled, setFiltersPulled] = useState(false); const [appliedFilters, setAppliedFilters] = useState(false); const [pinned, setPinned] = useState(false); + const [relatedSubjects, setRelatedSubjects] = useState([]); + // Fetch related subjects when subject changes + useEffect(() => { + if (!subject) return; + const fetchRelatedSubjects = async () => { + try { + const res = await axios.get<{related_subjects: string []}>("/api/related-subject", { + params: { subject }, + }); + console.log(res.data) + const data = res.data.related_subjects; + console.log("data" , data[0], data[1]); + if (data && data.length > 0) { + setRelatedSubjects(data); + } else { + setRelatedSubjects([]); + } + } catch (e) { + setRelatedSubjects([]); + } + }; + void fetchRelatedSubjects(); + }, [subject]); // Set initial state from searchParams on client-side mount useEffect(() => { @@ -317,22 +340,38 @@ const CatalogueContent = () => { -
-
-

- {subject?.split("[")[1]?.replace("]", "")} -

-

- {subject?.split(" [")[0]} -

-
-
- +
+
+
+

+ {subject?.split("[")[1]?.replace("]", "")} +

+

+ {subject?.split(" [")[0]} +

+
+
+ +
+ {relatedSubjects.length > 0 && ( +
+ Related subjects: + {relatedSubjects.map((sub) => ( + + {sub} + + ))} +
+ )}
{loading ? ( diff --git a/src/db/relatedSubjects.ts b/src/db/relatedSubjects.ts new file mode 100644 index 0000000..c9a4c27 --- /dev/null +++ b/src/db/relatedSubjects.ts @@ -0,0 +1,14 @@ +import mongoose, { Schema, type Model } from "mongoose"; +import { type IRelatedSubject } from "@/interface"; + + +const relatedSubjectSchema = new Schema({ + subject: { type: String, required: true }, + related_subjects: { type: [String], required: true }, +}); + +const RelatedSubject: Model = + mongoose.models.RelatedSubject ?? + mongoose.model("RelatedSubject", relatedSubjectSchema); + +export default RelatedSubject; diff --git a/src/interface.ts b/src/interface.ts index 2ee6030..c8362da 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -209,3 +209,9 @@ export interface TransformedPaper { subject: string; slots: string[]; } + + +export interface IRelatedSubject { + subject: string; + related_subjects: string[]; +} \ No newline at end of file