package domain import ( "fmt" "net/url" "strconv" archivalStore "git.nakama.town/fmartingr/hako/internal/archival/store" ) // LinkListRequest contains request parameters for listing links from the API type LinkListRequest struct { UserID string Limit int Offset int CategoryID string SearchQuery string } // Defaults sets sensible defaults for LinkListRequest func (r *LinkListRequest) Defaults() { if r.Limit == 0 { r.Limit = archivalStore.DefaultListLimit } if r.Offset < 0 { r.Offset = 0 } } // IsValid validates LinkListRequest func (r *LinkListRequest) IsValid() error { if r.UserID == "" { return fmt.Errorf("userID is required") } if r.Limit < archivalStore.MinListLimit || r.Limit > archivalStore.MaxListLimit { return fmt.Errorf("limit must be between %d and %d, got %d", archivalStore.MinListLimit, archivalStore.MaxListLimit, r.Limit) } if r.Offset < 0 { return fmt.Errorf("offset must be >= 0, got %d", r.Offset) } return nil } // FromURLValues parses query parameters from url.Values into the request struct func (r *LinkListRequest) FromURLValues(values url.Values) error { // Parse limit if limitStr := values.Get("limit"); limitStr != "" { limit, err := strconv.Atoi(limitStr) if err != nil { return fmt.Errorf("invalid limit parameter: %w", err) } r.Limit = limit } // Parse offset if offsetStr := values.Get("offset"); offsetStr != "" { offset, err := strconv.Atoi(offsetStr) if err != nil { return fmt.Errorf("invalid offset parameter: %w", err) } r.Offset = offset } // Parse category_id if categoryID := values.Get("category_id"); categoryID != "" { r.CategoryID = categoryID } // Parse search query (supports both 'q' and 'search' parameters) // Only accept queries with at least 3 characters if searchQuery := values.Get("q"); searchQuery != "" && len(searchQuery) >= 3 { r.SearchQuery = searchQuery } else if searchQuery := values.Get("search"); searchQuery != "" && len(searchQuery) >= 3 { r.SearchQuery = searchQuery } return nil } // ToLinkListOptions converts LinkListRequest to archivalStore.LinkListOptions func (r *LinkListRequest) ToLinkListOptions() archivalStore.LinkListOptions { return archivalStore.LinkListOptions{ UserID: r.UserID, Limit: r.Limit, Offset: r.Offset, CategoryID: r.CategoryID, SearchQuery: r.SearchQuery, } } // ToLinkCountOptions converts LinkListRequest to archivalStore.LinkCountOptions func (r *LinkListRequest) ToLinkCountOptions() archivalStore.LinkCountOptions { return archivalStore.LinkCountOptions{ UserID: r.UserID, CategoryID: r.CategoryID, SearchQuery: r.SearchQuery, } }