You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
themis/conflicts.go

124 lines
3.7 KiB

package themis
import (
"context"
11 months ago
"database/sql"
"fmt"
"github.com/rs/zerolog/log"
)
type Conflict struct {
Province string
Player string
ClaimType ClaimType
Claim string
ClaimID int
}
func (c Conflict) String() string {
return fmt.Sprintf("%s owned by #%d %s %s (%s)", c.Province, c.ClaimID, c.ClaimType, c.Claim, c.Player)
}
11 months ago
// const conflictQuery string = `SELECT name, player, claim_type, val, id FROM (
// SELECT provinces.name, claims.player, claims.claim_type, claims.val, claims.id
// FROM claims
// LEFT JOIN provinces ON claims.val = provinces.trade_node
// WHERE claims.claim_type = 'trade' AND claims.userid IS NOT ?
// AND provinces.%[1]s = ?
// UNION
// SELECT provinces.name, claims.player, claims.claim_type, claims.val, claims.id
// FROM claims
// LEFT JOIN provinces ON claims.val = provinces.region
// WHERE claims.claim_type = 'region' AND claims.userid IS NOT ?
// AND provinces.%[1]s = ?
// UNION
// SELECT provinces.name, claims.player, claims.claim_type, claims.val, claims.id
// FROM claims
// LEFT JOIN provinces ON claims.val = provinces.area
// WHERE claims.claim_type = 'area' AND claims.userid IS NOT ?
// AND provinces.%[1]s = ?
// );`
const conflictQuery string = `
WITH claiming AS (
SELECT province FROM claimables
WHERE typ = ?
AND name = ?
)
SELECT claimables.province, claims.player, claims.claim_type, claims.val, claims.id
FROM claims
INNER JOIN claimables
ON claims.claim_type = claimables.typ
AND claims.val = claimables.name
INNER JOIN claiming
ON claiming.province = claimables.province
WHERE claims.userid IS NOT ?`
func (s *Store) FindConflicts(ctx context.Context, userId, name string, claimType ClaimType) ([]Conflict, error) {
log.Debug().Ctx(ctx).Stringer("claim_type", claimType).Str("userid", userId).Msg("searching for potential conflicts")
11 months ago
stmt, err := s.db.PrepareContext(ctx, conflictQuery)
if err != nil {
return nil, fmt.Errorf("failed to prepare conflicts query: %w", err)
}
11 months ago
// =========================================================================
rows, err := s.db.QueryContext(ctx, `select claims.val, claims.claim_type, claims.player, claimables.province
from claims
inner join claimables on claims.val = claimables.name and claims.claim_type = claimables.typ;
`)
if err != nil {
panic(err)
}
res2 := make([]string, 0)
for rows.Next() {
var name, typ, play string
var pro sql.NullString
if err := rows.Scan(&name, &typ, &play, &pro); err != nil {
panic(err)
}
res2 = append(res2, fmt.Sprintf("%s, %s, %s, %s", name, typ, play, pro.String))
}
log.Debug().Strs("list", res2).Msg("existing claims")
// =========================================================================
rows, err = stmt.QueryContext(ctx, claimTypeToColumn[claimType], name, userId)
if err != nil {
return nil, fmt.Errorf("failed to get conflicting provinces: %w", err)
}
conflicts := make([]Conflict, 0)
for rows.Next() {
var (
province string
player string
sClaimType string
claimName string
claimId int
)
err = rows.Scan(&province, &player, &sClaimType, &claimName, &claimId)
if err != nil {
return nil, fmt.Errorf("failed to scan row: %w", err)
}
ct, err := ClaimTypeFromString(sClaimType)
if err != nil {
// In case of an error parsing the claim type, simply default to
// whatever the database sends; this is a read-only function, the
// input validation is assumed to have already been done at insert.
ct = ClaimType(sClaimType)
}
conflicts = append(conflicts, Conflict{
Province: province,
Player: player,
ClaimType: ct,
Claim: claimName,
ClaimID: claimId,
})
}
return conflicts, nil
}