| 694 | } |
| 695 | |
| 696 | func ListProjects(db *sql.DB, filter ProjectFilter) ([]*Project, error) { |
| 697 | var where []string |
| 698 | var args []any |
| 699 | if filter.Status != "" { |
| 700 | where = append(where, "status = ?") |
| 701 | args = append(args, filter.Status) |
| 702 | } |
| 703 | if !filter.IncludeArchived { |
| 704 | where = append(where, "archived_at IS NULL") |
| 705 | } |
| 706 | q := "SELECT " + ProjectCols + " FROM projects" |
| 707 | if len(where) > 0 { |
| 708 | q += " WHERE " + strings.Join(where, " AND ") |
| 709 | } |
| 710 | q += " ORDER BY slug" |
| 711 | rows, err := db.Query(q, args...) |
| 712 | if err != nil { |
| 713 | return nil, fmt.Errorf("list projects: %w", err) |
| 714 | } |
| 715 | defer rows.Close() |
| 716 | var out []*Project |
| 717 | for rows.Next() { |
| 718 | p, err := ScanProject(rows) |
| 719 | if err != nil { |
| 720 | return nil, fmt.Errorf("scan project: %w", err) |
| 721 | } |
| 722 | out = append(out, p) |
| 723 | } |
| 724 | return out, rows.Err() |
| 725 | } |
| 726 | |
| 727 | // ---------- task queries ---------- |
| 728 | |