refactor(categories): adopt Kysely for the /groups query (real production use)
Proves the POC in production: the category-groups list is now built with the typed Kysely builder (category_groups added to the schema; COLLATE NOCASE via sql``) and executed synchronously via all(). Byte-identical behavior — categoryGroups test 4/4, suite 248/248, typecheck:server clean. Establishes the migration recipe for rolling typed SQL out query-by-query. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
35a0e4262e
commit
d9545d6fd5
|
|
@ -27,8 +27,19 @@ export interface CategoriesTable {
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CategoryGroupsTable {
|
||||||
|
id: number;
|
||||||
|
user_id: number;
|
||||||
|
name: string;
|
||||||
|
sort_order: number;
|
||||||
|
is_seeded: number;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Database {
|
export interface Database {
|
||||||
categories: CategoriesTable;
|
categories: CategoriesTable;
|
||||||
|
category_groups: CategoryGroupsTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build-only Kysely instance. The dialect supplies the SQLite compiler; its driver
|
// Build-only Kysely instance. The dialect supplies the SQLite compiler; its driver
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ const { ValidationError, NotFoundError, ConflictError } = require('../utils/apiE
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { getDb, ensureUserDefaultCategories } = require('../db/database.cts');
|
const { getDb, ensureUserDefaultCategories } = require('../db/database.cts');
|
||||||
const { accountingActiveSql } = require('../services/paymentAccountingService.cts');
|
const { accountingActiveSql } = require('../services/paymentAccountingService.cts');
|
||||||
|
const { kysely, all } = require('../db/kysely.cts');
|
||||||
|
const { sql } = require('kysely');
|
||||||
|
|
||||||
// Maps a SQLite UNIQUE-constraint violation to a friendly 409; re-throws anything
|
// Maps a SQLite UNIQUE-constraint violation to a friendly 409; re-throws anything
|
||||||
// else so the terminal handler returns a safe 500.
|
// else so the terminal handler returns a safe 500.
|
||||||
|
|
@ -198,19 +200,16 @@ router.put('/:id', (req: Req, res: Res) => {
|
||||||
|
|
||||||
// ── Category groups ──────────────────────────────────────────────────────────
|
// ── Category groups ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
// GET /api/category-groups
|
// GET /api/category-groups — typed via Kysely (built, then run synchronously).
|
||||||
router.get('/groups', (req: Req, res: Res) => {
|
router.get('/groups', (req: Req, res: Res) => {
|
||||||
const db = getDb();
|
const groups = all(
|
||||||
const groups = db
|
kysely()
|
||||||
.prepare(
|
.selectFrom('category_groups')
|
||||||
`
|
.select(['id', 'name', 'sort_order', 'created_at', 'updated_at'])
|
||||||
SELECT id, name, sort_order, created_at, updated_at
|
.where('user_id', '=', req.user.id)
|
||||||
FROM category_groups
|
.orderBy('sort_order', 'asc')
|
||||||
WHERE user_id = ?
|
.orderBy(sql`name collate nocase`, 'asc'),
|
||||||
ORDER BY sort_order ASC, name COLLATE NOCASE ASC
|
);
|
||||||
`,
|
|
||||||
)
|
|
||||||
.all(req.user.id);
|
|
||||||
res.json(groups);
|
res.json(groups);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue