Implement parsing and persisting notes

This commit is contained in:
2024-10-27 21:43:46 +01:00
parent 09fe5a74d8
commit 4d21c77f99
5 changed files with 120 additions and 52 deletions

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"log"
) )
type GuildService struct { type GuildService struct {
@@ -39,6 +40,7 @@ func (gs *GuildService) Query(query GuildServiceQuery) ([]Guild, error) {
} }
func (gs *GuildService) Create(name string) (Guild, error) { func (gs *GuildService) Create(name string) (Guild, error) {
log.Printf("Creating guild %s", name)
guild := Guild{} guild := Guild{}
res, err := gs.db.writeConn.Exec("insert into guild (name) values (?)", name) res, err := gs.db.writeConn.Exec("insert into guild (name) values (?)", name)
if err != nil { if err != nil {
@@ -49,6 +51,7 @@ func (gs *GuildService) Create(name string) (Guild, error) {
if err != nil { if err != nil {
return guild, fmt.Errorf("failed to get last insert id: %v", err) return guild, fmt.Errorf("failed to get last insert id: %v", err)
} }
log.Printf("Created guild %s with id %d", name, id)
qres, err := gs.Query(GuildServiceQuery{ID: &id}) qres, err := gs.Query(GuildServiceQuery{ID: &id})
if err != nil { if err != nil {
@@ -64,14 +67,17 @@ func (gs *GuildService) Create(name string) (Guild, error) {
func (gs *GuildService) GetOrCreate(name string) (Guild, error) { func (gs *GuildService) GetOrCreate(name string) (Guild, error) {
guild := Guild{} guild := Guild{}
guilds, err := gs.Query(GuildServiceQuery{Name: &name}) guilds, err := gs.Query(GuildServiceQuery{Name: &name})
if err != nil { if len(guilds) > 1 {
if len(guilds) > 1 { return guild, fmt.Errorf("more than one guild found for name %s", name)
return guild, fmt.Errorf("more than one guild found for name %s", name) }
} if err != nil || len(guilds) == 0 {
guild, err = gs.Create(name) guild, err = gs.Create(name)
if err != nil { if err != nil {
return guild, fmt.Errorf("failed creating guild: %v", err) return guild, fmt.Errorf("failed creating guild: %v", err)
} }
} }
if len(guilds) == 1 {
guild = guilds[0]
}
return guild, nil return guild, nil
} }

49
main.go
View File

@@ -6,9 +6,6 @@ import (
"io" "io"
"log" "log"
"os" "os"
"regexp"
"strings"
"time"
) )
var Error *log.Logger var Error *log.Logger
@@ -36,6 +33,7 @@ var db DB
var gs GuildService var gs GuildService
var ps PlayerService var ps PlayerService
var ns NoteService var ns NoteService
var as AssociationService
func main() { func main() {
inputFile := flag.String("if", "input", "Input file") inputFile := flag.String("if", "input", "Input file")
@@ -55,6 +53,7 @@ func main() {
gs = GuildService{db: &db} gs = GuildService{db: &db}
ps = PlayerService{db: &db} ps = PlayerService{db: &db}
ns = NoteService{db: &db} ns = NoteService{db: &db}
as = AssociationService{db: &db}
inputData, err := os.ReadFile(*inputFile) inputData, err := os.ReadFile(*inputFile)
if err != nil { if err != nil {
@@ -68,44 +67,12 @@ func main() {
Error.Printf("Failed parsing note: %v", err) Error.Printf("Failed parsing note: %v", err)
return return
} }
log.Printf("%#v", note)
}
var associationRe = regexp.MustCompile(`r:(\w+)(?:\(([^)]+)\))?`) dbnote, ass, err := PersistNoteData(note)
func ParseNote(data string) (NoteData, error) { if err != nil {
res := NoteData{} Error.Printf("Failed persisting note: %v", err)
lines := strings.Split(data, "\n") return
note := []string{}
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" {
continue
}
parts := strings.Split(line, ":")
switch parts[0] {
case "p":
res.Player = parts[1]
case "d":
var err error
res.Date, err = time.Parse(time.DateOnly, parts[1])
if err != nil {
return res, fmt.Errorf("failed to parse date: %v", err)
}
case "g":
res.Guild = parts[1]
default:
note = append(note, line)
}
} }
res.Note = strings.Join(note, "\n") log.Printf("%#v", dbnote)
log.Printf("%#v", ass)
matches := associationRe.FindAllStringSubmatch(res.Note, -1)
for _, match := range matches {
res.Associations = append(res.Associations, NoteAssociationData{
Player: match[1],
Note: match[2],
})
}
return res, nil
} }

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"log"
"time" "time"
) )
@@ -30,10 +31,15 @@ func (ns *NoteService) Query(query NoteServiceQuery) ([]Note, error) {
for rows.Next() { for rows.Next() {
note := Note{} note := Note{}
err := rows.Scan(&note.ID, &note.Content, &note.Timestamp, &note.Player.ID) var ts string
err := rows.Scan(&note.ID, &note.Content, &ts, &note.Player.ID)
if err != nil { if err != nil {
return res, fmt.Errorf("failed scanning note: %v", err) return res, fmt.Errorf("failed scanning note: %v", err)
} }
note.Timestamp, err = time.Parse(time.RFC3339, ts)
if err != nil {
return res, fmt.Errorf("failed parsing timestamp: %v", err)
}
res = append(res, note) res = append(res, note)
} }
@@ -41,8 +47,9 @@ func (ns *NoteService) Query(query NoteServiceQuery) ([]Note, error) {
} }
func (ns *NoteService) Create(content string, timestamp time.Time, player Player) (Note, error) { func (ns *NoteService) Create(content string, timestamp time.Time, player Player) (Note, error) {
log.Printf("Creating note %q with timestamp %s and player %d", content, timestamp, player.ID)
note := Note{} note := Note{}
res, err := ns.db.writeConn.Exec("insert into note (content, timestamp, player) values (?, ?, ?)", content, timestamp, player.ID) res, err := ns.db.writeConn.Exec("insert into note (content, timestamp, player) values (?, ?, ?)", content, timestamp.Format(time.RFC3339), player.ID)
if err != nil { if err != nil {
return note, fmt.Errorf("failed to insert note: %v", err) return note, fmt.Errorf("failed to insert note: %v", err)
} }
@@ -51,6 +58,7 @@ func (ns *NoteService) Create(content string, timestamp time.Time, player Player
if err != nil { if err != nil {
return note, fmt.Errorf("failed to get last insert id: %v", err) return note, fmt.Errorf("failed to get last insert id: %v", err)
} }
log.Printf("Created note %q with timestamp %s and player %d with id %d", content, timestamp, player.ID, id)
qres, err := ns.Query(NoteServiceQuery{ID: &id}) qres, err := ns.Query(NoteServiceQuery{ID: &id})
if err != nil { if err != nil {

View File

@@ -1,6 +1,9 @@
package main package main
import "fmt" import (
"fmt"
"log"
)
type PlayerService struct { type PlayerService struct {
db *DB db *DB
@@ -37,6 +40,7 @@ func (ps *PlayerService) Query(query PlayerServiceQuery) ([]Player, error) {
} }
func (ps *PlayerService) Create(name string, guild Guild) (Player, error) { func (ps *PlayerService) Create(name string, guild Guild) (Player, error) {
log.Printf("Creating player %s in guild %s", name, guild.Name)
player := Player{} player := Player{}
res, err := ps.db.writeConn.Exec("insert into player (name, guild) values (?, ?)", name, guild.ID) res, err := ps.db.writeConn.Exec("insert into player (name, guild) values (?, ?)", name, guild.ID)
if err != nil { if err != nil {
@@ -47,6 +51,7 @@ func (ps *PlayerService) Create(name string, guild Guild) (Player, error) {
if err != nil { if err != nil {
return player, fmt.Errorf("failed to get last insert id: %v", err) 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}) qres, err := ps.Query(PlayerServiceQuery{ID: &id})
if err != nil { if err != nil {
@@ -62,14 +67,17 @@ func (ps *PlayerService) Create(name string, guild Guild) (Player, error) {
func (ps *PlayerService) GetOrCreate(name string, guild Guild) (Player, error) { func (ps *PlayerService) GetOrCreate(name string, guild Guild) (Player, error) {
player := Player{} player := Player{}
players, err := ps.Query(PlayerServiceQuery{Name: &name}) players, err := ps.Query(PlayerServiceQuery{Name: &name})
if err != nil { if len(players) > 1 {
if len(players) > 1 { return player, fmt.Errorf("more than one player found for name %s", name)
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) player, err = ps.Create(name, guild)
if err != nil { if err != nil {
return player, fmt.Errorf("failed creating player: %v", err) return player, fmt.Errorf("failed creating player: %v", err)
} }
} }
if len(players) == 1 {
player = players[0]
}
return player, nil return player, nil
} }

View File

@@ -3,7 +3,9 @@ package main
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"regexp"
"strings" "strings"
"time"
) )
func BuildWhereQuery(params interface{}) string { func BuildWhereQuery(params interface{}) string {
@@ -35,3 +37,80 @@ func BuildWhereQuery(params interface{}) string {
} }
return "" return ""
} }
var associationRe = regexp.MustCompile(`r:(\w+)(?:\(([^)]+)\))?`)
func ParseNote(data string) (NoteData, error) {
res := NoteData{}
lines := strings.Split(data, "\n")
note := []string{}
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" {
continue
}
parts := strings.Split(line, ":")
switch parts[0] {
case "p":
res.Player = parts[1]
case "d":
var err error
res.Date, err = time.Parse(time.DateOnly, parts[1])
if err != nil {
return res, fmt.Errorf("failed to parse date: %v", err)
}
case "g":
res.Guild = parts[1]
default:
note = append(note, line)
}
}
res.Note = strings.Join(note, "\n")
matches := associationRe.FindAllStringSubmatch(res.Note, -1)
for _, match := range matches {
res.Associations = append(res.Associations, NoteAssociationData{
Player: match[1],
Note: match[2],
})
}
return res, nil
}
func PersistNoteData(note NoteData) (Note, []Association, error) {
res := Note{}
ass := []Association{}
res.Content = note.Note
res.Timestamp = note.Date
guild, err := gs.GetOrCreate(note.Guild)
if err != nil {
return res, ass, fmt.Errorf("failed getting guild for %s: %v", note.Guild, err)
}
player, err := ps.GetOrCreate(note.Player, guild)
if err != nil {
return res, ass, fmt.Errorf("failed getting player for %s: %v", note.Player, err)
}
res.Player = player
player.Guild = guild
for _, assoc := range note.Associations {
assocPlayer, err := ps.GetOrCreate(assoc.Player, guild)
if err != nil {
return res, ass, fmt.Errorf("failed getting player for %s: %v", assoc.Player, err)
}
association, err := as.Create(player, assocPlayer, assoc.Note)
if err != nil {
return res, ass, fmt.Errorf("failed creating association: %v", err)
}
ass = append(ass, association)
}
res, err = ns.Create(res.Content, res.Timestamp, res.Player)
if err != nil {
return res, ass, fmt.Errorf("failed creating note: %v", err)
}
return res, ass, nil
}