Codex commited on
Commit
e4fef26
·
1 Parent(s): 3c3ae66

Speed up baseball profile chart lookups

Browse files
Files changed (1) hide show
  1. src/matchups.js +84 -16
src/matchups.js CHANGED
@@ -2127,14 +2127,7 @@ export class MatchupService {
2127
 
2128
  async getHrProfileData(options = {}) {
2129
  return this.getCachedChartValue(this.buildChartCacheKey('hr-profile', options), async () => {
2130
- const result = await this.getPlayerContext({
2131
- ...options,
2132
- player: options.player,
2133
- playerType: 'hitter',
2134
- });
2135
- if (result.playerType !== 'hitter') {
2136
- throw new Error(`No hitter matchup profile matched "${options.player}".`);
2137
- }
2138
  const overview = result.overview ?? {};
2139
  return {
2140
  ...result,
@@ -2162,14 +2155,7 @@ export class MatchupService {
2162
 
2163
  async getKProfileData(options = {}) {
2164
  return this.getCachedChartValue(this.buildChartCacheKey('k-profile', options), async () => {
2165
- const result = await this.getPlayerContext({
2166
- ...options,
2167
- player: options.pitcher,
2168
- playerType: 'pitcher',
2169
- });
2170
- if (result.playerType !== 'pitcher') {
2171
- throw new Error(`No pitcher matchup profile matched "${options.pitcher}".`);
2172
- }
2173
  const overview = result.overview ?? {};
2174
  return {
2175
  ...result,
@@ -2560,6 +2546,88 @@ export class MatchupService {
2560
  return points.reverse();
2561
  }
2562
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2563
  async enrichHostedHitters(result, options = {}, methodName = 'getTopHitters') {
2564
  if (!result?.rows?.length || !this.fallback?.getHitterSnapshotRows) {
2565
  return result;
 
2127
 
2128
  async getHrProfileData(options = {}) {
2129
  return this.getCachedChartValue(this.buildChartCacheKey('hr-profile', options), async () => {
2130
+ const result = await this.getFastHitterChartContext(options.player, options);
 
 
 
 
 
 
 
2131
  const overview = result.overview ?? {};
2132
  return {
2133
  ...result,
 
2155
 
2156
  async getKProfileData(options = {}) {
2157
  return this.getCachedChartValue(this.buildChartCacheKey('k-profile', options), async () => {
2158
+ const result = await this.getFastPitcherChartContext(options.pitcher, options);
 
 
 
 
 
 
 
2159
  const overview = result.overview ?? {};
2160
  return {
2161
  ...result,
 
2546
  return points.reverse();
2547
  }
2548
 
2549
+ async getFastHitterChartContext(playerName, options = {}) {
2550
+ if (!this.hosted?.isConfigured?.()) {
2551
+ const fallback = await this.getPlayerContext({
2552
+ ...options,
2553
+ player: playerName,
2554
+ playerType: 'hitter',
2555
+ });
2556
+ if (fallback.playerType !== 'hitter') {
2557
+ throw new Error(`No hitter matchup profile matched "${playerName}".`);
2558
+ }
2559
+ return fallback;
2560
+ }
2561
+
2562
+ const result = await this.hosted.buildHostedHitterParityBase(options);
2563
+ const hitterMatch = findBestPlayerMatch(result.rows, 'hitter_name', playerName);
2564
+ if (!hitterMatch) {
2565
+ throw new Error(`No hitter matchup profile matched "${playerName}".`);
2566
+ }
2567
+
2568
+ return {
2569
+ source: result.source,
2570
+ resolvedDate: result.resolvedDate,
2571
+ playerType: 'hitter',
2572
+ name: hitterMatch.hitter_name,
2573
+ team: hitterMatch.team ?? null,
2574
+ opponentTeam: hitterMatch.opponent_team ?? null,
2575
+ opposingPitcherName: hitterMatch.opposing_pitcher_name ?? null,
2576
+ hand: hitterMatch.opposing_pitcher_hand ?? null,
2577
+ overview: hitterMatch,
2578
+ };
2579
+ }
2580
+
2581
+ async getFastPitcherChartContext(playerName, options = {}) {
2582
+ if (!this.hosted?.isConfigured?.()) {
2583
+ const fallback = await this.getPlayerContext({
2584
+ ...options,
2585
+ player: playerName,
2586
+ playerType: 'pitcher',
2587
+ });
2588
+ if (fallback.playerType !== 'pitcher') {
2589
+ throw new Error(`No pitcher matchup profile matched "${playerName}".`);
2590
+ }
2591
+ return fallback;
2592
+ }
2593
+
2594
+ const targetDate = parseDateOrToday(options.date);
2595
+ const resolvedDate = await this.hosted.getLatestAvailableDate(targetDate);
2596
+ if (!resolvedDate) {
2597
+ throw new Error('No hosted pitcher slate was available in the fallback window.');
2598
+ }
2599
+
2600
+ const cacheKey = this.buildChartCacheKey('pitcher-chart-base', { date: resolvedDate });
2601
+ const base = await this.getCachedChartValue(cacheKey, async () => {
2602
+ const [slateRows, pitcherRows, rosterRows] = await Promise.all([
2603
+ this.hosted.readDailyFile(resolvedDate, 'slate.parquet', SLATE_COLUMNS),
2604
+ this.hosted.readDailyFile(resolvedDate, 'daily_pitcher_metrics.parquet', PITCHER_COLUMNS),
2605
+ this.hosted.readDailyFile(resolvedDate, 'rosters.parquet', ROSTER_COLUMNS).catch(() => []),
2606
+ ]);
2607
+ const slateLookup = mapSlateTeams(slateRows);
2608
+ const rosterLookup = buildRosterLookup(rosterRows);
2609
+ return pitcherRows
2610
+ .filter(keepRowForDefaults)
2611
+ .map((row) => withDefaults(row, slateLookup, { rosterLookup, playerType: 'pitcher' }));
2612
+ });
2613
+
2614
+ const pitcherMatch = findBestPlayerMatch(base, 'pitcher_name', playerName);
2615
+ if (!pitcherMatch) {
2616
+ throw new Error(`No pitcher matchup profile matched "${playerName}".`);
2617
+ }
2618
+
2619
+ return {
2620
+ source: 'hosted',
2621
+ resolvedDate,
2622
+ playerType: 'pitcher',
2623
+ name: pitcherMatch.pitcher_name,
2624
+ team: pitcherMatch.team ?? null,
2625
+ opponentTeam: pitcherMatch.opponent_team ?? null,
2626
+ hand: pitcherMatch.p_throws ?? null,
2627
+ overview: pitcherMatch,
2628
+ };
2629
+ }
2630
+
2631
  async enrichHostedHitters(result, options = {}, methodName = 'getTopHitters') {
2632
  if (!result?.rows?.length || !this.fallback?.getHitterSnapshotRows) {
2633
  return result;