feat(trash): active queries exclude deleted_at IS NOT NULL (#4 v0.2.3)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -83,17 +83,25 @@ export class NoteRepository {
|
||||
const limit = Math.max(1, Math.min(200, opts.limit));
|
||||
const rows = opts.cursor
|
||||
? (this.db
|
||||
.prepare(`SELECT * FROM notes WHERE created_at < ? ORDER BY created_at DESC, id DESC LIMIT ?`)
|
||||
.prepare(
|
||||
`SELECT * FROM notes
|
||||
WHERE deleted_at IS NULL AND created_at < ?
|
||||
ORDER BY created_at DESC, id DESC LIMIT ?`
|
||||
)
|
||||
.all(opts.cursor, limit) as any[])
|
||||
: (this.db
|
||||
.prepare(`SELECT * FROM notes ORDER BY created_at DESC, id DESC LIMIT ?`)
|
||||
.prepare(
|
||||
`SELECT * FROM notes
|
||||
WHERE deleted_at IS NULL
|
||||
ORDER BY created_at DESC, id DESC LIMIT ?`
|
||||
)
|
||||
.all(limit) as any[]);
|
||||
return rows.map((r) => this.hydrate(r));
|
||||
}
|
||||
|
||||
listAll(): Note[] {
|
||||
const rows = this.db
|
||||
.prepare(`SELECT * FROM notes ORDER BY created_at ASC, id ASC`)
|
||||
.prepare(`SELECT * FROM notes WHERE deleted_at IS NULL ORDER BY created_at ASC, id ASC`)
|
||||
.all() as any[];
|
||||
return rows.map((r) => this.hydrate(r));
|
||||
}
|
||||
@@ -359,7 +367,10 @@ export class NoteRepository {
|
||||
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 < ?`)
|
||||
.prepare(
|
||||
`SELECT COUNT(*) AS c FROM notes
|
||||
WHERE deleted_at IS NULL AND created_at >= ? AND created_at < ?`
|
||||
)
|
||||
.get(startIso, endIso) as { c: number };
|
||||
return row.c;
|
||||
}
|
||||
|
||||
@@ -363,3 +363,44 @@ describe('NoteRepository.listTrashed', () => {
|
||||
expect(r).toHaveLength(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Active queries exclude deleted notes', () => {
|
||||
let db: Database.Database;
|
||||
let repo: NoteRepository;
|
||||
beforeEach(() => {
|
||||
db = new Database(':memory:');
|
||||
runMigrations(db);
|
||||
repo = new NoteRepository(db);
|
||||
});
|
||||
|
||||
it('list() excludes trashed', () => {
|
||||
const a = repo.create({ rawText: 'a' }).id;
|
||||
const b = repo.create({ rawText: 'b' }).id;
|
||||
repo.trash(a, '2026-05-01T00:00:00.000Z');
|
||||
const r = repo.list({ limit: 50 });
|
||||
expect(r.map((n) => n.id)).toEqual([b]);
|
||||
});
|
||||
|
||||
it('listAll() excludes trashed', () => {
|
||||
const a = repo.create({ rawText: 'a' }).id;
|
||||
repo.create({ rawText: 'b' });
|
||||
repo.trash(a, '2026-05-01T00:00:00.000Z');
|
||||
const r = repo.listAll();
|
||||
expect(r.map((n) => n.rawText)).toEqual(['b']);
|
||||
});
|
||||
|
||||
it('countToday() excludes trashed', () => {
|
||||
const a = repo.create({ rawText: 'a' }).id;
|
||||
repo.create({ rawText: 'b' });
|
||||
repo.trash(a, new Date().toISOString());
|
||||
expect(repo.countToday(new Date())).toBe(1);
|
||||
});
|
||||
|
||||
it('findById() returns trashed notes (does NOT filter)', () => {
|
||||
const { id } = repo.create({ rawText: 'a' });
|
||||
repo.trash(id, '2026-05-01T00:00:00.000Z');
|
||||
const note = repo.findById(id);
|
||||
expect(note).not.toBeNull();
|
||||
expect(note!.deletedAt).toBe('2026-05-01T00:00:00.000Z');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user