feat(repo): countToday(now?) — KST midnight bucket count
For the F4-C·F cue strengthening surfaces (tray tooltip + Inbox identity counter), main + renderer need a single source of truth for "오늘 N번 잡아뒀다". Implements `NoteRepository.countToday(now?)` that computes the half-open UTC interval covering the KST calendar date of `now` and counts rows whose `created_at` falls inside. `now` is injectable for deterministic tests across the KST/UTC boundary (02:00 KST and 23:00 KST land on different UTC dates yet the same / a different KST day). Four new cases cover empty DB, KST-day filtering, KST-midnight crossover, and the default-arg branch.
This commit is contained in:
@@ -302,6 +302,28 @@ export class NoteRepository {
|
||||
return row.c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count notes whose `created_at` falls on the KST calendar date of `now`.
|
||||
* KST = UTC+9. We compute the UTC half-open interval
|
||||
* [KST-midnight today, KST-midnight tomorrow)
|
||||
* and count rows whose UTC ISO `created_at` lies inside.
|
||||
*/
|
||||
countToday(now: Date = new Date()): number {
|
||||
const KST_OFFSET_MS = 9 * 60 * 60 * 1000;
|
||||
const kstNow = new Date(now.getTime() + KST_OFFSET_MS);
|
||||
const kstYear = kstNow.getUTCFullYear();
|
||||
const kstMonth = kstNow.getUTCMonth();
|
||||
const kstDate = kstNow.getUTCDate();
|
||||
const kstMidnightUtc = Date.UTC(kstYear, kstMonth, kstDate) - KST_OFFSET_MS;
|
||||
const nextKstMidnightUtc = kstMidnightUtc + 24 * 60 * 60 * 1000;
|
||||
const startIso = new Date(kstMidnightUtc).toISOString();
|
||||
const endIso = new Date(nextKstMidnightUtc).toISOString();
|
||||
const row = this.db
|
||||
.prepare(`SELECT COUNT(*) AS c FROM notes WHERE created_at >= ? AND created_at < ?`)
|
||||
.get(startIso, endIso) as { c: number };
|
||||
return row.c;
|
||||
}
|
||||
|
||||
getAllPendingJobs(): Array<{ noteId: string; attempts: number; nextRunAt: string }> {
|
||||
const rows = this.db
|
||||
.prepare(`SELECT note_id, attempts, next_run_at FROM pending_jobs`)
|
||||
|
||||
@@ -175,4 +175,43 @@ describe('NoteRepository', () => {
|
||||
const note = repo.findById(id)!;
|
||||
expect(note.dueDate).toBeNull();
|
||||
});
|
||||
|
||||
it('countToday returns 0 for empty DB', () => {
|
||||
expect(repo.countToday(new Date('2026-04-26T12:00:00Z'))).toBe(0);
|
||||
});
|
||||
|
||||
it('countToday counts notes created on the KST date of "now"', () => {
|
||||
// now = 2026-04-26 14:00 KST (= 2026-04-26T05:00:00Z UTC).
|
||||
// a, b: 2026-04-26 KST → counted.
|
||||
// c: 2026-04-25 KST → excluded.
|
||||
db.prepare(
|
||||
`INSERT INTO notes (id, raw_text, ai_status, created_at, updated_at)
|
||||
VALUES (?, 'x', 'pending', ?, ?)`
|
||||
).run('a', '2026-04-25T17:00:00Z', '2026-04-25T17:00:00Z'); // 04-26 02:00 KST
|
||||
db.prepare(
|
||||
`INSERT INTO notes (id, raw_text, ai_status, created_at, updated_at)
|
||||
VALUES (?, 'x', 'pending', ?, ?)`
|
||||
).run('b', '2026-04-25T18:00:00Z', '2026-04-25T18:00:00Z'); // 04-26 03:00 KST
|
||||
db.prepare(
|
||||
`INSERT INTO notes (id, raw_text, ai_status, created_at, updated_at)
|
||||
VALUES (?, 'x', 'pending', ?, ?)`
|
||||
).run('c', '2026-04-25T14:00:00Z', '2026-04-25T14:00:00Z'); // 04-25 23:00 KST
|
||||
expect(repo.countToday(new Date('2026-04-26T05:00:00Z'))).toBe(2);
|
||||
});
|
||||
|
||||
it('countToday handles KST midnight crossover', () => {
|
||||
// now = 2026-04-26 14:00 KST. A note at 2026-04-26T23:30Z = 2026-04-27 08:30 KST
|
||||
// belongs to "tomorrow" (KST), so MUST NOT be counted as "today".
|
||||
db.prepare(
|
||||
`INSERT INTO notes (id, raw_text, ai_status, created_at, updated_at)
|
||||
VALUES (?, 'x', 'pending', ?, ?)`
|
||||
).run('a', '2026-04-26T23:30:00Z', '2026-04-26T23:30:00Z');
|
||||
expect(repo.countToday(new Date('2026-04-26T05:00:00Z'))).toBe(0);
|
||||
});
|
||||
|
||||
it('countToday default arg uses Date.now()', () => {
|
||||
const n = repo.countToday();
|
||||
expect(typeof n).toBe('number');
|
||||
expect(n).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user