feat(16-02): add userId scoping to item, category, totals, and CSV services
- All functions accept userId as second parameter, no more prodDb defaults - All queries filter by eq(table.userId, userId) for data isolation - Get-by-id, update, delete use and() for composite id+userId conditions - deleteCategory uses dynamic getOrCreateUncategorized(db, userId) not hardcoded ID - CSV import scopes category lookup/creation and item creation to userId - CSV export filters items by userId - Category service converted from sync SQLite to async Postgres patterns
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import { and, eq, sql } from "drizzle-orm";
|
||||
import { db as prodDb } from "../../db/index.ts";
|
||||
import { categories, items } from "../../db/schema.ts";
|
||||
|
||||
type Db = typeof prodDb;
|
||||
|
||||
export async function getCategoryTotals(db: Db = prodDb) {
|
||||
export async function getCategoryTotals(db: Db, userId: number) {
|
||||
return db
|
||||
.select({
|
||||
categoryId: items.categoryId,
|
||||
@@ -16,17 +16,19 @@ export async function getCategoryTotals(db: Db = prodDb) {
|
||||
})
|
||||
.from(items)
|
||||
.innerJoin(categories, eq(items.categoryId, categories.id))
|
||||
.where(eq(items.userId, userId))
|
||||
.groupBy(items.categoryId, categories.name, categories.icon);
|
||||
}
|
||||
|
||||
export async function getGlobalTotals(db: Db = prodDb) {
|
||||
export async function getGlobalTotals(db: Db, userId: number) {
|
||||
const [row] = await db
|
||||
.select({
|
||||
totalWeight: sql<number>`COALESCE(SUM(${items.weightGrams} * ${items.quantity}), 0)`,
|
||||
totalCost: sql<number>`COALESCE(SUM(${items.priceCents} * ${items.quantity}), 0)`,
|
||||
itemCount: sql<number>`COUNT(*)`,
|
||||
})
|
||||
.from(items);
|
||||
.from(items)
|
||||
.where(eq(items.userId, userId));
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user