package main import ( "fmt" "log" ) type PlayerService struct { db *DB } type PlayerServiceQuery struct { Name *string `db:"name"` ID *int64 `db:"id"` } func (ps *PlayerService) Query(query PlayerServiceQuery) ([]Player, error) { res := []Player{} sqlQuery := "SELECT id, name, guild FROM player" whereQuery := BuildWhereQuery(query) if whereQuery != "" { sqlQuery += " " + whereQuery } rows, err := ps.db.readConn.Query(sqlQuery) if err != nil { return res, fmt.Errorf("failed getting players for query %q: %v", sqlQuery, err) } defer rows.Close() for rows.Next() { player := Player{} err := rows.Scan(&player.ID, &player.Name, &player.Guild.ID) if err != nil { return res, fmt.Errorf("failed scanning player: %v", err) } res = append(res, player) } return res, nil } func (ps *PlayerService) Create(name string, guild Guild) (Player, error) { log.Printf("Creating player %s in guild %s", name, guild.Name) player := Player{} res, err := ps.db.writeConn.Exec("insert into player (name, guild) values (?, ?)", name, guild.ID) if err != nil { return player, fmt.Errorf("failed to insert player: %v", err) } id, err := res.LastInsertId() if err != nil { return player, fmt.Errorf("failed to get last insert id: %v", err) } log.Printf("Created player %s in guild %s with id %d", name, guild.Name, id) qres, err := ps.Query(PlayerServiceQuery{ID: &id}) if err != nil { return player, fmt.Errorf("failed getting player for id %d: %v", id, err) } if len(qres) > 1 { return player, fmt.Errorf("more than one player found for id %d", id) } return qres[0], nil } func (ps *PlayerService) GetOrCreate(name string, guild Guild) (Player, error) { player := Player{} players, err := ps.Query(PlayerServiceQuery{Name: &name}) if len(players) > 1 { return player, fmt.Errorf("more than one player found for name %s", name) } if err != nil || len(players) == 0 { player, err = ps.Create(name, guild) if err != nil { return player, fmt.Errorf("failed creating player: %v", err) } } if len(players) == 1 { player = players[0] } return player, nil } type ( FullPlayer struct { ID int64 `json:"id"` Name string `json:"name"` Guild struct { ID int64 `json:"id"` Name string `json:"name"` } `json:"guild"` Associations []FullPlayerAssociation `json:"associations"` Notes []FullPlayerNote `json:"notes"` } FullPlayerAssociation struct { ID int64 `json:"id"` Name string `json:"name"` Note string `json:"note"` } FullPlayerNote struct { ID int64 `json:"id"` Content string `json:"content"` Timestamp string `json:"timestamp"` } ) func (ps *PlayerService) GetAllPlayerInfo(name string, nnotes int) (FullPlayer, error) { res := FullPlayer{} err := ps.db.readConn.QueryRow(selectPlayer, name).Scan(&res.ID, &res.Name, &res.Guild.ID, &res.Guild.Name) if err != nil { return res, fmt.Errorf("failed getting player info: %v", err) } rows, err := ps.db.readConn.Query(selectAssociation, res.ID) if err != nil { return res, fmt.Errorf("failed getting player associations: %v", err) } for rows.Next() { assoc := FullPlayerAssociation{} err := rows.Scan(&assoc.ID, &assoc.Name, &assoc.Note) if err != nil { return res, fmt.Errorf("failed scanning association: %v", err) } res.Associations = append(res.Associations, assoc) } rows.Close() rows, err = ps.db.readConn.Query(selectNotes, res.ID, nnotes) if err != nil { return res, fmt.Errorf("failed getting player notes: %v", err) } for rows.Next() { note := FullPlayerNote{} err := rows.Scan(¬e.ID, ¬e.Content, ¬e.Timestamp) if err != nil { return res, fmt.Errorf("failed scanning note: %v", err) } res.Notes = append(res.Notes, note) } rows.Close() return res, nil } func (ps *PlayerService) GetAllPlayers() ([]Player, error) { res := []Player{} rows, err := ps.db.readConn.Query(selectPlayers) if err != nil { return res, fmt.Errorf("failed getting players: %v", err) } for rows.Next() { player := Player{} err := rows.Scan(&player.ID, &player.Name, &player.Guild.ID, &player.Guild.Name, &player.Notes, &player.Associations) if err != nil { return res, fmt.Errorf("failed scanning player: %v", err) } res = append(res, player) } rows.Close() return res, nil }