scaffold: Next.js 15 + Drizzle + Better Auth + OpenAI + Recharts base
This commit is contained in:
114
src/app/actions/comparison.ts
Normal file
114
src/app/actions/comparison.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
"use server";
|
||||
|
||||
import { db } from "@/lib/db";
|
||||
import { comparisons, comparisonItems } from "@/lib/db/schema";
|
||||
import type { ComparisonData } from "@/lib/types";
|
||||
import { eq, desc, and } from "drizzle-orm";
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
|
||||
export async function createComparison(formData: FormData) {
|
||||
const query = formData.get("query") as string;
|
||||
const itemsRaw = formData.get("items") as string;
|
||||
|
||||
if (!query || !itemsRaw) {
|
||||
return { error: "Query and items are required" };
|
||||
}
|
||||
|
||||
const items: string[] = JSON.parse(itemsRaw);
|
||||
if (!Array.isArray(items) || items.length < 2) {
|
||||
return { error: "At least 2 items are required" };
|
||||
}
|
||||
|
||||
const id = createId();
|
||||
const title =
|
||||
(formData.get("title") as string) ||
|
||||
`Comparing ${items.join(" vs ")}`;
|
||||
const slug =
|
||||
title
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-|-$/g, "")
|
||||
.slice(0, 200) + `-${id.slice(-6)}`;
|
||||
|
||||
await db.insert(comparisons).values({
|
||||
id,
|
||||
title,
|
||||
query,
|
||||
slug,
|
||||
status: "researching",
|
||||
});
|
||||
|
||||
return { id, slug };
|
||||
}
|
||||
|
||||
export async function getComparison(
|
||||
slug: string
|
||||
): Promise<ComparisonData | null> {
|
||||
const result = await db
|
||||
.select()
|
||||
.from(comparisons)
|
||||
.where(eq(comparisons.slug, slug))
|
||||
.limit(1);
|
||||
|
||||
if (!result.length) return null;
|
||||
|
||||
const comparison = result[0];
|
||||
const items = await db
|
||||
.select()
|
||||
.from(comparisonItems)
|
||||
.where(eq(comparisonItems.comparisonId, comparison.id))
|
||||
.orderBy(comparisonItems.order);
|
||||
|
||||
return {
|
||||
id: comparison.id,
|
||||
userId: comparison.userId || "",
|
||||
title: comparison.title,
|
||||
query: comparison.query || "",
|
||||
slug: comparison.slug,
|
||||
status: comparison.status as ComparisonData["status"],
|
||||
summary: comparison.summary || "",
|
||||
items: items.map((item) => ({
|
||||
name: item.name,
|
||||
description: item.description || "",
|
||||
overallScore:
|
||||
(item.scores as Record<string, unknown>)?.overallScore as number ?? 0,
|
||||
dimensions:
|
||||
(item.scores as Record<string, unknown>)?.dimensions as Record<
|
||||
string,
|
||||
{ score: number; summary: string; details: string; pros?: string[]; cons?: string[] }
|
||||
> ?? {},
|
||||
pros: item.pros || [],
|
||||
cons: item.cons || [],
|
||||
})),
|
||||
dimensions:
|
||||
(comparison.overallData as Record<string, unknown>)?.dimensions as string[] ??
|
||||
[],
|
||||
tags: comparison.tags || [],
|
||||
isPublic: comparison.isPublic ?? false,
|
||||
viewCount: comparison.viewCount ?? 0,
|
||||
createdAt: comparison.createdAt.toISOString(),
|
||||
updatedAt: comparison.updatedAt.toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
export async function getUserComparisons(userId: string) {
|
||||
return db
|
||||
.select()
|
||||
.from(comparisons)
|
||||
.where(eq(comparisons.userId, userId))
|
||||
.orderBy(desc(comparisons.createdAt));
|
||||
}
|
||||
|
||||
export async function getPublicComparisons(limit = 20) {
|
||||
return db
|
||||
.select()
|
||||
.from(comparisons)
|
||||
.where(
|
||||
and(
|
||||
eq(comparisons.isPublic, true),
|
||||
eq(comparisons.status, "completed")
|
||||
)
|
||||
)
|
||||
.orderBy(desc(comparisons.createdAt))
|
||||
.limit(limit);
|
||||
}
|
||||
Reference in New Issue
Block a user