From 4f14040747f3833e0129b5705b971802e1562e72 Mon Sep 17 00:00:00 2001 From: The Magician Date: Sun, 8 Sep 2024 00:24:24 +0100 Subject: [PATCH] Add "locate from file" feature --- sevenkeys/cli/mainui.go | 26 +++++++------- sevenkeys/database/locate.go | 17 ++++++--- sevenkeys/go.mod | 1 + sevenkeys/go.sum | 4 +++ sevenkeys/logic/file.go | 25 ++++++++++++++ sevenkeys/logic/locate.go | 63 ++++++++++++++++++++++++++++++++-- sevenkeys/logic/locate_test.go | 25 ++++++++++++++ 7 files changed, 141 insertions(+), 20 deletions(-) create mode 100644 sevenkeys/logic/file.go create mode 100644 sevenkeys/logic/locate_test.go diff --git a/sevenkeys/cli/mainui.go b/sevenkeys/cli/mainui.go index cb6efd5..216016b 100644 --- a/sevenkeys/cli/mainui.go +++ b/sevenkeys/cli/mainui.go @@ -26,6 +26,14 @@ func MainCliLoop(db *sql.DB) { } var insertSearchOptions logic.InsertSearchOptions + // TODO: Make these do something and add the ability to modify them + var locateSearchCriteria logic.SearchCriteria = logic.SearchCriteria{ + SetCode: "", + Foil: logic.True, + Promo: logic.Either, + Language: "en", + } + for { ShowSplashScreen() showStorageInfo(os.Stdout, selectedStorageArea) @@ -81,23 +89,15 @@ func MainCliLoop(db *sql.DB) { insertSelectedCard(db, selectedStorageArea, cardLocation) break case "l", "locate": - cardName := GetStringResponse("Card name:") + filename := GetStringResponse("Filename:") + cardNames, err := logic.GetCardNamesFromFile(filename) + logic.Check(err) - locations, err := logic.LocateCards(db, cardName) + locations, err := logic.LocateCards(db, cardNames, locateSearchCriteria) logic.Check(err) for _, location := range locations { - fmt.Printf("%s (%s %s) [%s]", location.CardName, location.SetCode, location.CollectorNumber, location.Language) - - if location.IsFoil { - fmt.Printf(" FOIL") - } - - if location.IsPromo { - fmt.Printf(" PROMO") - } - - fmt.Printf(" in %s \"%s\" at position %d\n", location.StorageAreaType, location.StorageAreaName, location.Position) + fmt.Println(location) } fmt.Scanln() diff --git a/sevenkeys/database/locate.go b/sevenkeys/database/locate.go index 76353b5..cb1f217 100644 --- a/sevenkeys/database/locate.go +++ b/sevenkeys/database/locate.go @@ -1,6 +1,10 @@ package database -import "database/sql" +import ( + "database/sql" + + "github.com/jmoiron/sqlx" +) type LocateCardResult struct { CardName string @@ -14,11 +18,16 @@ type LocateCardResult struct { Position int } -func GetLocateCardResultsByCardName(db *sql.DB, cardName string) ([]LocateCardResult, error) { +func GetLocateResults(db *sql.DB, cardNames []string) ([]LocateCardResult, error) { var results []LocateCardResult - query := "SELECT CardPrinting.Name, CardPrinting.SetCode, CardPrinting.IsFoil, CardPrinting.IsPromo, CardPrinting.CollectorNumber, CardPrinting.Language, StorageArea.StorageType, StorageArea.Name, CardLocation.Position FROM CardLocation JOIN CardPrinting ON CardLocation.CardPrintingId = CardPrinting.Id JOIN StorageArea ON CardLocation.StorageAreaId = StorageArea.Id WHERE CardPrinting.Name = ?;" - rows, err := db.Query(query, cardName) + query := "SELECT CardPrinting.Name, CardPrinting.SetCode, CardPrinting.IsFoil, CardPrinting.IsPromo, CardPrinting.CollectorNumber, CardPrinting.Language, StorageArea.StorageType, StorageArea.Name, CardLocation.Position FROM CardLocation JOIN CardPrinting ON CardLocation.CardPrintingId = CardPrinting.Id JOIN StorageArea ON CardLocation.StorageAreaId = StorageArea.Id WHERE CardPrinting.Name IN (?);" + query, args, err := sqlx.In(query, cardNames) + if err != nil { + return results, err + } + + rows, err := db.Query(query, args...) defer rows.Close() if err != nil { return results, err diff --git a/sevenkeys/go.mod b/sevenkeys/go.mod index 2a1e0fb..9b41e78 100644 --- a/sevenkeys/go.mod +++ b/sevenkeys/go.mod @@ -17,6 +17,7 @@ require ( github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lukesampson/figlet v0.0.0-20190211215653-8a3ef4a6ac42 // indirect github.com/mattn/go-isatty v0.0.18 // indirect diff --git a/sevenkeys/go.sum b/sevenkeys/go.sum index cf1a592..ff0b383 100644 --- a/sevenkeys/go.sum +++ b/sevenkeys/go.sum @@ -20,6 +20,9 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 h1:fO9A67/izFYFYky7l1pDP5Dr0BTCRkaQJUG6Jm5ehsk= github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3/go.mod h1:Ey4uAp+LvIl+s5jRbOHLcZpUDnkjLBROl15fZLwPlTM= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lukesampson/figlet v0.0.0-20190211215653-8a3ef4a6ac42 h1:UtyD+eBVdLYSj5/pjfSR6mtnzMgIiOVcFT024G2l4CY= @@ -31,6 +34,7 @@ github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+Ei github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= diff --git a/sevenkeys/logic/file.go b/sevenkeys/logic/file.go new file mode 100644 index 0000000..58f4e5c --- /dev/null +++ b/sevenkeys/logic/file.go @@ -0,0 +1,25 @@ +package logic + +import ( + "bufio" + "os" +) + +func GetCardNamesFromFile(filename string) ([]string, error) { + var cardNames []string + + file, err := os.Open(filename) + defer file.Close() + if err != nil { + return cardNames, err + } + + scanner := bufio.NewScanner(file) + scanner.Split(bufio.ScanLines) + + for scanner.Scan() { + cardNames = append(cardNames, scanner.Text()) + } + + return cardNames, nil +} diff --git a/sevenkeys/logic/locate.go b/sevenkeys/logic/locate.go index 754378d..bf9fc31 100644 --- a/sevenkeys/logic/locate.go +++ b/sevenkeys/logic/locate.go @@ -2,10 +2,67 @@ package logic import ( "database/sql" + "fmt" "sevenkeys/database" ) -func LocateCards(db *sql.DB, cardName string) ([]database.LocateCardResult, error) { - results, err := database.GetLocateCardResultsByCardName(db, cardName) - return results, err +const SLOTS_PER_BINDER_PAGE = 18 // TODO: Make this configurable + +func GetBinderLocationDescription(position int) string { + var page int = (position / SLOTS_PER_BINDER_PAGE) + 1 + + var pagePosition int = position % SLOTS_PER_BINDER_PAGE + + var slot int + var frontOrBack string + + if pagePosition <= (SLOTS_PER_BINDER_PAGE / 2) { + slot = pagePosition + frontOrBack = "front" + } else { + slot = pagePosition - (SLOTS_PER_BINDER_PAGE / 2) + frontOrBack = "back" + } + + return fmt.Sprintf(" on page %d in %s slot %d", page, frontOrBack, slot) +} + +func LocateCards(db *sql.DB, cardNames []string, criteria SearchCriteria) ([]string, error) { + var locations []string + + results, err := database.GetLocateResults(db, cardNames) + if err != nil { + return locations, err + } + // TODO: Filter by search criteria + + var location string + for _, result := range results { + location = fmt.Sprintf("%s (%s %s) [%s]", + result.CardName, + result.SetCode, + result.CollectorNumber, + result.Language) + + if result.IsFoil { + location += " FOIL" + } + if result.IsPromo { + location += " PROMO" + } + + location += fmt.Sprintf(" in %s \"%s\"", + result.StorageAreaType, + result.StorageAreaName) + + if result.StorageAreaType == "Binder" { + location += GetBinderLocationDescription(result.Position) + } else if result.StorageAreaType == "Box" { + location += fmt.Sprintf(" at position %d", result.Position) + } + + locations = append(locations, location) + } + + return locations, nil } diff --git a/sevenkeys/logic/locate_test.go b/sevenkeys/logic/locate_test.go new file mode 100644 index 0000000..cd27632 --- /dev/null +++ b/sevenkeys/logic/locate_test.go @@ -0,0 +1,25 @@ +package logic + +import "testing" + +func Test_GetBinderLocationDescription_ReturnsCorrectFormat_ForFrontSlots(t *testing.T) { + var position int = 24 + var expected string = "on page 2 in front slot 6" + + description := GetBinderLocationDescription(position) + + if description != expected { + t.Errorf("expected %s, got %s\n", expected, description) + } +} + +func Test_GetBinderLocationDescription_ReturnsCorrectFormat_ForBackSlots(t *testing.T) { + var position int = 17 + var expected string = "on page 1 in back slot 8" + + description := GetBinderLocationDescription(position) + + if description != expected { + t.Errorf("expected %s, got %s\n", expected, description) + } +}