Merge branch 'feat/api-endpoints'
This commit is contained in:
24
src/app/api/comparisons/[slug]/route.ts
Normal file
24
src/app/api/comparisons/[slug]/route.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { db } from "@/lib/db";
|
||||
import { comparisons } from "@/lib/db/schema";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import { getComparison } from "@/app/actions/comparison";
|
||||
|
||||
export async function GET(
|
||||
_request: Request,
|
||||
{ params }: { params: Promise<{ slug: string }> }
|
||||
) {
|
||||
const { slug } = await params;
|
||||
|
||||
await db
|
||||
.update(comparisons)
|
||||
.set({ viewCount: sql`${comparisons.viewCount} + 1` })
|
||||
.where(eq(comparisons.slug, slug));
|
||||
|
||||
const comparison = await getComparison(slug);
|
||||
|
||||
if (!comparison) {
|
||||
return Response.json({ error: "Not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
return Response.json(comparison);
|
||||
}
|
||||
65
src/app/api/comparisons/route.ts
Normal file
65
src/app/api/comparisons/route.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { db } from "@/lib/db";
|
||||
import { comparisons, comparisonItems } from "@/lib/db/schema";
|
||||
import { eq, and, desc, ilike, sql, inArray } from "drizzle-orm";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const page = Math.max(1, Number(searchParams.get("page")) || 1);
|
||||
const limit = Math.min(100, Math.max(1, Number(searchParams.get("limit")) || 20));
|
||||
const search = searchParams.get("search") || "";
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
const conditions = [eq(comparisons.isPublic, true), eq(comparisons.status, "completed")];
|
||||
if (search) {
|
||||
conditions.push(ilike(comparisons.title, `%${search}%`));
|
||||
}
|
||||
|
||||
const where = and(...conditions);
|
||||
|
||||
const [result, countResult] = await Promise.all([
|
||||
db
|
||||
.select()
|
||||
.from(comparisons)
|
||||
.where(where)
|
||||
.orderBy(desc(comparisons.createdAt))
|
||||
.limit(limit)
|
||||
.offset(offset),
|
||||
db
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
.from(comparisons)
|
||||
.where(where),
|
||||
]);
|
||||
|
||||
const total = countResult[0].count;
|
||||
|
||||
const comparisonIds = result.map((c) => c.id);
|
||||
const itemsMap: Record<string, string[]> = {};
|
||||
|
||||
if (comparisonIds.length > 0) {
|
||||
const items = await db
|
||||
.select({
|
||||
comparisonId: comparisonItems.comparisonId,
|
||||
name: comparisonItems.name,
|
||||
})
|
||||
.from(comparisonItems)
|
||||
.where(inArray(comparisonItems.comparisonId, comparisonIds));
|
||||
|
||||
for (const item of items) {
|
||||
if (!itemsMap[item.comparisonId]) itemsMap[item.comparisonId] = [];
|
||||
itemsMap[item.comparisonId].push(item.name);
|
||||
}
|
||||
}
|
||||
|
||||
const data = result.map((c) => ({
|
||||
id: c.id,
|
||||
title: c.title,
|
||||
summary: (c.summary || "").slice(0, 200),
|
||||
slug: c.slug,
|
||||
tags: c.tags || [],
|
||||
items: itemsMap[c.id] || [],
|
||||
viewCount: c.viewCount ?? 0,
|
||||
createdAt: c.createdAt.toISOString(),
|
||||
}));
|
||||
|
||||
return Response.json({ comparisons: data, total, page, limit });
|
||||
}
|
||||
69
src/app/api/user/comparisons/route.ts
Normal file
69
src/app/api/user/comparisons/route.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { db } from "@/lib/db";
|
||||
import { comparisons, comparisonItems } from "@/lib/db/schema";
|
||||
import { eq, desc, sql, inArray } from "drizzle-orm";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { headers } from "next/headers";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
|
||||
if (!session?.user) {
|
||||
return Response.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
const page = Math.max(1, Number(searchParams.get("page")) || 1);
|
||||
const limit = Math.min(100, Math.max(1, Number(searchParams.get("limit")) || 20));
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
const where = eq(comparisons.userId, session.user.id);
|
||||
|
||||
const [result, countResult] = await Promise.all([
|
||||
db
|
||||
.select()
|
||||
.from(comparisons)
|
||||
.where(where)
|
||||
.orderBy(desc(comparisons.createdAt))
|
||||
.limit(limit)
|
||||
.offset(offset),
|
||||
db
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
.from(comparisons)
|
||||
.where(where),
|
||||
]);
|
||||
|
||||
const total = countResult[0].count;
|
||||
|
||||
const comparisonIds = result.map((c) => c.id);
|
||||
const itemsMap: Record<string, string[]> = {};
|
||||
|
||||
if (comparisonIds.length > 0) {
|
||||
const items = await db
|
||||
.select({
|
||||
comparisonId: comparisonItems.comparisonId,
|
||||
name: comparisonItems.name,
|
||||
})
|
||||
.from(comparisonItems)
|
||||
.where(inArray(comparisonItems.comparisonId, comparisonIds));
|
||||
|
||||
for (const item of items) {
|
||||
if (!itemsMap[item.comparisonId]) itemsMap[item.comparisonId] = [];
|
||||
itemsMap[item.comparisonId].push(item.name);
|
||||
}
|
||||
}
|
||||
|
||||
const data = result.map((c) => ({
|
||||
id: c.id,
|
||||
title: c.title,
|
||||
summary: (c.summary || "").slice(0, 200),
|
||||
slug: c.slug,
|
||||
tags: c.tags || [],
|
||||
items: itemsMap[c.id] || [],
|
||||
viewCount: c.viewCount ?? 0,
|
||||
status: c.status,
|
||||
isPublic: c.isPublic,
|
||||
createdAt: c.createdAt.toISOString(),
|
||||
}));
|
||||
|
||||
return Response.json({ comparisons: data, total, page, limit });
|
||||
}
|
||||
23
src/app/api/user/stats/route.ts
Normal file
23
src/app/api/user/stats/route.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { db } from "@/lib/db";
|
||||
import { comparisons } from "@/lib/db/schema";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { headers } from "next/headers";
|
||||
|
||||
export async function GET() {
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
|
||||
if (!session?.user) {
|
||||
return Response.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
const result = await db
|
||||
.select({
|
||||
totalComparisons: sql<number>`count(*)`,
|
||||
totalViews: sql<number>`coalesce(sum(${comparisons.viewCount}), 0)`,
|
||||
})
|
||||
.from(comparisons)
|
||||
.where(eq(comparisons.userId, session.user.id));
|
||||
|
||||
return Response.json(result[0]);
|
||||
}
|
||||
Reference in New Issue
Block a user