Compare commits

..

No commits in common. "70f0b4d4f7b5fe428d0ac75821b48b4199b6a17d" and "1e967674b68e34fa06cd1b2fe924f4db9076c152" have entirely different histories.

13 changed files with 145 additions and 325 deletions

View File

@ -4,9 +4,9 @@ import (
"database/sql" "database/sql"
"errors" "errors"
"fmt" "fmt"
"os"
"os/exec" "os/exec"
"sevenkeys/database" "sevenkeys/database"
"sevenkeys/delverlens"
"sevenkeys/logic" "sevenkeys/logic"
) )
@ -15,7 +15,7 @@ var output string
func MainCliLoop(db *sql.DB) { func MainCliLoop(db *sql.DB) {
var command string var command string
//var selectedStorageAreaName string var selectedStorageArea database.StorageArea
var cardLocation database.CardLocation var cardLocation database.CardLocation
var insertSearchCriteria logic.SearchCriteria = logic.SearchCriteria{ var insertSearchCriteria logic.SearchCriteria = logic.SearchCriteria{
@ -26,18 +26,17 @@ func MainCliLoop(db *sql.DB) {
} }
var insertSearchOptions logic.InsertSearchOptions var insertSearchOptions logic.InsertSearchOptions
// TODO: Add the ability to modify this // TODO: Make these do something and add the ability to modify them
var locateSearchCriteria logic.SearchCriteria = logic.SearchCriteria{ var locateSearchCriteria logic.SearchCriteria = logic.SearchCriteria{
SetCode: "", SetCode: "",
Foil: logic.True, Foil: logic.Either,
Promo: logic.Either, Promo: logic.Either,
Language: "en", Language: "en",
} }
for { for {
ShowSplashScreen() ShowSplashScreen()
// TODO: Fix this showStorageInfo(os.Stdout, selectedStorageArea)
//showStorageInfo(os.Stdout, selectedStorageAreaName)
showInsertSearchCriteria(insertSearchCriteria) showInsertSearchCriteria(insertSearchCriteria)
showSelectedCard() showSelectedCard()
showCopiesInserted() showCopiesInserted()
@ -57,14 +56,10 @@ func MainCliLoop(db *sql.DB) {
logic.Check(err) logic.Check(err)
break break
case "a", "area": case "a", "area":
options, err := logic.GetStorageAreaSearchOptions(db) area, err := logic.SelectStorageArea(db)
logic.Check(err) logic.Check(err)
selectedStorageArea = area
id, _, err := logic.GenericSearch(options) cardLocation.StorageAreaId = area.Id
logic.Check(err)
//selectedStorageAreaName = name
cardLocation.StorageAreaId = id
break break
case "c", "criteria": case "c", "criteria":
insertSearchCriteria = getSearchCriteria() insertSearchCriteria = getSearchCriteria()
@ -76,9 +71,8 @@ func MainCliLoop(db *sql.DB) {
var previousCardPrintingId = cardLocation.CardPrintingId var previousCardPrintingId = cardLocation.CardPrintingId
pk, searchLine, err := logic.GenericSearch(insertSearchOptions) pk, err := logic.GenericSearch(insertSearchOptions)
cardLocation.CardPrintingId = pk cardLocation.CardPrintingId = pk
selectedCardPrintingSearchLine = searchLine
var exitError *exec.ExitError var exitError *exec.ExitError
if errors.As(err, &exitError) { if errors.As(err, &exitError) {
@ -92,18 +86,7 @@ func MainCliLoop(db *sql.DB) {
} }
break break
case "i", "insert": case "i", "insert":
err := logic.StoreCard(db, cardLocation) insertSelectedCard(db, selectedStorageArea, cardLocation)
logic.Check(err)
copiesInserted++
break
case "d", "delverlens":
filename := GetStringResponse("Filename:")
cards, err := delverlens.ParseExportFile(filename)
logic.Check(err)
err = logic.ImportDelverLensCards(cards)
logic.Check(err)
break break
case "l", "locate": case "l", "locate":
filename := GetStringResponse("Filename:") filename := GetStringResponse("Filename:")
@ -113,32 +96,11 @@ func MainCliLoop(db *sql.DB) {
locations, err := logic.LocateCards(db, cardNames, locateSearchCriteria) locations, err := logic.LocateCards(db, cardNames, locateSearchCriteria)
logic.Check(err) logic.Check(err)
if len(locations) == 0 {
fmt.Println("No results found")
fmt.Scanln()
break
}
for _, location := range locations { for _, location := range locations {
description := logic.GetLocationDescription(location) fmt.Println(location)
fmt.Println(description)
for true {
todo := GetStringResponse("TODO:")
if todo == "r" {
logic.RemoveFromStorage(db, location)
break
} else if todo == "n" {
break
} else {
fmt.Printf("Unrecognized option: %s\n", todo)
} }
}
}
fmt.Println("Though this query has ended, its relics still slumber in New Argive.")
fmt.Scanln() fmt.Scanln()
break break
default: default:
fmt.Println("Unrecognized command:", command) fmt.Println("Unrecognized command:", command)

View File

@ -1,9 +1,11 @@
package cli package cli
import ( import (
"database/sql"
"fmt" "fmt"
"io" "io"
"sevenkeys/database" "sevenkeys/database"
"sevenkeys/logic"
) )
var ( var (
@ -34,3 +36,20 @@ func showStorageInfo(w io.Writer, area database.StorageArea) {
func showCopiesInserted() { func showCopiesInserted() {
fmt.Println("Copies inserted:", copiesInserted) fmt.Println("Copies inserted:", copiesInserted)
} }
func insertSelectedCard(db *sql.DB, area database.StorageArea, location database.CardLocation) {
if area.Name == "" {
output = "No storage area selected."
return
}
if location.CardPrintingId == "" {
output = "No card selected, please [search] for a card printing."
return
}
err := logic.StoreCard(db, location)
logic.Check(err)
copiesInserted++
}

View File

@ -43,19 +43,3 @@ func InsertCardLocation(db *sql.DB, storageLocation CardLocation) error {
return nil return nil
} }
func InsertCardInExistingLocation(db *sql.DB, cardLocation CardLocation) error {
query := `UPDATE CardLocation SET CardPrintingId = ? WHERE Id = ?;`
update, err := db.Prepare(query)
if err != nil {
return err
}
_, err = update.Exec(cardLocation.CardPrintingId, cardLocation.Id)
if err != nil {
return err
}
return nil
}

View File

@ -7,14 +7,12 @@ import (
) )
type LocateCardResult struct { type LocateCardResult struct {
CardLocationId int
CardName string CardName string
SetCode string SetCode string
IsFoil bool IsFoil bool
IsPromo bool IsPromo bool
CollectorNumber string CollectorNumber string
Language string Language string
StorageAreaId int
StorageAreaType string StorageAreaType string
StorageAreaName string StorageAreaName string
Position int Position int
@ -23,21 +21,7 @@ type LocateCardResult struct {
func GetLocateResults(db *sql.DB, cardNames []string) ([]LocateCardResult, error) { func GetLocateResults(db *sql.DB, cardNames []string) ([]LocateCardResult, error) {
var results []LocateCardResult var results []LocateCardResult
query := `SELECT CardLocation.Id, 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 (?);"
CardPrinting.Name,
CardPrinting.SetCode,
CardPrinting.IsFoil,
CardPrinting.IsPromo,
CardPrinting.CollectorNumber,
CardPrinting.Language,
StorageArea.Id,
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) query, args, err := sqlx.In(query, cardNames)
if err != nil { if err != nil {
return results, err return results, err
@ -51,7 +35,7 @@ func GetLocateResults(db *sql.DB, cardNames []string) ([]LocateCardResult, error
var result LocateCardResult var result LocateCardResult
for rows.Next() { for rows.Next() {
err := rows.Scan(&result.CardLocationId, &result.CardName, &result.SetCode, &result.IsFoil, &result.IsPromo, &result.CollectorNumber, &result.Language, &result.StorageAreaId, &result.StorageAreaType, &result.StorageAreaName, &result.Position) err := rows.Scan(&result.CardName, &result.SetCode, &result.IsFoil, &result.IsPromo, &result.CollectorNumber, &result.Language, &result.StorageAreaType, &result.StorageAreaName, &result.Position)
if err != nil { if err != nil {
return results, err return results, err
} }

View File

@ -2,8 +2,8 @@ package database
import "database/sql" import "database/sql"
func RemoveFromBinder(db *sql.DB, location LocateCardResult) error { func RemoveFromBinder(db *sql.DB, location CardLocation) error {
query := `UPDATE CardLocation SET CardPrintingId = NULL WHERE Id = ?;` query := `UPDATE CardStorageLocation SET CardPrintingId = NULL WHERE Id = ?;`
update, err := db.Prepare(query) update, err := db.Prepare(query)
defer update.Close() defer update.Close()
@ -11,7 +11,7 @@ func RemoveFromBinder(db *sql.DB, location LocateCardResult) error {
return err return err
} }
_, err = update.Exec(location.CardLocationId) _, err = update.Exec(location.Id)
if err != nil { if err != nil {
return err return err
} }
@ -19,8 +19,8 @@ func RemoveFromBinder(db *sql.DB, location LocateCardResult) error {
return nil return nil
} }
func RemoveFromBox(db *sql.DB, location LocateCardResult) error { func RemoveFromBox(db *sql.DB, location CardLocation) error {
deleteQuery := `DELETE FROM CardLocation WHERE Id = ?;` deleteQuery := `DELETE FROM CardStorageLocation WHERE Id = ?;`
del, err := db.Prepare(deleteQuery) del, err := db.Prepare(deleteQuery)
defer del.Close() defer del.Close()
@ -28,12 +28,12 @@ func RemoveFromBox(db *sql.DB, location LocateCardResult) error {
return err return err
} }
_, err = del.Exec(location.CardLocationId) _, err = del.Exec(location.Id)
if err != nil { if err != nil {
return err return err
} }
updateQuery := `UPDATE CardLocation SET Position = Position - 1 WHERE Position > ? AND StorageAreaId = ?;` updateQuery := `UPDATE CardStorageLocation SET Position = Position - 1 WHERE Position > 5;`
update, err := db.Prepare(updateQuery) update, err := db.Prepare(updateQuery)
defer update.Close() defer update.Close()
@ -41,7 +41,7 @@ func RemoveFromBox(db *sql.DB, location LocateCardResult) error {
return err return err
} }
_, err = update.Exec(location.Position, location.StorageAreaId) _, err = update.Exec(location.Id)
if err != nil { if err != nil {
return err return err
} }

View File

@ -34,34 +34,6 @@ func GetAllStorageAreas(db *sql.DB) ([]StorageArea, error) {
return storageAreas, nil return storageAreas, nil
} }
func GetStorageAreaTypeById(db *sql.DB, storageAreaId int) (string, error) {
var storageType string
query := `SELECT StorageType FROM StorageArea WHERE Id = ?;`
row := db.QueryRow(query, storageAreaId)
err := row.Scan(&storageType)
if err != nil {
return storageType, err
}
return storageType, nil
}
func GetNextEmptySlotInBinder(db *sql.DB, storageAreaId int) (int, error) {
query := `SELECT Id FROM CardLocation WHERE CardPrintingId IS NULL AND StorageAreaId = ? ORDER BY Position ASC LIMIT 1;`
var emptySlotId int
err := db.QueryRow(query, storageAreaId).Scan(&emptySlotId)
if err == sql.ErrNoRows {
return -1, nil
} else if err != nil {
return 0, err
}
return emptySlotId, nil
}
func InsertStorageArea(db *sql.DB, storageArea StorageArea) error { func InsertStorageArea(db *sql.DB, storageArea StorageArea) error {
query := `INSERT INTO StorageArea (Name, StorageType) VALUES (?, ?);` query := `INSERT INTO StorageArea (Name, StorageType) VALUES (?, ?);`
@ -77,3 +49,17 @@ func InsertStorageArea(db *sql.DB, storageArea StorageArea) error {
return nil return nil
} }
func GetStorageAreaTypeById(db *sql.DB, storageAreaId int) (string, error) {
var storageType string
query := `SELECT StorageType FROM StorageArea WHERE Id = ?;`
row := db.QueryRow(query, storageAreaId)
err := row.Scan(&storageType)
if err != nil {
return storageType, err
}
return storageType, nil
}

View File

@ -1,50 +0,0 @@
package delverlens
import (
"encoding/csv"
"io"
"os"
"strings"
)
type DelverLensCard struct {
ScryfallID string
IsFoil bool
}
func ParseExportFile(filename string) ([]DelverLensCard, error) {
var cards []DelverLensCard
file, err := os.Open("/home/viciouscirce/dox/sevenkeys_imports/" + filename)
if err != nil {
return cards, err
}
r := csv.NewReader(file)
var isHeader bool = true
for {
record, err := r.Read()
if err == io.EOF {
break
} else if err != nil {
return cards, err
}
// Skip the header line
if isHeader {
isHeader = false
continue
}
card := DelverLensCard{
Name: record[0],
IsFoil: record[1] == "Foil",
CollectorNumber: record[2],
SetCode: strings.ToLower(record[3]),
}
cards = append(cards, card)
}
return cards, nil
}

View File

@ -1,25 +0,0 @@
package logic
import (
"database/sql"
"sevenkeys/database"
"sevenkeys/delverlens"
)
func ImportDelverLensCards(db *sql.DB, cards []delverlens.DelverLensCard, storageAreaId int) error {
for _, card := range cards {
var cardPrintingId string
if card.IsFoil {
cardPrintingId = card.ScryfallID + "n"
} else {
cardPrintingId = card.ScryfallID + "f"
}
cardLocation := database.CardLocation{
CardPrintingId: cardPrintingId,
StorageAreaId: storageAreaId,
}
StoreCard(cardLocation)
}
}

View File

@ -9,12 +9,9 @@ import (
const SLOTS_PER_BINDER_PAGE = 18 // TODO: Make this configurable const SLOTS_PER_BINDER_PAGE = 18 // TODO: Make this configurable
func GetBinderLocationDescription(position int) string { func GetBinderLocationDescription(position int) string {
var page int = ((position - 1) / SLOTS_PER_BINDER_PAGE) + 1 var page int = (position / SLOTS_PER_BINDER_PAGE) + 1
var pagePosition int = position % SLOTS_PER_BINDER_PAGE var pagePosition int = position % SLOTS_PER_BINDER_PAGE
if pagePosition == 0 {
pagePosition = SLOTS_PER_BINDER_PAGE
}
var slot int var slot int
var frontOrBack string var frontOrBack string
@ -30,14 +27,15 @@ func GetBinderLocationDescription(position int) string {
return fmt.Sprintf(" on page %d in %s slot %d", page, frontOrBack, slot) return fmt.Sprintf(" on page %d in %s slot %d", page, frontOrBack, slot)
} }
func LocateCards(db *sql.DB, cardNames []string, criteria SearchCriteria) ([]database.LocateCardResult, error) { func LocateCards(db *sql.DB, cardNames []string, criteria SearchCriteria) ([]string, error) {
var locations []string
results, err := database.GetLocateResults(db, cardNames) results, err := database.GetLocateResults(db, cardNames)
if err != nil { if err != nil {
return results, err return locations, err
} }
var filteredResults []database.LocateCardResult var location string
for _, result := range results { for _, result := range results {
printing := database.CardPrinting{ printing := database.CardPrinting{
SetCode: result.SetCode, SetCode: result.SetCode,
@ -51,37 +49,31 @@ func LocateCards(db *sql.DB, cardNames []string, criteria SearchCriteria) ([]dat
continue continue
} }
filteredResults = append(filteredResults, result) 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"
} }
return filteredResults, nil 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)
} }
func GetLocationDescription(location database.LocateCardResult) string { locations = append(locations, location)
var description string
description = fmt.Sprintf("%s (%s %s) [%s]",
location.CardName,
location.SetCode,
location.CollectorNumber,
location.Language)
if location.IsFoil {
description += " FOIL"
}
if location.IsPromo {
description += " PROMO"
} }
description += fmt.Sprintf(" in %s \"%s\"", return locations, nil
location.StorageAreaType,
location.StorageAreaName)
if location.StorageAreaType == "Binder" {
description += GetBinderLocationDescription(location.Position)
} else if location.StorageAreaType == "Box" {
description += fmt.Sprintf(" at position %d", location.Position)
}
return description
} }

View File

@ -2,44 +2,24 @@ package logic
import "testing" import "testing"
func assert(t *testing.T, description string, expected string) { 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 { if description != expected {
t.Errorf("expected \"%s\", got \"%s\"\n", expected, description) t.Errorf("expected %s, got %s\n", expected, description)
} }
} }
func Test_GetBinderLocationDescription_ReturnsCorrectSlotNumber_ForFirstSlotInPage(t *testing.T) { func Test_GetBinderLocationDescription_ReturnsCorrectFormat_ForBackSlots(t *testing.T) {
var position int = 1 var position int = 17
var expected string = " on page 1 in front slot 1" var expected string = " on page 1 in back slot 8"
description := GetBinderLocationDescription(position) description := GetBinderLocationDescription(position)
assert(t, description, expected) if description != expected {
t.Errorf("expected %s, got %s\n", expected, description)
} }
func Test_GetBinderLocationDescription_ReturnsCorrectSlotNumber_ForFirstSlotOnBackOfPage(t *testing.T) {
var position int = 10
var expected string = " on page 1 in back slot 1"
description := GetBinderLocationDescription(position)
assert(t, description, expected)
}
func Test_GetBinderLocationDescription_ReturnsCorrectSlotNumber_ForLastSlotOnBackOfPage(t *testing.T) {
var position int = 18
var expected string = " on page 1 in back slot 9"
description := GetBinderLocationDescription(position)
assert(t, description, expected)
}
func Test_GetBinderLocationDescription_ReturnsCorrectSlotNumber_ForLastSlotOnBackOfSecondPage(t *testing.T) {
var position int = 36
var expected string = " on page 2 in back slot 9"
description := GetBinderLocationDescription(position)
assert(t, description, expected)
} }

View File

@ -9,10 +9,15 @@ import (
var UnrecognizedStorageAreaTypeError error = errors.New("Unrecognized storage area type.") var UnrecognizedStorageAreaTypeError error = errors.New("Unrecognized storage area type.")
func RemoveFromStorage(db *sql.DB, location database.LocateCardResult) error { func RemoveFromStorage(db *sql.DB, location database.CardLocation) error {
if location.StorageAreaType == database.StorageAreaTypeBinder { locationType, err := database.GetStorageAreaTypeById(db, location.Id)
if err != nil {
return err
}
if locationType == database.StorageAreaTypeBinder {
database.RemoveFromBinder(db, location) database.RemoveFromBinder(db, location)
} else if location.StorageAreaType == database.StorageAreaTypeBox { } else if locationType == database.StorageAreaTypeBox {
database.RemoveFromBox(db, location) database.RemoveFromBox(db, location)
} else { } else {
return UnrecognizedStorageAreaTypeError return UnrecognizedStorageAreaTypeError

View File

@ -61,7 +61,7 @@ func GetAllSearchOptions(db *sql.DB, searchCriteria SearchCriteria) (InsertSearc
return searchOptions, err return searchOptions, err
} }
func GenericSearch[pk string | int](options map[string]pk) (pk, string, error) { func GenericSearch[pk string | int](options map[string]pk) (pk, error) {
var value pk var value pk
cmd := exec.Command("fzf") cmd := exec.Command("fzf")
@ -69,7 +69,7 @@ func GenericSearch[pk string | int](options map[string]pk) (pk, string, error) {
fzfStdin, err := cmd.StdinPipe() fzfStdin, err := cmd.StdinPipe()
if err != nil { if err != nil {
return value, "", err return value, err
} }
go func() { go func() {
@ -81,10 +81,10 @@ func GenericSearch[pk string | int](options map[string]pk) (pk, string, error) {
fzfOutput, err := cmd.Output() fzfOutput, err := cmd.Output()
if err != nil { if err != nil {
return value, "", err return value, err
} }
searchResult := strings.TrimSuffix(string(fzfOutput), "\n") searchResult := strings.TrimSuffix(string(fzfOutput), "\n")
value = options[searchResult] value = options[searchResult]
return value, searchResult, nil return value, nil
} }

View File

@ -2,11 +2,13 @@ package logic
import ( import (
"database/sql" "database/sql"
"io"
"os"
"os/exec"
"sevenkeys/database" "sevenkeys/database"
"strings"
) )
type StorageAreaSearchOptions map[string]int
func CreateStorageArea(db *sql.DB, storageArea database.StorageArea) error { func CreateStorageArea(db *sql.DB, storageArea database.StorageArea) error {
// TODO: Check if there's already a storage are with the same name // TODO: Check if there's already a storage are with the same name
// TODO: Check if the type entered is valid // TODO: Check if the type entered is valid
@ -18,22 +20,46 @@ func CreateStorageArea(db *sql.DB, storageArea database.StorageArea) error {
return nil return nil
} }
func GetStorageAreaSearchOptions(db *sql.DB) (StorageAreaSearchOptions, error) { func SelectStorageArea(db *sql.DB) (database.StorageArea, error) {
var options StorageAreaSearchOptions var selectedStorageArea database.StorageArea
storageAreas, err := database.GetAllStorageAreas(db) storageAreas, err := database.GetAllStorageAreas(db)
if err != nil { if err != nil {
return options, err return selectedStorageArea, err
} }
cmd := exec.Command("fzf")
cmd.Stderr = os.Stderr
fzfStdin, err := cmd.StdinPipe()
if err != nil {
return selectedStorageArea, err
}
go func() {
defer fzfStdin.Close()
for _, area := range storageAreas { for _, area := range storageAreas {
options[area.Name] = area.Id io.WriteString(fzfStdin, area.Name+"\n")
}
}()
fzfOutput, err := cmd.Output()
if err != nil {
return selectedStorageArea, err
} }
return options, nil key := strings.TrimSuffix(string(fzfOutput), "\n")
for _, area := range storageAreas {
if area.Name == key {
selectedStorageArea = area
break
}
} }
func StoreAfterLastCard(db *sql.DB, cardLocation database.CardLocation) error { return selectedStorageArea, nil
}
func StoreCard(db *sql.DB, cardLocation database.CardLocation) error {
lastPosition, err := database.GetLastPositionInStorageArea(db, cardLocation.StorageAreaId) lastPosition, err := database.GetLastPositionInStorageArea(db, cardLocation.StorageAreaId)
if err != nil { if err != nil {
return err return err
@ -48,46 +74,3 @@ func StoreAfterLastCard(db *sql.DB, cardLocation database.CardLocation) error {
return nil return nil
} }
func StoreInEmptySlot(db *sql.DB, cardLocation database.CardLocation, cardLocationId int) error {
cardLocation.Id = cardLocationId
err := database.InsertCardInExistingLocation(db, cardLocation)
if err != nil {
return err
}
return nil
}
func StoreCard(db *sql.DB, cardLocation database.CardLocation) error {
storageAreaType, err := database.GetStorageAreaTypeById(db, cardLocation.StorageAreaId)
if err != nil {
return err
}
if storageAreaType == database.StorageAreaTypeBinder {
nextEmptySlotId, err := database.GetNextEmptySlotInBinder(db, cardLocation.StorageAreaId)
if err == sql.ErrNoRows {
err = StoreAfterLastCard(db, cardLocation)
if err != nil {
return err
}
} else if err != nil {
return err
} else {
err = StoreInEmptySlot(db, cardLocation, nextEmptySlotId)
if err != nil {
return err
}
}
return nil
}
err = StoreAfterLastCard(db, cardLocation)
if err != nil {
return err
}
return nil
}