search, db integration

This commit is contained in:
2026-06-05 21:47:00 -04:00
parent 365d1281dd
commit 71d7a9d6f0
25 changed files with 1573 additions and 244 deletions

View File

@@ -0,0 +1,94 @@
/**
* Browse API — fetches plants with disease counts from the Turso DB
* for the browse page. Runs server-side only.
*/
import { sql, eq } from "drizzle-orm";
import { getDb } from "@/lib/db/index";
import { plants, diseases } from "@/lib/db/schema";
import type { PlantCardData } from "@/components/PlantCard";
export type { PlantCardData };
/**
* Get all plants with their disease counts for the browse page.
*/
export async function getBrowsePlants(): Promise<PlantCardData[]> {
const db = getDb();
// LEFT JOIN to include plants with zero diseases
const rows = await db
.select({
id: plants.id,
commonName: plants.commonName,
scientificName: plants.scientificName,
family: plants.family,
category: plants.category,
diseaseCount: sql<number>`COUNT(${diseases.id})`,
})
.from(plants)
.leftJoin(diseases, eq(diseases.plantId, plants.id))
.groupBy(plants.id)
.orderBy(plants.commonName);
return rows.map((r) => ({
id: r.id,
commonName: r.commonName,
scientificName: r.scientificName,
family: r.family,
category: r.category,
diseaseCount: r.diseaseCount,
}));
}
/**
* Get a single plant with disease count (for detail page lookups).
*/
export async function getBrowsePlant(id: string): Promise<PlantCardData | null> {
const db = getDb();
const rows = await db
.select({
id: plants.id,
commonName: plants.commonName,
scientificName: plants.scientificName,
family: plants.family,
category: plants.category,
diseaseCount: sql<number>`COUNT(${diseases.id})`,
})
.from(plants)
.leftJoin(diseases, eq(diseases.plantId, plants.id))
.where(eq(plants.id, id))
.groupBy(plants.id)
.limit(1);
return rows[0] ?? null;
}
/**
* Get featured plants for the homepage (subset).
*/
const FEATURED_IDS = [
"tomato",
"basil",
"rose",
"monstera",
"snake-plant",
"pepper",
"apple",
"corn",
"wheat",
"strawberry",
"blueberry",
"lettuce",
];
export async function getFeaturedPlants(): Promise<PlantCardData[]> {
const all = await getBrowsePlants();
const featured = all.filter((p) => FEATURED_IDS.includes(p.id));
// If fewer than expected are found, pad with first available plants
if (featured.length < 6) {
const rest = all.filter((p) => !FEATURED_IDS.includes(p.id));
return [...featured, ...rest].slice(0, 12);
}
return featured.slice(0, 12);
}