Merge branch 'feat/api-endpoints'

This commit is contained in:
Christopher Mayor
2026-04-26 15:58:04 -07:00
4 changed files with 181 additions and 0 deletions

View 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);
}

View 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 });
}

View 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 });
}

View 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]);
}