feat(01-02): implement item, category, and totals service layers
- Item CRUD: getAllItems with category join, getById, create, update, delete - Category CRUD: getAll ordered by name, create, update, delete with reassignment - Totals: per-category aggregates and global totals via SQL SUM/COUNT - All 20 service tests passing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
32
src/server/services/totals.service.ts
Normal file
32
src/server/services/totals.service.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import { items, categories } from "../../db/schema.ts";
|
||||
import { db as prodDb } from "../../db/index.ts";
|
||||
|
||||
type Db = typeof prodDb;
|
||||
|
||||
export function getCategoryTotals(db: Db = prodDb) {
|
||||
return db
|
||||
.select({
|
||||
categoryId: items.categoryId,
|
||||
categoryName: categories.name,
|
||||
categoryEmoji: categories.emoji,
|
||||
totalWeight: sql<number>`COALESCE(SUM(${items.weightGrams}), 0)`,
|
||||
totalCost: sql<number>`COALESCE(SUM(${items.priceCents}), 0)`,
|
||||
itemCount: sql<number>`COUNT(*)`,
|
||||
})
|
||||
.from(items)
|
||||
.innerJoin(categories, eq(items.categoryId, categories.id))
|
||||
.groupBy(items.categoryId)
|
||||
.all();
|
||||
}
|
||||
|
||||
export function getGlobalTotals(db: Db = prodDb) {
|
||||
return db
|
||||
.select({
|
||||
totalWeight: sql<number>`COALESCE(SUM(${items.weightGrams}), 0)`,
|
||||
totalCost: sql<number>`COALESCE(SUM(${items.priceCents}), 0)`,
|
||||
itemCount: sql<number>`COUNT(*)`,
|
||||
})
|
||||
.from(items)
|
||||
.get();
|
||||
}
|
||||
Reference in New Issue
Block a user