fix(14): revise plans based on checker feedback
This commit is contained in:
@@ -90,7 +90,7 @@ Conversion rules (apply to ALL service files):
|
||||
<action>
|
||||
Convert each service file following the async conversion rules. Read each file fully before modifying.
|
||||
|
||||
**item.service.ts** — 5 exported functions (getAllItems, getItemById, createItem, updateItem, duplicateItem, deleteItem):
|
||||
**item.service.ts** -- 5 exported functions (getAllItems, getItemById, createItem, updateItem, duplicateItem, deleteItem):
|
||||
- `getAllItems`: `async`, remove `.all()`, `return await db.select()...`
|
||||
- `getItemById`: `async`, replace `.get() ?? null` with `const [row] = await db.select()...; return row ?? null`
|
||||
- `createItem`: `async`, replace `.returning().get()` with `const [row] = await db.insert()...returning(); return row`
|
||||
@@ -98,29 +98,29 @@ Convert each service file following the async conversion rules. Read each file f
|
||||
- `duplicateItem`: `async`, same pattern as createItem
|
||||
- `deleteItem`: `async`, existence check `const [item] = await db.select()...`, delete `await db.delete()...`
|
||||
|
||||
**category.service.ts** — Has a transaction in `deleteCategory` (moves items to Uncategorized then deletes):
|
||||
**category.service.ts** -- Has a transaction in `deleteCategory` (moves items to Uncategorized then deletes):
|
||||
- All functions: `async`
|
||||
- Transaction: `await db.transaction(async (tx) => { await tx.update()...; await tx.delete()...; })`
|
||||
- All `.all()` -> remove, `.get()` -> destructure, `.run()` -> remove
|
||||
|
||||
**thread.service.ts** — Has transactions in `resolveThread` and `unresolveThread`:
|
||||
**thread.service.ts** -- Has transactions in `resolveThread` and `unresolveThread`:
|
||||
- All functions: `async`
|
||||
- `resolveThread` transaction: `await db.transaction(async (tx) => { ... })` with all inner operations awaited
|
||||
- `unresolveThread` transaction: same pattern
|
||||
- `.all()` -> remove, `.get()` -> destructure, `.run()` -> remove
|
||||
- `.returning().get()` -> `const [row] = await ...returning()`
|
||||
|
||||
**setup.service.ts** — Has a transaction in `updateSetupItems` (delete all + re-insert):
|
||||
**setup.service.ts** -- Has a transaction in `updateSetupItems` (delete all + re-insert):
|
||||
- All functions: `async`
|
||||
- Transaction: `await db.transaction(async (tx) => { await tx.delete()...; for (const item of items) { await tx.insert()...; } })`
|
||||
- `.all()` -> remove, `.get()` -> destructure, `.run()` -> remove
|
||||
|
||||
**totals.service.ts** — Read-only aggregate queries:
|
||||
**totals.service.ts** -- Read-only aggregate queries:
|
||||
- All functions: `async`
|
||||
- Remove `.all()`, `.get()` -> destructure
|
||||
</action>
|
||||
<verify>
|
||||
<automated>! grep -n "\.all()\|\.get()\|\.run()" src/server/services/item.service.ts src/server/services/category.service.ts src/server/services/thread.service.ts src/server/services/setup.service.ts src/server/services/totals.service.ts && grep -c "async function" src/server/services/item.service.ts | grep -q "[3-9]" && echo "PASS" || echo "FAIL"</automated>
|
||||
<automated>! grep -n "\.all()\|\.get()\|\.run()" src/server/services/item.service.ts src/server/services/category.service.ts src/server/services/thread.service.ts src/server/services/setup.service.ts src/server/services/totals.service.ts && grep -c "async function" src/server/services/item.service.ts | grep -q "[3-9]" && bun run lint 2>&1 | tail -3 && echo "PASS" || echo "FAIL"</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- item.service.ts: every exported function starts with `export async function`
|
||||
@@ -135,30 +135,30 @@ Convert each service file following the async conversion rules. Read each file f
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Convert auth/oauth/csv/image services and update server index</name>
|
||||
<name>Task 2: Convert auth/oauth/csv/image services, update server index, and run PGlite smoke test</name>
|
||||
<files>src/server/services/auth.service.ts, src/server/services/oauth.service.ts, src/server/services/csv.service.ts, src/server/services/image.service.ts, src/server/index.ts</files>
|
||||
<read_first>src/server/services/auth.service.ts, src/server/services/oauth.service.ts, src/server/services/csv.service.ts, src/server/services/image.service.ts, src/server/index.ts</read_first>
|
||||
<action>
|
||||
**auth.service.ts** — User and session management:
|
||||
**auth.service.ts** -- User and session management:
|
||||
- All functions: `async`
|
||||
- Remove `.all()`, `.get()` -> destructure, `.run()` -> remove
|
||||
- `.returning().get()` -> `const [row] = await ...returning()`
|
||||
- Pay attention to boolean checks on `oauthCodes.used` — the column is now native `boolean` (true/false), not integer (0/1). If any code checks `=== 0` or `=== 1` for the `used` field, change to `=== false` or `=== true`.
|
||||
- Pay attention to boolean checks on `oauthCodes.used` -- the column is now native `boolean` (true/false), not integer (0/1). If any code checks `=== 0` or `=== 1` for the `used` field, change to `=== false` or `=== true`.
|
||||
|
||||
**oauth.service.ts** — OAuth client, code, token management:
|
||||
**oauth.service.ts** -- OAuth client, code, token management:
|
||||
- All functions: `async`
|
||||
- Same conversion patterns
|
||||
- IMPORTANT: The `used` column on `oauthCodes` is now `boolean` type. Any `.set({ used: 1 })` must become `.set({ used: true })`. Any `.where(eq(oauthCodes.used, 0))` must become `.where(eq(oauthCodes.used, false))`.
|
||||
|
||||
**csv.service.ts** — CSV export:
|
||||
**csv.service.ts** -- CSV export:
|
||||
- All functions: `async`
|
||||
- This is read-only, straightforward `.all()` removal
|
||||
|
||||
**image.service.ts** — Image handling:
|
||||
**image.service.ts** -- Image handling:
|
||||
- All functions: `async`
|
||||
- Same conversion patterns. May have fewer DB calls than other services.
|
||||
|
||||
**src/server/index.ts** — Server startup:
|
||||
**src/server/index.ts** -- Server startup:
|
||||
- Change `seedDefaults()` to `await seedDefaults()` at the top level
|
||||
- Since the file is a module (ESM), top-level await is supported. Wrap the seed call:
|
||||
```typescript
|
||||
@@ -167,22 +167,39 @@ Convert each service file following the async conversion rules. Read each file f
|
||||
```
|
||||
- If the file structure does not support top-level await cleanly (e.g., exports are synchronous), wrap in an async IIFE or move the await before the export.
|
||||
- The `seedDefaults` import already points to the async version from Plan 01.
|
||||
|
||||
**After all conversions, run a PGlite smoke test to verify at least one service works end-to-end:**
|
||||
```bash
|
||||
bun -e "
|
||||
import { createTestDb } from './tests/helpers/db.ts';
|
||||
import * as schema from './src/db/schema.ts';
|
||||
const db = await createTestDb();
|
||||
// Test a basic item service operation
|
||||
const { createItem } = await import('./src/server/services/item.service.ts');
|
||||
const [cat] = await db.select().from(schema.categories);
|
||||
const item = await createItem(db as any, { name: 'Smoke Test', categoryId: cat.id, quantity: 1 });
|
||||
if (!item || !item.id) { console.error('FAIL: createItem returned no result'); process.exit(1); }
|
||||
console.log('Service smoke test PASSED: item created with id', item.id);
|
||||
"
|
||||
```
|
||||
This validates that the async conversion is actually functional, not just structurally correct.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>! grep -n "\.all()\|\.get()\|\.run()" src/server/services/auth.service.ts src/server/services/oauth.service.ts src/server/services/csv.service.ts src/server/services/image.service.ts && grep -q "await seedDefaults" src/server/index.ts && echo "PASS" || echo "FAIL"</automated>
|
||||
<automated>! grep -n "\.all()\|\.get()\|\.run()" src/server/services/auth.service.ts src/server/services/oauth.service.ts src/server/services/csv.service.ts src/server/services/image.service.ts && grep -q "await seedDefaults" src/server/index.ts && bun run lint 2>&1 | tail -3 && echo "PASS" || echo "FAIL"</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- auth.service.ts: every exported function is `async`
|
||||
- auth.service.ts: does NOT contain `.all()`, `.get()`, or `.run()`
|
||||
- oauth.service.ts: every exported function is `async`
|
||||
- oauth.service.ts: does NOT contain `.set({ used: 1 })` — uses `.set({ used: true })` instead
|
||||
- oauth.service.ts: does NOT contain `eq(oauthCodes.used, 0)` — uses `eq(oauthCodes.used, false)` instead
|
||||
- oauth.service.ts: does NOT contain `.set({ used: 1 })` -- uses `.set({ used: true })` instead
|
||||
- oauth.service.ts: does NOT contain `eq(oauthCodes.used, 0)` -- uses `eq(oauthCodes.used, false)` instead
|
||||
- csv.service.ts: every exported function is `async`, no `.all()` calls
|
||||
- image.service.ts: every exported function is `async`
|
||||
- src/server/index.ts: contains `await seedDefaults()`
|
||||
- No file in this set contains `.all()`, `.get()`, or `.run()` calls on db objects
|
||||
- PGlite smoke test creating an item via service function exits 0
|
||||
</acceptance_criteria>
|
||||
<done>Auth, OAuth, CSV, and image services fully async. OAuth boolean conversion complete. Server startup awaits async seed.</done>
|
||||
<done>Auth, OAuth, CSV, and image services fully async. OAuth boolean conversion complete. Server startup awaits async seed. PGlite smoke test confirms services work against async DB.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
@@ -191,10 +208,12 @@ Convert each service file following the async conversion rules. Read each file f
|
||||
- `grep -rn "\.all()\|\.get()\|\.run()" src/server/services/` returns NO matches (except possibly string literals in error messages)
|
||||
- `grep -c "async function" src/server/services/*.ts` shows every service has async functions
|
||||
- `grep "await seedDefaults" src/server/index.ts` returns a match
|
||||
- `bun run lint` passes
|
||||
- PGlite smoke test exits 0
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
All 9 service files use async/await for every database operation. No SQLite-only methods (.all, .get, .run) remain. Transactions use async callbacks. OAuth boolean conversion complete. Server index awaits async seed.
|
||||
All 9 service files use async/await for every database operation. No SQLite-only methods (.all, .get, .run) remain. Transactions use async callbacks. OAuth boolean conversion complete. Server index awaits async seed. PGlite smoke test validates at least one service works end-to-end. Lint passes.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
|
||||
Reference in New Issue
Block a user