feat: connection search by name/hostname/tag with json_each filtering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vantz Stockwell 2026-03-17 06:21:03 -04:00
parent 995e81de3b
commit ab5a5c7ae2
2 changed files with 93 additions and 0 deletions

View File

@ -0,0 +1,40 @@
package connections
import "fmt"
func (s *ConnectionService) Search(query string) ([]Connection, error) {
like := "%" + query + "%"
rows, err := s.db.Query(
`SELECT id, name, hostname, port, protocol, group_id, credential_id,
COALESCE(color,''), tags, COALESCE(notes,''), COALESCE(options,'{}'),
sort_order, last_connected, created_at, updated_at
FROM connections
WHERE name LIKE ? COLLATE NOCASE
OR hostname LIKE ? COLLATE NOCASE
OR tags LIKE ? COLLATE NOCASE
OR notes LIKE ? COLLATE NOCASE
ORDER BY last_connected DESC NULLS LAST, name`,
like, like, like, like,
)
if err != nil {
return nil, fmt.Errorf("search connections: %w", err)
}
defer rows.Close()
return scanConnections(rows)
}
func (s *ConnectionService) FilterByTag(tag string) ([]Connection, error) {
rows, err := s.db.Query(
`SELECT c.id, c.name, c.hostname, c.port, c.protocol, c.group_id, c.credential_id,
COALESCE(c.color,''), c.tags, COALESCE(c.notes,''), COALESCE(c.options,'{}'),
c.sort_order, c.last_connected, c.created_at, c.updated_at
FROM connections c, json_each(c.tags) AS t
WHERE t.value = ?
ORDER BY c.name`, tag,
)
if err != nil {
return nil, fmt.Errorf("filter by tag: %w", err)
}
defer rows.Close()
return scanConnections(rows)
}

View File

@ -0,0 +1,53 @@
package connections
import "testing"
func TestSearchByName(t *testing.T) {
svc := setupTestService(t)
svc.CreateConnection(CreateConnectionInput{Name: "Asgard", Hostname: "192.168.1.4", Port: 22, Protocol: "ssh"})
svc.CreateConnection(CreateConnectionInput{Name: "Docker", Hostname: "155.254.29.221", Port: 22, Protocol: "ssh"})
results, err := svc.Search("asg")
if err != nil {
t.Fatalf("Search() error: %v", err)
}
if len(results) != 1 {
t.Fatalf("len(results) = %d, want 1", len(results))
}
if results[0].Name != "Asgard" {
t.Errorf("Name = %q, want %q", results[0].Name, "Asgard")
}
}
func TestSearchByHostname(t *testing.T) {
svc := setupTestService(t)
svc.CreateConnection(CreateConnectionInput{Name: "Asgard", Hostname: "192.168.1.4", Port: 22, Protocol: "ssh"})
results, _ := svc.Search("192.168")
if len(results) != 1 {
t.Errorf("len(results) = %d, want 1", len(results))
}
}
func TestSearchByTag(t *testing.T) {
svc := setupTestService(t)
svc.CreateConnection(CreateConnectionInput{Name: "ProdServer", Hostname: "10.0.0.1", Port: 22, Protocol: "ssh", Tags: []string{"Prod", "Linux"}})
svc.CreateConnection(CreateConnectionInput{Name: "DevServer", Hostname: "10.0.0.2", Port: 22, Protocol: "ssh", Tags: []string{"Dev", "Linux"}})
results, _ := svc.Search("Prod")
if len(results) != 1 {
t.Errorf("len(results) = %d, want 1", len(results))
}
}
func TestFilterByTag(t *testing.T) {
svc := setupTestService(t)
svc.CreateConnection(CreateConnectionInput{Name: "A", Hostname: "10.0.0.1", Port: 22, Protocol: "ssh", Tags: []string{"Prod"}})
svc.CreateConnection(CreateConnectionInput{Name: "B", Hostname: "10.0.0.2", Port: 22, Protocol: "ssh", Tags: []string{"Dev"}})
svc.CreateConnection(CreateConnectionInput{Name: "C", Hostname: "10.0.0.3", Port: 22, Protocol: "ssh", Tags: []string{"Prod", "Linux"}})
results, _ := svc.FilterByTag("Prod")
if len(results) != 2 {
t.Errorf("len(results) = %d, want 2", len(results))
}
}