diff --git a/db.go b/db.go index 3f597ee..5f8e2c2 100644 --- a/db.go +++ b/db.go @@ -24,6 +24,7 @@ type QueryParams struct { type FitStatistics struct { TotalKillmails int64 + ShipBreakdown map[int64]SystemStats // shipTypeID -> {Count, Percentage} SystemBreakdown map[int64]SystemStats // systemID -> {Count, Percentage} HighSlotModules map[int32]ModuleStats // typeID -> {Count, Percentage} MidSlotModules map[int32]ModuleStats // typeID -> {Count, Percentage} @@ -320,6 +321,9 @@ func (db *DBWrapper) QueryFits(params QueryParams) (*FitStatistics, error) { flog := logger.Default.WithPrefix("QueryFits").WithPrefix(fmt.Sprintf("%+v", params)) flog.Info("Starting query") + // Check if params are empty (all fields zero/empty) + isEmpty := params.Ship == 0 && len(params.Systems) == 0 && len(params.Modules) == 0 && len(params.Groups) == 0 + modules := deduplicateInt64(params.Modules) flog.Debug("Deduplicated modules: %d -> %d", len(params.Modules), len(modules)) @@ -348,6 +352,7 @@ func (db *DBWrapper) QueryFits(params QueryParams) (*FitStatistics, error) { var killmailIDs []int64 var systemIDs []int64 + var shipTypeIDsFromResults []int64 if len(modules) > 0 { placeholders := make([]string, len(modules)) @@ -365,14 +370,21 @@ func (db *DBWrapper) QueryFits(params QueryParams) (*FitStatistics, error) { shipPlaceholders[i] = "?" shipArgs = append(shipArgs, shipID) } - } else { + } else if !isEmpty { shipPlaceholders = []string{"?"} shipArgs = []interface{}{params.Ship} } - moduleQuery := "SELECT DISTINCT killmail_id, solar_system_id FROM fitted_modules WHERE victim_ship_type_id IN (" + strings.Join(shipPlaceholders, ",") + ") AND item_type_id IN (" + strings.Join(placeholders, ",") + ")" - args := shipArgs - args = append(args, moduleArgs...) + var moduleQuery string + var args []interface{} + if len(shipPlaceholders) > 0 { + moduleQuery = "SELECT DISTINCT killmail_id, solar_system_id, victim_ship_type_id FROM fitted_modules WHERE victim_ship_type_id IN (" + strings.Join(shipPlaceholders, ",") + ") AND item_type_id IN (" + strings.Join(placeholders, ",") + ")" + args = shipArgs + args = append(args, moduleArgs...) + } else { + moduleQuery = "SELECT DISTINCT killmail_id, solar_system_id, victim_ship_type_id FROM fitted_modules WHERE item_type_id IN (" + strings.Join(placeholders, ",") + ")" + args = moduleArgs + } if len(params.Systems) > 0 { sysPlaceholders := make([]string, len(params.Systems)) @@ -389,30 +401,33 @@ func (db *DBWrapper) QueryFits(params QueryParams) (*FitStatistics, error) { return nil, err } for rows.Next() { - var id, systemID int64 - if err := rows.Scan(&id, &systemID); err != nil { + var id, systemID, shipTypeID int64 + if err := rows.Scan(&id, &systemID, &shipTypeID); err != nil { rows.Close() return nil, err } killmailIDs = append(killmailIDs, id) systemIDs = append(systemIDs, systemID) + shipTypeIDsFromResults = append(shipTypeIDsFromResults, shipTypeID) } rows.Close() } else { // No module filter - query flat_killmails directly - var shipPlaceholders []string + var query string var args []interface{} if len(shipTypeIDs) > 0 { - shipPlaceholders = make([]string, len(shipTypeIDs)) + shipPlaceholders := make([]string, len(shipTypeIDs)) for i, shipID := range shipTypeIDs { shipPlaceholders[i] = "?" args = append(args, shipID) } - } else { - shipPlaceholders = []string{"?"} + query = "SELECT killmail_id, solar_system_id, victim_ship_type_id FROM flat_killmails WHERE victim_ship_type_id IN (" + strings.Join(shipPlaceholders, ",") + ")" + } else if !isEmpty { + query = "SELECT killmail_id, solar_system_id, victim_ship_type_id FROM flat_killmails WHERE victim_ship_type_id = ?" args = []interface{}{params.Ship} + } else { + query = "SELECT killmail_id, solar_system_id, victim_ship_type_id FROM flat_killmails" } - query := "SELECT killmail_id, solar_system_id FROM flat_killmails WHERE victim_ship_type_id IN (" + strings.Join(shipPlaceholders, ",") + ")" if len(params.Systems) > 0 { placeholders := make([]string, len(params.Systems)) @@ -431,13 +446,14 @@ func (db *DBWrapper) QueryFits(params QueryParams) (*FitStatistics, error) { defer rows.Close() for rows.Next() { - var killmailID, systemID int64 - if err := rows.Scan(&killmailID, &systemID); err != nil { + var killmailID, systemID, shipTypeID int64 + if err := rows.Scan(&killmailID, &systemID, &shipTypeID); err != nil { flog.Error("Failed to scan row: %v", err) return nil, err } killmailIDs = append(killmailIDs, killmailID) systemIDs = append(systemIDs, systemID) + shipTypeIDsFromResults = append(shipTypeIDsFromResults, shipTypeID) } } @@ -449,6 +465,7 @@ func (db *DBWrapper) QueryFits(params QueryParams) (*FitStatistics, error) { stats := &FitStatistics{ TotalKillmails: totalKillmails, + ShipBreakdown: make(map[int64]SystemStats), SystemBreakdown: make(map[int64]SystemStats), HighSlotModules: make(map[int32]ModuleStats), MidSlotModules: make(map[int32]ModuleStats), @@ -462,6 +479,24 @@ func (db *DBWrapper) QueryFits(params QueryParams) (*FitStatistics, error) { return stats, nil } + // Calculate ship breakdown if params are empty or we have ship data + if isEmpty || len(shipTypeIDsFromResults) > 0 { + flog.Debug("Calculating ship breakdown") + shipCounts := make(map[int64]int64) + for _, shipTypeID := range shipTypeIDsFromResults { + shipCounts[shipTypeID]++ + } + + for shipTypeID, count := range shipCounts { + percentage := float64(count) / float64(totalKillmails) * 100.0 + stats.ShipBreakdown[shipTypeID] = SystemStats{ + Count: count, + Percentage: percentage, + } + } + flog.Debug("Ship breakdown: %d unique ships", len(stats.ShipBreakdown)) + } + flog.Debug("Calculating system breakdown") systemCounts := make(map[int64]int64) for _, systemID := range systemIDs { @@ -579,18 +614,24 @@ func (db *DBWrapper) calculateModuleStats(params QueryParams, shipTypeIDs []int6 // Use shipTypeIDs filter instead of huge IN clause of killmailIDs var shipPlaceholders []string var args []interface{} + if len(shipTypeIDs) > 0 { shipPlaceholders = make([]string, len(shipTypeIDs)) for i, shipID := range shipTypeIDs { shipPlaceholders[i] = "?" args = append(args, shipID) } - } else { + } else if params.Ship != 0 { shipPlaceholders = []string{"?"} args = []interface{}{params.Ship} } - query := "SELECT item_type_id, flag, count(DISTINCT killmail_id) as count FROM fitted_modules WHERE victim_ship_type_id IN (" + strings.Join(shipPlaceholders, ",") + ")" + var query string + if len(shipPlaceholders) > 0 { + query = "SELECT item_type_id, flag, count(DISTINCT killmail_id) as count FROM fitted_modules WHERE victim_ship_type_id IN (" + strings.Join(shipPlaceholders, ",") + ")" + } else { + query = "SELECT item_type_id, flag, count(DISTINCT killmail_id) as count FROM fitted_modules" + } if len(params.Systems) > 0 { sysPlaceholders := make([]string, len(params.Systems)) @@ -598,7 +639,11 @@ func (db *DBWrapper) calculateModuleStats(params QueryParams, shipTypeIDs []int6 sysPlaceholders[i] = "?" args = append(args, params.Systems[i]) } - query += " AND solar_system_id IN (" + strings.Join(sysPlaceholders, ",") + ")" + if len(shipPlaceholders) > 0 { + query += " AND solar_system_id IN (" + strings.Join(sysPlaceholders, ",") + ")" + } else { + query += " WHERE solar_system_id IN (" + strings.Join(sysPlaceholders, ",") + ")" + } } query += " GROUP BY item_type_id, flag" diff --git a/main.go b/main.go index 2e3c2b0..4286dd9 100644 --- a/main.go +++ b/main.go @@ -34,8 +34,6 @@ func main() { logger.Info("Querying fits") params := QueryParams{ - Ship: 32872, // Algos typeID - Groups: []int64{325}, } stats, err := db.QueryFits(params) if err != nil {