diff --git a/src/server/services/manufacturer.service.ts b/src/server/services/manufacturer.service.ts new file mode 100644 index 0000000..d9caeed --- /dev/null +++ b/src/server/services/manufacturer.service.ts @@ -0,0 +1,42 @@ +import { asc, eq } from "drizzle-orm"; +import { db as prodDb } from "../../db/index.ts"; +import { manufacturers } from "../../db/schema.ts"; + +type Db = typeof prodDb; + +export type CreateManufacturerInput = { + name: string; + slug: string; + website: string; + tier?: number; + country?: string; +}; + +export async function listManufacturers(db: Db = prodDb) { + return db.select().from(manufacturers).orderBy(asc(manufacturers.name)); +} + +export async function getManufacturerBySlug(db: Db = prodDb, slug: string) { + const [row] = await db + .select() + .from(manufacturers) + .where(eq(manufacturers.slug, slug)); + return row ?? null; +} + +export async function createManufacturer( + db: Db = prodDb, + data: CreateManufacturerInput, +) { + const [row] = await db + .insert(manufacturers) + .values({ + name: data.name, + slug: data.slug, + website: data.website, + tier: data.tier ?? 1, + country: data.country ?? null, + }) + .returning(); + return row!; +} diff --git a/tests/helpers/db.ts b/tests/helpers/db.ts index fa7c093..6a181de 100644 --- a/tests/helpers/db.ts +++ b/tests/helpers/db.ts @@ -25,6 +25,8 @@ const TRUNCATE_TABLES = [ "setups", "thread_candidates", "threads", + "community_prices", + "market_prices", "items", "global_item_tags", "global_items", @@ -35,6 +37,7 @@ const TRUNCATE_TABLES = [ "api_keys", "settings", "categories", + "manufacturers", "users", ]; diff --git a/tests/services/manufacturer.service.test.ts b/tests/services/manufacturer.service.test.ts new file mode 100644 index 0000000..4caac91 --- /dev/null +++ b/tests/services/manufacturer.service.test.ts @@ -0,0 +1,72 @@ +import { beforeEach, describe, expect, it } from "bun:test"; +import { manufacturers } from "../../src/db/schema.ts"; +import { + createManufacturer, + getManufacturerBySlug, + listManufacturers, +} from "../../src/server/services/manufacturer.service.ts"; +import { createTestDb } from "../helpers/db.ts"; + +let db: Awaited>["db"]; + +beforeEach(async () => { + ({ db } = await createTestDb()); +}); + +describe("createManufacturer", () => { + it("inserts a manufacturer and returns it", async () => { + const result = await createManufacturer(db, { + name: "Apidura", + slug: "apidura", + website: "https://apidura.com", + tier: 1, + country: "GB", + }); + expect(result.id).toBeGreaterThan(0); + expect(result.name).toBe("Apidura"); + expect(result.slug).toBe("apidura"); + expect(result.active).toBe(true); + }); + + it("throws on duplicate slug", async () => { + await createManufacturer(db, { + name: "Apidura", + slug: "apidura", + website: "https://apidura.com", + }); + await expect( + createManufacturer(db, { + name: "Apidura Copy", + slug: "apidura", + website: "https://other.com", + }), + ).rejects.toThrow(); + }); +}); + +describe("getManufacturerBySlug", () => { + it("returns manufacturer when found", async () => { + await createManufacturer(db, { + name: "Revelate Designs", + slug: "revelate-designs", + website: "https://revelatedesigns.com", + }); + const result = await getManufacturerBySlug(db, "revelate-designs"); + expect(result?.name).toBe("Revelate Designs"); + }); + + it("returns null when not found", async () => { + const result = await getManufacturerBySlug(db, "nope"); + expect(result).toBeNull(); + }); +}); + +describe("listManufacturers", () => { + it("returns all manufacturers ordered by name", async () => { + await createManufacturer(db, { name: "Ortlieb", slug: "ortlieb", website: "https://ortlieb.com" }); + await createManufacturer(db, { name: "Apidura", slug: "apidura", website: "https://apidura.com" }); + const result = await listManufacturers(db); + expect(result[0]?.name).toBe("Apidura"); + expect(result[1]?.name).toBe("Ortlieb"); + }); +});