Implement opal-task Phase 3: Filter and Modifier Parsing
- Add filter.go: Parse filters (+tag, -tag, attribute:value, IDs) - Implement Filter.ToSQL() for WHERE clause generation - Add modifier.go: Parse modifiers (set/clear attributes, add/remove tags) - Implement Modifier.Apply() to update existing tasks - Add dateparse.go: Smart date parsing (ISO, today, tomorrow, weekdays) - Implement nextWeekday logic (smart Sunday interpretation) - Update GetTasks() to accept Filter parameter - Add CreateTaskWithModifier() for task creation with modifiers - Add comprehensive test suite (13 new tests, all passing) - Support filtering by status, project, priority, tags, UUIDs, display IDs - Support modifying priority, project, dates, recurrence, tags
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ParseDate parses date strings with smart interpretation
|
||||
// Supports: ISO dates, relative (tomorrow, today), weekdays (sun, monday)
|
||||
func ParseDate(s string) (time.Time, error) {
|
||||
s = strings.ToLower(strings.TrimSpace(s))
|
||||
now := timeNow()
|
||||
|
||||
// Try ISO format first
|
||||
if t, err := time.Parse("2006-01-02", s); err == nil {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// Relative dates
|
||||
switch s {
|
||||
case "today":
|
||||
return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()), nil
|
||||
case "tomorrow":
|
||||
tomorrow := now.AddDate(0, 0, 1)
|
||||
return time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), 0, 0, 0, 0, tomorrow.Location()), nil
|
||||
case "yesterday":
|
||||
yesterday := now.AddDate(0, 0, -1)
|
||||
return time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, yesterday.Location()), nil
|
||||
}
|
||||
|
||||
// Weekday names
|
||||
weekdays := map[string]time.Weekday{
|
||||
"sun": time.Sunday, "sunday": time.Sunday,
|
||||
"mon": time.Monday, "monday": time.Monday,
|
||||
"tue": time.Tuesday, "tuesday": time.Tuesday,
|
||||
"wed": time.Wednesday, "wednesday": time.Wednesday,
|
||||
"thu": time.Thursday, "thursday": time.Thursday,
|
||||
"fri": time.Friday, "friday": time.Friday,
|
||||
"sat": time.Saturday, "saturday": time.Saturday,
|
||||
}
|
||||
|
||||
if targetWeekday, ok := weekdays[s]; ok {
|
||||
return nextWeekday(now, targetWeekday), nil
|
||||
}
|
||||
|
||||
return time.Time{}, fmt.Errorf("unable to parse date: %s", s)
|
||||
}
|
||||
|
||||
// nextWeekday returns the next occurrence of the target weekday
|
||||
// Smart logic: if today is Thursday and target is Sunday, returns this Sunday
|
||||
// If today is Sunday and target is Sunday, returns next Sunday
|
||||
func nextWeekday(from time.Time, target time.Weekday) time.Time {
|
||||
// Calculate days until target
|
||||
daysUntil := int(target - from.Weekday())
|
||||
|
||||
if daysUntil <= 0 {
|
||||
daysUntil += 7 // Next week
|
||||
}
|
||||
|
||||
next := from.AddDate(0, 0, daysUntil)
|
||||
return time.Date(next.Year(), next.Month(), next.Day(), 0, 0, 0, 0, next.Location())
|
||||
}
|
||||
Reference in New Issue
Block a user