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:
@@ -139,6 +139,11 @@ func sqlToUUIDPtr(v interface{}) *uuid.UUID {
|
||||
|
||||
// CreateTask creates a new task with the given description
|
||||
func CreateTask(description string) (*Task, error) {
|
||||
return CreateTaskWithModifier(description, nil)
|
||||
}
|
||||
|
||||
// CreateTaskWithModifier creates a new task with the given description and applies modifiers
|
||||
func CreateTaskWithModifier(description string, mod *Modifier) (*Task, error) {
|
||||
now := timeNow()
|
||||
task := &Task{
|
||||
UUID: uuid.New(),
|
||||
@@ -150,10 +155,26 @@ func CreateTask(description string) (*Task, error) {
|
||||
Tags: []string{},
|
||||
}
|
||||
|
||||
// Apply modifiers before saving (for attributes)
|
||||
if mod != nil {
|
||||
if err := mod.ApplyToNew(task); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := task.Save(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Apply tags after saving (requires task.ID)
|
||||
if mod != nil {
|
||||
for _, tag := range mod.AddTags {
|
||||
if err := task.AddTag(tag); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return task, nil
|
||||
}
|
||||
|
||||
@@ -242,22 +263,33 @@ func GetTask(taskUUID uuid.UUID) (*Task, error) {
|
||||
return task, nil
|
||||
}
|
||||
|
||||
// GetTasks retrieves all tasks (filtering will be added later)
|
||||
func GetTasks() ([]*Task, error) {
|
||||
// GetTasks retrieves all tasks with optional filtering
|
||||
func GetTasks(filter *Filter) ([]*Task, error) {
|
||||
db := GetDB()
|
||||
if db == nil {
|
||||
return nil, fmt.Errorf("database not initialized")
|
||||
}
|
||||
|
||||
query := `
|
||||
// Build WHERE clause from filter
|
||||
whereClause := "1=1"
|
||||
var args []interface{}
|
||||
if filter != nil {
|
||||
whereClause, args = filter.ToSQL()
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT id, uuid, status, description, project, priority,
|
||||
created, modified, start, end, due, scheduled, wait, until_date,
|
||||
recurrence_duration, parent_uuid
|
||||
FROM tasks
|
||||
ORDER BY due ASC, priority DESC
|
||||
`
|
||||
WHERE %s
|
||||
ORDER BY
|
||||
CASE WHEN due IS NULL THEN 1 ELSE 0 END,
|
||||
due ASC,
|
||||
priority DESC
|
||||
`, whereClause)
|
||||
|
||||
rows, err := db.Query(query)
|
||||
rows, err := db.Query(query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query tasks: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user