Implement ship breakdown too

This commit is contained in:
2026-01-05 21:55:48 +01:00
parent 2f0af9f7b1
commit 8c51f0c721
2 changed files with 61 additions and 18 deletions

77
db.go
View File

@@ -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"

View File

@@ -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 {