From 8f544a9989ebbdeba56e45b653084f8fc02c4385 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Sat, 31 Jan 2026 17:11:53 +0100 Subject: [PATCH] feat(05-02): create filterEntries utility function - Add SearchFilters type and utilities (search.ts) - Implement filterEntries with query, tags, type, dateRange filters - Case-insensitive text search with 2-character minimum - AND logic for tag filtering - Date range inclusive of end date --- src/lib/utils/filterEntries.ts | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/lib/utils/filterEntries.ts diff --git a/src/lib/utils/filterEntries.ts b/src/lib/utils/filterEntries.ts new file mode 100644 index 0000000..067d99a --- /dev/null +++ b/src/lib/utils/filterEntries.ts @@ -0,0 +1,55 @@ +import type { SearchFilters } from '$lib/types/search'; +import type { Entry, Tag } from '$lib/server/db/schema'; + +interface EntryWithTags extends Entry { + tags: Tag[]; +} + +/** + * Filters entries based on search criteria. + * + * @param entries - Array of entries with their tags + * @param filters - SearchFilters object containing filter criteria + * @returns Filtered array of entries + */ +export function filterEntries( + entries: EntryWithTags[], + filters: SearchFilters +): EntryWithTags[] { + let result = entries; + + // Text search (title + content) - minimum 2 characters + if (filters.query.length >= 2) { + const query = filters.query.toLowerCase(); + result = result.filter( + (e) => + e.title?.toLowerCase().includes(query) || e.content.toLowerCase().includes(query) + ); + } + + // Tag filter - AND logic (must have ALL selected tags) + if (filters.tags.length > 0) { + result = result.filter((e) => + filters.tags.every((tagName) => + e.tags.some((t) => t.name.toLowerCase() === tagName.toLowerCase()) + ) + ); + } + + // Type filter + if (filters.type !== 'all') { + result = result.filter((e) => e.type === filters.type); + } + + // Date range filter (using createdAt) + if (filters.dateRange.start) { + result = result.filter((e) => e.createdAt >= filters.dateRange.start!); + } + if (filters.dateRange.end) { + // Include the end date by comparing to end of day + const endOfDay = filters.dateRange.end + 'T23:59:59'; + result = result.filter((e) => e.createdAt <= endOfDay); + } + + return result; +}