paper-dynasty-database/app/db_engine.py
Cal Corum ec04a111c5
All checks were successful
Build Docker Image / build (pull_request) Successful in 8m32s
fix: remove legacy SQLite compatibility code (#122)
Closes #122

Both prod and dev environments use PostgreSQL. Removes all SQLite
compatibility code that was never exercised in practice.

Changes:
- db_engine.py: replace SQLite/PostgreSQL branching with direct
  PooledPostgresqlDatabase init; remove DATABASE_TYPE, SKIP_TABLE_CREATION,
  all db.create_tables() calls, and commented-out SQLite scout_db code
- db_helpers.py: remove DATABASE_TYPE var and SQLite on_conflict_replace
  branch from upsert_many(); PostgreSQL ON CONFLICT is now the only path
- players.py: update stale comment
- tests/conftest.py: remove DATABASE_TYPE env var (no longer needed);
  keep POSTGRES_PASSWORD dummy for instantiation
- CLAUDE.md: update SQLite references to PostgreSQL

Note: unit tests in test_evolution_seed.py and test_season_stats_model.py
use SqliteDatabase(':memory:') for test isolation — this is legitimate test
infrastructure, not production SQLite compatibility code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 23:37:02 -05:00

1106 lines
30 KiB
Python

import math
from datetime import datetime
from typing import List
import logging
import os
from pandas import DataFrame
from peewee import *
from peewee import ModelSelect
from playhouse.shortcuts import model_to_dict
from playhouse.pool import PooledPostgresqlDatabase
db = PooledPostgresqlDatabase(
os.environ.get("POSTGRES_DB", "pd_master"),
user=os.environ.get("POSTGRES_USER", "pd_admin"),
password=os.environ.get("POSTGRES_PASSWORD"),
host=os.environ.get("POSTGRES_HOST", "localhost"),
port=int(os.environ.get("POSTGRES_PORT", "5432")),
max_connections=20,
stale_timeout=300, # 5 minutes
timeout=0,
autoconnect=True,
autorollback=True, # Automatically rollback failed transactions
)
# 2025, 2005
ranked_cardsets = [24, 25, 26, 27, 28, 29]
LIVE_CARDSET_ID = 27
LIVE_PROMO_CARDSET_ID = 28
CARDSETS = {
"ranked": {"primary": ranked_cardsets, "human": ranked_cardsets},
"minor-league": {
"primary": [27, 8], # 2005, Mario
"secondary": [24], # 2025
"human": [x for x in range(1, 30)],
},
"major-league": {
"primary": [
27,
28,
24,
25,
13,
14,
6,
8,
], # 2005 + Promos, 2025 + Promos, 2018 + Promos, 2012, Mario
"secondary": [5, 3], # 2019, 2022
"human": ranked_cardsets,
},
"hall-of-fame": {"primary": [x for x in range(1, 30)], "human": ranked_cardsets},
"flashback": {
"primary": [
13,
14,
5,
1,
3,
4,
8,
], # 2018 + Promos, 2019, 2021, 2022 + Promos, Mario
"secondary": [24], # 2025
"human": [13, 14, 5, 1, 3, 4, 8], # 2018 + Promos, 2019, 2021, 2022 + Promos
},
"gauntlet-3": {
"primary": [13], # 2018
"secondary": [5, 11, 9], # 2019, 2016, 2023
"human": [x for x in range(1, 30)],
},
"gauntlet-4": {
"primary": [3, 6, 16], # 2022, 2013, Backyard Baseball
"secondary": [4, 9], # 2022 Promos, 2023
"human": [3, 4, 6, 9, 15, 16],
},
"gauntlet-5": {
"primary": [17, 8], # 2024, Mario
"secondary": [13], # 2018
"human": [x for x in range(1, 30)],
},
"gauntlet-6": {
"primary": [20, 8], # 1998, Mario
"secondary": [12], # 2008
"human": [x for x in range(1, 30)],
},
"gauntlet-7": {
"primary": [5, 23], # 2019, Brilliant Stars
"secondary": [1], # 2021
"human": [x for x in range(1, 30)],
},
"gauntlet-8": {
"primary": [24], # 2025
"secondary": [17],
"human": [24, 25, 22, 23],
},
"gauntlet-9": {
"primary": [27], # 2005
"secondary": [24], # 2025
"human": [x for x in range(1, 30)],
},
}
def model_csv_headers(this_obj, exclude=None) -> List:
data = model_to_dict(this_obj, recurse=False, exclude=exclude)
return [x for x in data.keys()]
def model_to_csv(this_obj, exclude=None) -> List:
data = model_to_dict(this_obj, recurse=False, exclude=exclude)
return [x for x in data.values()]
def query_to_csv(all_items: ModelSelect, exclude=None):
if all_items.count() == 0:
data_list = [["No data found"]]
else:
data_list = [model_csv_headers(all_items[0], exclude=exclude)]
for x in all_items:
data_list.append(model_to_csv(x, exclude=exclude))
return DataFrame(data_list).to_csv(header=False, index=False)
def complex_data_to_csv(complex_data: List):
if len(complex_data) == 0:
data_list = [["No data found"]]
else:
data_list = [[x for x in complex_data[0].keys()]]
for line in complex_data:
logging.debug(f"line: {line}")
this_row = []
for key in line:
logging.debug(f"key: {key}")
if line[key] is None:
this_row.append("")
elif isinstance(line[key], dict):
if "name" in line[key]:
this_row.append(line[key]["name"])
elif "abbrev" in line[key]:
this_row.append(line[key]["abbrev"])
else:
this_row.append(line[key]["id"])
elif isinstance(line[key], int) and line[key] > 100000000:
this_row.append(f"'{line[key]}")
elif isinstance(line[key], str) and "," in line[key]:
this_row.append(line[key].replace(",", "-_-"))
else:
this_row.append(line[key])
data_list.append(this_row)
return DataFrame(data_list).to_csv(header=False, index=False)
class BaseModel(Model):
class Meta:
database = db
class Current(BaseModel):
season = IntegerField()
week = IntegerField(default=0)
gsheet_template = CharField()
gsheet_version = CharField()
live_scoreboard = BigIntegerField() # Discord channel ID - needs BIGINT
class Meta:
database = db
table_name = "current"
@staticmethod
def latest():
latest_current = Current.select().order_by(-Current.id).get()
return latest_current
class Rarity(BaseModel):
value = IntegerField()
name = CharField(unique=True)
color = CharField()
class Meta:
database = db
table_name = "rarity"
def __str__(self):
return self.name
class Event(BaseModel):
name = CharField()
short_desc = CharField(null=True)
url = CharField(null=True)
long_desc = CharField(null=True)
thumbnail = CharField(null=True)
active = BooleanField(default=False)
class Meta:
database = db
table_name = "event"
class Cardset(BaseModel):
name = CharField()
description = CharField()
event = ForeignKeyField(Event, null=True)
for_purchase = BooleanField(default=True) # for_purchase
total_cards = IntegerField()
in_packs = BooleanField(default=True)
ranked_legal = BooleanField(default=True)
class Meta:
database = db
table_name = "cardset"
def __str__(self):
return self.name
class MlbPlayer(BaseModel):
first_name = CharField()
last_name = CharField()
key_fangraphs = IntegerField(null=True)
key_bbref = CharField(null=True)
key_retro = CharField(null=True)
key_mlbam = IntegerField(null=True)
offense_col = IntegerField(default=1)
class Meta:
database = db
table_name = "mlbplayer"
class Player(BaseModel):
player_id = IntegerField(primary_key=True)
p_name = CharField()
cost = IntegerField(default=0)
image = CharField()
image2 = CharField(null=True)
mlbclub = CharField()
franchise = CharField()
cardset = ForeignKeyField(Cardset)
set_num = IntegerField()
rarity = ForeignKeyField(Rarity)
pos_1 = CharField()
pos_2 = CharField(null=True)
pos_3 = CharField(null=True)
pos_4 = CharField(null=True)
pos_5 = CharField(null=True)
pos_6 = CharField(null=True)
pos_7 = CharField(null=True)
pos_8 = CharField(null=True)
headshot = CharField(null=True)
vanity_card = CharField(null=True)
strat_code = CharField(null=True)
bbref_id = CharField(null=True)
fangr_id = CharField(null=True)
description = CharField()
quantity = IntegerField(default=999)
mlbplayer = ForeignKeyField(MlbPlayer, null=True)
def __str__(self):
return f"{self.cardset} {self.p_name} ({self.rarity.name})"
# def __eq__(self, other):
# if self.cardset.id == other.cardset.id and self.name == other.name:
# return True
# else:
# return False
def __lt__(self, other):
if self.wara < other.wara:
return True
elif self.wara > other.wara:
return False
elif self.name < other.name:
return True
else:
return False
def get_all_pos(self):
all_pos = []
if self.pos_1 and self.pos_1 != "CP":
all_pos.append(self.pos_1)
if self.pos_2 and self.pos_2 != "CP":
all_pos.append(self.pos_2)
if self.pos_3 and self.pos_3 != "CP":
all_pos.append(self.pos_3)
if self.pos_4 and self.pos_4 != "CP":
all_pos.append(self.pos_4)
if self.pos_5 and self.pos_5 != "CP":
all_pos.append(self.pos_5)
if self.pos_6 and self.pos_6 != "CP":
all_pos.append(self.pos_6)
if self.pos_7 and self.pos_7 != "CP":
all_pos.append(self.pos_7)
if self.pos_8 and self.pos_8 != "CP":
all_pos.append(self.pos_8)
return all_pos
def change_on_sell(self):
# caps = {
# 'replacement': 15,
# 'reserve': 50,
# 'starter': 200,
# 'all-star': 750,
# 'mvp': 2500,
# 'hof': 999999999
# }
logging.info(f"{self.p_name} cost changing from: {self.cost}")
self.cost = max(math.floor(self.cost * 0.95), 1)
# if self.quantity != 999:
# self.quantity += 1
logging.info(f"{self.p_name} cost now: {self.cost}")
self.save()
def change_on_buy(self):
logging.info(f"{self.p_name} cost changing from: {self.cost}")
self.cost = math.ceil(self.cost * 1.1)
# if self.quantity != 999:
# self.quantity -= 1
logging.info(f"{self.p_name} cost now: {self.cost}")
self.save()
class Meta:
database = db
table_name = "player"
class Team(BaseModel):
abbrev = CharField(max_length=20) # Gauntlet teams use prefixes like "Gauntlet-NCB"
sname = CharField(max_length=100)
lname = CharField(max_length=255)
gmid = BigIntegerField() # Discord user ID - needs BIGINT
gmname = CharField()
gsheet = CharField()
wallet = IntegerField()
team_value = IntegerField()
collection_value = IntegerField()
logo = CharField(null=True)
color = CharField(null=True)
season = IntegerField()
event = ForeignKeyField(Event, null=True)
career = IntegerField(default=0)
ranking = IntegerField(default=1000)
has_guide = BooleanField(default=False)
is_ai = IntegerField(null=True)
def __str__(self):
return f"S{self.season} {self.lname}"
@staticmethod
def get_by_owner(gmid, season=None):
if not season:
season = Current.get().season
team = Team.get_or_none((Team.gmid == gmid) & (Team.season == season))
if not team:
return None
return team
@staticmethod
def select_season(season=None):
if not season:
season = Current.get().season
return Team.select().where(Team.season == season)
@staticmethod
def get_season(abbrev, season=None):
if not season:
season = Current.get().season
return Team.get_or_none(Team.season == season, Team.abbrev == abbrev.upper())
def team_hash(self):
hash_string = f"{self.sname[-1]}{self.gmid / 6950123:.0f}{self.sname[-2]}{self.gmid / 42069123:.0f}"
logging.info(f"string: {hash_string}")
return hash_string
class Meta:
database = db
table_name = "team"
class PackType(BaseModel):
name = CharField()
card_count = IntegerField()
description = CharField()
cost = IntegerField()
available = BooleanField(default=True)
class Meta:
database = db
table_name = "packtype"
class Pack(BaseModel):
team = ForeignKeyField(Team)
pack_type = ForeignKeyField(PackType)
pack_team = ForeignKeyField(Team, null=True)
pack_cardset = ForeignKeyField(Cardset, null=True)
open_time = DateTimeField(null=True)
class Meta:
database = db
table_name = "pack"
class Card(BaseModel):
player = ForeignKeyField(Player, null=True)
team = ForeignKeyField(Team, null=True)
pack = ForeignKeyField(Pack, null=True)
value = IntegerField(default=0)
def __str__(self):
if self.player:
return f"{self.player} - {self.team.sname}"
else:
return f"Blank - {self.team.sname}"
@staticmethod
def select_season(season):
return Card.select().join(Team).where(Card.team.season == season)
class Meta:
database = db
table_name = "card"
class Roster(BaseModel):
team = ForeignKeyField(Team)
name = CharField()
roster_num = IntegerField()
def __str__(self):
return f"{self.team} Roster"
def get_cards(self):
return (
Card.select()
.join(RosterSlot)
.where(RosterSlot.roster == self)
.order_by(RosterSlot.slot)
)
class Meta:
database = db
table_name = "roster"
class RosterSlot(BaseModel):
roster = ForeignKeyField(Roster, backref="slots")
slot = IntegerField()
card = ForeignKeyField(Card, backref="roster_slots")
class Meta:
database = db
table_name = "rosterslot"
indexes = ((("roster", "slot"), True),)
class Result(BaseModel):
away_team = ForeignKeyField(Team)
home_team = ForeignKeyField(Team)
away_score = IntegerField()
home_score = IntegerField()
away_team_value = IntegerField(null=True)
home_team_value = IntegerField(null=True)
away_team_ranking = IntegerField(null=True)
home_team_ranking = IntegerField(null=True)
scorecard = CharField()
week = IntegerField()
season = IntegerField()
ranked = BooleanField()
short_game = BooleanField()
game_type = CharField(null=True)
@staticmethod
def select_season(season=None):
if not season:
season = Current.get().season
return Result.select().where(Result.season == season)
class Meta:
database = db
table_name = "result"
class BattingStat(BaseModel):
card = ForeignKeyField(Card)
team = ForeignKeyField(Team)
roster_num = IntegerField()
vs_team = ForeignKeyField(Team)
result = ForeignKeyField(Result, null=True)
pos = CharField()
pa = IntegerField()
ab = IntegerField()
run = IntegerField()
hit = IntegerField()
rbi = IntegerField()
double = IntegerField()
triple = IntegerField()
hr = IntegerField()
bb = IntegerField()
so = IntegerField()
hbp = IntegerField()
sac = IntegerField()
ibb = IntegerField()
gidp = IntegerField()
sb = IntegerField()
cs = IntegerField()
bphr = IntegerField()
bpfo = IntegerField()
bp1b = IntegerField()
bplo = IntegerField()
xch = IntegerField()
xhit = IntegerField()
error = IntegerField()
pb = IntegerField()
sbc = IntegerField()
csc = IntegerField()
week = IntegerField()
season = IntegerField()
created = DateTimeField()
game_id = IntegerField()
class Meta:
database = db
table_name = "battingstat"
class PitchingStat(BaseModel):
card = ForeignKeyField(Card)
team = ForeignKeyField(Team)
roster_num = IntegerField()
vs_team = ForeignKeyField(Team)
result = ForeignKeyField(Result, null=True)
ip = FloatField()
hit = IntegerField()
run = IntegerField()
erun = IntegerField()
so = IntegerField()
bb = IntegerField()
hbp = IntegerField()
wp = IntegerField()
balk = IntegerField()
hr = IntegerField()
ir = IntegerField()
irs = IntegerField()
gs = IntegerField()
win = IntegerField()
loss = IntegerField()
hold = IntegerField()
sv = IntegerField()
bsv = IntegerField()
week = IntegerField()
season = IntegerField()
created = DateTimeField()
game_id = IntegerField()
class Meta:
database = db
table_name = "pitchingstat"
class Award(BaseModel):
name = CharField()
season = IntegerField()
timing = CharField(default="In-Season")
card = ForeignKeyField(Card, null=True)
team = ForeignKeyField(Team, null=True)
image = CharField(null=True)
class Meta:
database = db
table_name = "award"
class Paperdex(BaseModel):
team = ForeignKeyField(Team)
player = ForeignKeyField(Player)
created = DateTimeField(default=datetime.now)
class Meta:
database = db
table_name = "paperdex"
# def add_to_paperdex(self, team, cards: list):
# for x in players:
# if not isinstance(x, Card):
# raise TypeError(f'The Pokedex can only take a list of Player or Card objects')
#
# Paperdex.get_or_create(team=team, player=player)
class Reward(BaseModel):
name = CharField(null=True)
season = IntegerField()
week = IntegerField()
team = ForeignKeyField(Team)
created = DateTimeField()
class Meta:
database = db
table_name = "reward"
class GameRewards(BaseModel):
name = CharField()
pack_type = ForeignKeyField(PackType, null=True)
player = ForeignKeyField(Player, null=True)
money = IntegerField(null=True)
class Meta:
database = db
table_name = "gamerewards"
class Notification(BaseModel):
created = DateTimeField()
title = CharField()
desc = CharField(null=True)
field_name = CharField()
message = CharField()
about = CharField() # f'{Topic}-{Object ID}'
ack = BooleanField(default=False)
class Meta:
database = db
table_name = "notification"
class GauntletReward(BaseModel):
name = CharField()
gauntlet = ForeignKeyField(Event)
reward = ForeignKeyField(GameRewards)
win_num = IntegerField()
loss_max = IntegerField(default=1)
class Meta:
database = db
table_name = "gauntletreward"
class GauntletRun(BaseModel):
team = ForeignKeyField(Team)
gauntlet = ForeignKeyField(Event)
wins = IntegerField(default=0)
losses = IntegerField(default=0)
gsheet = CharField(null=True)
created = DateTimeField(default=datetime.now)
ended = DateTimeField(null=True) # NULL means run not yet ended
class Meta:
database = db
table_name = "gauntletrun"
class BattingCard(BaseModel):
player = ForeignKeyField(Player)
variant = IntegerField()
steal_low = IntegerField()
steal_high = IntegerField()
steal_auto = BooleanField()
steal_jump = FloatField()
bunting = CharField()
hit_and_run = CharField()
running = IntegerField()
offense_col = IntegerField()
hand = CharField(default="R")
class Meta:
database = db
table_name = "battingcard"
bc_index = ModelIndex(
BattingCard, (BattingCard.player, BattingCard.variant), unique=True
)
BattingCard.add_index(bc_index)
class BattingCardRatings(BaseModel):
battingcard = ForeignKeyField(BattingCard)
vs_hand = CharField(default="R")
pull_rate = FloatField()
center_rate = FloatField()
slap_rate = FloatField()
homerun = FloatField()
bp_homerun = FloatField()
triple = FloatField()
double_three = FloatField()
double_two = FloatField()
double_pull = FloatField()
single_two = FloatField()
single_one = FloatField()
single_center = FloatField()
bp_single = FloatField()
hbp = FloatField()
walk = FloatField()
strikeout = FloatField()
lineout = FloatField()
popout = FloatField()
flyout_a = FloatField()
flyout_bq = FloatField()
flyout_lf_b = FloatField()
flyout_rf_b = FloatField()
groundout_a = FloatField()
groundout_b = FloatField()
groundout_c = FloatField()
avg = FloatField(null=True)
obp = FloatField(null=True)
slg = FloatField(null=True)
class Meta:
database = db
table_name = "battingcardratings"
bcr_index = ModelIndex(
BattingCardRatings,
(BattingCardRatings.battingcard, BattingCardRatings.vs_hand),
unique=True,
)
BattingCardRatings.add_index(bcr_index)
class PitchingCard(BaseModel):
player = ForeignKeyField(Player)
variant = IntegerField()
balk = IntegerField()
wild_pitch = IntegerField()
hold = IntegerField()
starter_rating = IntegerField()
relief_rating = IntegerField()
closer_rating = IntegerField(null=True)
batting = CharField(null=True)
offense_col = IntegerField()
hand = CharField(default="R")
class Meta:
database = db
table_name = "pitchingcard"
pc_index = ModelIndex(
PitchingCard, (PitchingCard.player, PitchingCard.variant), unique=True
)
PitchingCard.add_index(pc_index)
class PitchingCardRatings(BaseModel):
pitchingcard = ForeignKeyField(PitchingCard)
vs_hand = CharField(default="R")
homerun = FloatField()
bp_homerun = FloatField()
triple = FloatField()
double_three = FloatField()
double_two = FloatField()
double_cf = FloatField()
single_two = FloatField()
single_one = FloatField()
single_center = FloatField()
bp_single = FloatField()
hbp = FloatField()
walk = FloatField()
strikeout = FloatField()
flyout_lf_b = FloatField()
flyout_cf_b = FloatField()
flyout_rf_b = FloatField()
groundout_a = FloatField()
groundout_b = FloatField()
xcheck_p = FloatField()
xcheck_c = FloatField()
xcheck_1b = FloatField()
xcheck_2b = FloatField()
xcheck_3b = FloatField()
xcheck_ss = FloatField()
xcheck_lf = FloatField()
xcheck_cf = FloatField()
xcheck_rf = FloatField()
avg = FloatField(null=True)
obp = FloatField(null=True)
slg = FloatField(null=True)
class Meta:
database = db
table_name = "pitchingcardratings"
pcr_index = ModelIndex(
PitchingCardRatings,
(PitchingCardRatings.pitchingcard, PitchingCardRatings.vs_hand),
unique=True,
)
PitchingCardRatings.add_index(pcr_index)
class CardPosition(BaseModel):
player = ForeignKeyField(Player)
variant = IntegerField()
position = CharField()
innings = IntegerField()
range = IntegerField()
error = IntegerField()
arm = IntegerField(null=True)
pb = IntegerField(null=True)
overthrow = IntegerField(null=True)
class Meta:
database = db
table_name = "cardposition"
pos_index = ModelIndex(
CardPosition,
(CardPosition.player, CardPosition.variant, CardPosition.position),
unique=True,
)
CardPosition.add_index(pos_index)
class StratGame(BaseModel):
season = IntegerField()
game_type = CharField()
away_team = ForeignKeyField(Team)
home_team = ForeignKeyField(Team)
week = IntegerField(default=1)
away_score = IntegerField(default=0)
home_score = IntegerField(default=0)
away_team_value = IntegerField(null=True)
home_team_value = IntegerField(null=True)
away_team_ranking = IntegerField(null=True)
home_team_ranking = IntegerField(null=True)
ranked = BooleanField(default=False)
short_game = BooleanField(default=False)
forfeit = BooleanField(default=False)
class Meta:
database = db
table_name = "stratgame"
class StratPlay(BaseModel):
game = ForeignKeyField(StratGame)
play_num = IntegerField()
batter = ForeignKeyField(Player, null=True)
batter_team = ForeignKeyField(Team, null=True)
pitcher = ForeignKeyField(Player)
pitcher_team = ForeignKeyField(Team)
on_base_code = CharField()
inning_half = CharField()
inning_num = IntegerField()
batting_order = IntegerField()
starting_outs = IntegerField()
away_score = IntegerField()
home_score = IntegerField()
batter_pos = CharField(null=True)
# These <base>_final fields track the base this runner advances to post-play (None) if out
on_first = ForeignKeyField(Player, null=True)
on_first_final = IntegerField(null=True)
on_second = ForeignKeyField(Player, null=True)
on_second_final = IntegerField(null=True)
on_third = ForeignKeyField(Player, null=True)
on_third_final = IntegerField(null=True)
batter_final = IntegerField(null=True)
pa = IntegerField(default=0)
ab = IntegerField(default=0)
e_run = IntegerField(default=0)
run = IntegerField(default=0)
hit = IntegerField(default=0)
rbi = IntegerField(default=0)
double = IntegerField(default=0)
triple = IntegerField(default=0)
homerun = IntegerField(default=0)
bb = IntegerField(default=0)
so = IntegerField(default=0)
hbp = IntegerField(default=0)
sac = IntegerField(default=0)
ibb = IntegerField(default=0)
gidp = IntegerField(default=0)
bphr = IntegerField(default=0)
bpfo = IntegerField(default=0)
bp1b = IntegerField(default=0)
bplo = IntegerField(default=0)
sb = IntegerField(default=0)
cs = IntegerField(default=0)
outs = IntegerField(default=0)
wpa = FloatField(default=0.0)
re24 = FloatField(default=0.0)
# These <position> fields are only required if the play is an x-check or baserunning play
catcher = ForeignKeyField(Player, null=True)
catcher_team = ForeignKeyField(Team, null=True)
defender = ForeignKeyField(Player, null=True)
defender_team = ForeignKeyField(Team, null=True)
runner = ForeignKeyField(Player, null=True)
runner_team = ForeignKeyField(Team, null=True)
check_pos = CharField(null=True)
error = IntegerField(default=0)
wild_pitch = IntegerField(default=0)
passed_ball = IntegerField(default=0)
pick_off = IntegerField(default=0)
balk = IntegerField(default=0)
is_go_ahead = BooleanField(default=False)
is_tied = BooleanField(default=False)
is_new_inning = BooleanField(default=False)
class Meta:
database = db
table_name = "stratplay"
# Unique index for StratPlay - a play number should be unique within a game
# Required for PostgreSQL on_conflict() upsert operations
stratplay_index = ModelIndex(
StratPlay, (StratPlay.game, StratPlay.play_num), unique=True
)
StratPlay.add_index(stratplay_index)
class Decision(BaseModel):
season = IntegerField()
game = ForeignKeyField(StratGame)
pitcher = ForeignKeyField(Player)
pitcher_team = ForeignKeyField(Team)
week = IntegerField(default=1)
win = IntegerField(default=0)
loss = IntegerField(default=0)
hold = IntegerField(default=0)
is_save = IntegerField(default=0)
b_save = IntegerField(default=0)
irunners = IntegerField(default=0)
irunners_scored = IntegerField(default=0)
rest_ip = FloatField(default=0.0)
rest_required = IntegerField(default=0)
is_start = BooleanField(default=False)
class Meta:
database = db
table_name = "decision"
# Unique index for Decision - one decision per pitcher per game
# Required for PostgreSQL on_conflict() upsert operations
decision_index = ModelIndex(Decision, (Decision.game, Decision.pitcher), unique=True)
Decision.add_index(decision_index)
class BattingSeasonStats(BaseModel):
player = ForeignKeyField(Player)
team = ForeignKeyField(Team)
season = IntegerField()
games = IntegerField(default=0)
pa = IntegerField(default=0)
ab = IntegerField(default=0)
hits = IntegerField(default=0)
doubles = IntegerField(default=0)
triples = IntegerField(default=0)
hr = IntegerField(default=0)
rbi = IntegerField(default=0)
runs = IntegerField(default=0)
bb = IntegerField(default=0)
strikeouts = IntegerField(default=0)
hbp = IntegerField(default=0)
sac = IntegerField(default=0)
ibb = IntegerField(default=0)
gidp = IntegerField(default=0)
sb = IntegerField(default=0)
cs = IntegerField(default=0)
last_game = ForeignKeyField(StratGame, null=True)
last_updated_at = DateTimeField(null=True)
class Meta:
database = db
table_name = "batting_season_stats"
bss_unique_index = ModelIndex(
BattingSeasonStats,
(BattingSeasonStats.player, BattingSeasonStats.team, BattingSeasonStats.season),
unique=True,
)
BattingSeasonStats.add_index(bss_unique_index)
bss_team_season_index = ModelIndex(
BattingSeasonStats,
(BattingSeasonStats.team, BattingSeasonStats.season),
unique=False,
)
BattingSeasonStats.add_index(bss_team_season_index)
bss_player_season_index = ModelIndex(
BattingSeasonStats,
(BattingSeasonStats.player, BattingSeasonStats.season),
unique=False,
)
BattingSeasonStats.add_index(bss_player_season_index)
class PitchingSeasonStats(BaseModel):
player = ForeignKeyField(Player)
team = ForeignKeyField(Team)
season = IntegerField()
games = IntegerField(default=0)
games_started = IntegerField(default=0)
outs = IntegerField(default=0)
strikeouts = IntegerField(default=0)
bb = IntegerField(default=0)
hits_allowed = IntegerField(default=0)
runs_allowed = IntegerField(default=0)
earned_runs = IntegerField(default=0)
hr_allowed = IntegerField(default=0)
hbp = IntegerField(default=0)
wild_pitches = IntegerField(default=0)
balks = IntegerField(default=0)
wins = IntegerField(default=0)
losses = IntegerField(default=0)
holds = IntegerField(default=0)
saves = IntegerField(default=0)
blown_saves = IntegerField(default=0)
last_game = ForeignKeyField(StratGame, null=True)
last_updated_at = DateTimeField(null=True)
class Meta:
database = db
table_name = "pitching_season_stats"
pitss_unique_index = ModelIndex(
PitchingSeasonStats,
(PitchingSeasonStats.player, PitchingSeasonStats.team, PitchingSeasonStats.season),
unique=True,
)
PitchingSeasonStats.add_index(pitss_unique_index)
pitss_team_season_index = ModelIndex(
PitchingSeasonStats,
(PitchingSeasonStats.team, PitchingSeasonStats.season),
unique=False,
)
PitchingSeasonStats.add_index(pitss_team_season_index)
pitss_player_season_index = ModelIndex(
PitchingSeasonStats,
(PitchingSeasonStats.player, PitchingSeasonStats.season),
unique=False,
)
PitchingSeasonStats.add_index(pitss_player_season_index)
class ScoutOpportunity(BaseModel):
pack = ForeignKeyField(Pack, null=True)
opener_team = ForeignKeyField(Team)
card_ids = CharField() # JSON array of card IDs
expires_at = BigIntegerField()
created = BigIntegerField()
class Meta:
database = db
table_name = "scout_opportunity"
class ScoutClaim(BaseModel):
scout_opportunity = ForeignKeyField(ScoutOpportunity)
card = ForeignKeyField(Card)
claimed_by_team = ForeignKeyField(Team)
created = BigIntegerField()
class Meta:
database = db
table_name = "scout_claim"
scout_claim_index = ModelIndex(
ScoutClaim,
(ScoutClaim.scout_opportunity, ScoutClaim.claimed_by_team),
unique=True,
)
ScoutClaim.add_index(scout_claim_index)
db.close()