diff --git a/api.go b/api.go index 88bf355..09be576 100644 --- a/api.go +++ b/api.go @@ -15,10 +15,11 @@ import ( ) type APIStatisticsRequest struct { - Ship *int64 `json:"ship,omitempty"` - Systems []int64 `json:"systems,omitempty"` - Modules []int64 `json:"modules,omitempty"` - Groups []int64 `json:"groups,omitempty"` + Ship *int64 `json:"ship,omitempty"` + Systems []int64 `json:"systems,omitempty"` + Modules []int64 `json:"modules,omitempty"` + Groups []int64 `json:"groups,omitempty"` + KillmailLimit *int `json:"killmailLimit,omitempty"` } type APIItemCount struct { @@ -35,6 +36,7 @@ type APIFitStatistics struct { LowSlotModules []APIItemCount `json:"lowSlotModules"` Rigs []APIItemCount `json:"rigs"` Drones []APIItemCount `json:"drones"` + KillmailIDs []int64 `json:"killmailIds,omitempty"` } type APISearchResult struct { @@ -80,6 +82,7 @@ func convertFitStatistics(stats *FitStatistics) *APIFitStatistics { LowSlotModules: convertModuleMapToItemCounts(stats.LowSlotModules), Rigs: convertModuleMapToItemCounts(stats.Rigs), Drones: convertModuleMapToItemCounts(stats.Drones), + KillmailIDs: stats.KillmailIDs, } return api } @@ -142,6 +145,13 @@ func handleStatistics(w http.ResponseWriter, r *http.Request) { if len(params.Groups) > 0 { flog.Debug("Groups filter: %d groups", len(params.Groups)) } + // Killmail limit defaults to 20 when not provided or invalid + if req.KillmailLimit != nil && *req.KillmailLimit > 0 { + params.KillmailLimit = *req.KillmailLimit + } else { + params.KillmailLimit = 20 + } + flog.Debug("Killmail limit: %d", params.KillmailLimit) db, err := GetDB() if err != nil { diff --git a/db.go b/db.go index 8e71ed1..f762ade 100644 --- a/db.go +++ b/db.go @@ -18,10 +18,11 @@ import ( ) type QueryParams struct { - Ship int64 - Systems []int64 - Modules []int64 - Groups []int64 + Ship int64 + Systems []int64 + Modules []int64 + Groups []int64 + KillmailLimit int } // CacheEntry stores both statistics (JSON) and images (blobs) in unified cache @@ -48,6 +49,7 @@ type FitStatistics struct { LowSlotModules map[int32]ModuleStats // typeID -> {Count, Percentage} Rigs map[int32]ModuleStats // typeID -> {Count, Percentage} Drones map[int32]ModuleStats // typeID -> {Count, Percentage} + KillmailIDs []int64 } type SystemStats struct { @@ -512,6 +514,7 @@ func (db *DBWrapper) QueryFits(params QueryParams) (*FitStatistics, error) { LowSlotModules: make(map[int32]ModuleStats), Rigs: make(map[int32]ModuleStats), Drones: make(map[int32]ModuleStats), + KillmailIDs: limitKillmails(killmailIDs, params.KillmailLimit), } if totalKillmails == 0 { @@ -944,3 +947,13 @@ func min(a, b int) int { } return b } + +func limitKillmails(ids []int64, limit int) []int64 { + if limit <= 0 || len(ids) == 0 { + return nil + } + if limit > len(ids) { + limit = len(ids) + } + return ids[:limit] +} diff --git a/db_test.go b/db_test.go index 917eb12..870aa56 100644 --- a/db_test.go +++ b/db_test.go @@ -128,6 +128,24 @@ func TestQueryFitsModuleFilterKeepsOtherModulesAndSlots(t *testing.T) { assert.Greater(t, otherSlots, 0, "other slot categories should remain populated") } +func TestQueryFitsReturnsKillmailIDsWithLimit(t *testing.T) { + dbi, err := GetDB() + require.NoError(t, err) + db := dbi.(*DBWrapper) + + shipID := int64(32872) + moduleID := int64(16433) + limit := 5 + + stats, err := db.QueryFits(QueryParams{Ship: shipID, Modules: []int64{moduleID}, KillmailLimit: limit}) + require.NoError(t, err) + require.Greater(t, stats.TotalKillmails, int64(0)) + + require.NotNil(t, stats.KillmailIDs) + assert.LessOrEqual(t, len(stats.KillmailIDs), limit) + assert.Greater(t, len(stats.KillmailIDs), 0) +} + func pickTopSystemID(stats *FitStatistics) int64 { var bestID int64 var bestCount int64