fix: multi currency seeders

This commit is contained in:
hackerESQ
2025-05-15 20:05:14 -05:00
parent 26370c03c4
commit 689aa4d50b
6 changed files with 66 additions and 225 deletions
+18 -14
View File
@@ -111,7 +111,7 @@ class CurrencyRate extends Model
* *
* @return array<string, float> * @return array<string, float>
*/ */
public static function timeSeriesRates(string|array $currency, mixed $start = null, mixed $end = null): array public static function timeSeriesRates(?string $currency = null, mixed $start = null, mixed $end = null): array
{ {
if (empty($start)) { if (empty($start)) {
return []; return [];
@@ -132,19 +132,18 @@ class CurrencyRate extends Model
return $dateRange; return $dateRange;
} }
[$currency, $adjustment] = self::getCurrencyAliasAdjustments($currency); // handle currency alias
if (! empty($currency)) { if (! empty($currency)) {
$currencies = Arr::wrap($currency); [$currency, $adjustment] = self::getCurrencyAliasAdjustments($currency);
} else { } else {
$currencies = Currency::all()->pluck('currency')->toArray(); $currency = Currency::all()->pluck('currency')->toArray();
} }
// get rates // get rates
$rates = Frankfurter::setSymbols($currencies)->timeSeries($period->first(), $period->last()); $rates = Frankfurter::setSymbols($currency)->timeSeries($period->first(), $period->last());
$rates = collect(Arr::get($rates, 'rates', []))->sortKeys()->toArray(); $rates = collect(Arr::get($rates, 'rates', []))->sortKeys()->toArray();
@@ -177,13 +176,18 @@ class CurrencyRate extends Model
// persist // persist
self::chunkInsert($updates); self::chunkInsert($updates);
return collect($updates) if (is_string($currency)) {
->whereBetween('date', [$start, $end ?? now()])
->where('currency', $currency) return collect($updates)
->mapWithKeys(fn ($rate) => [ ->whereBetween('date', [$start, $end ?? now()])
$rate['date'] => $rate['rate'] * $adjustment, ->where('currency', $currency)
]) ->mapWithKeys(fn ($rate) => [
->toArray(); $rate['date'] => $rate['rate'] * ($adjustment ?? 1),
])
->toArray();
}
return [];
} }
private static function getNearestPastDate(CarbonInterface $date, array $datesOnly, array $rates): ?CarbonInterface private static function getNearestPastDate(CarbonInterface $date, array $datesOnly, array $rates): ?CarbonInterface
@@ -265,7 +269,7 @@ class CurrencyRate extends Model
} }
} }
protected static function getCurrencyAliasAdjustments($currency) protected static function getCurrencyAliasAdjustments(string $currency)
{ {
$adjustment = 1; $adjustment = 1;
@@ -97,9 +97,14 @@ return new class extends Migration
'--force' => true, '--force' => true,
]); ]);
CurrencyRate::timeSeriesRates( Holding::all()->groupBy('market_data.currency')->keys()->each(
Holding::all()->groupBy('market_data.currency')->keys()->toArray(), fn ($currency) => dispatch(
Transaction::min('date') function () use ($currency) {
CurrencyRate::timeSeriesRates(
$currency,
Transaction::min('date')
);
})
); );
CurrencyRate::refreshCurrencyData(); CurrencyRate::refreshCurrencyData();
+6 -4
View File
@@ -54,8 +54,7 @@ class MarketDataSeeder extends Seeder
$rowCount++; $rowCount++;
if ($rowCount % $chunkSize == 0) { if ($rowCount % $chunkSize == 0) {
DB::table('market_data')->upsert($this->rows, ['symbol'], ['name', 'currency', 'meta_data']); $this->bulkInsert($this->rows);
$this->rows = [];
} }
} }
} }
@@ -77,11 +76,14 @@ class MarketDataSeeder extends Seeder
} }
} }
public function bulkInsert(array $rows) public function bulkInsert($rows)
{ {
try { try {
DB::table('market_data')->insertOrIgnore($rows); dispatch(
fn () => DB::table('market_data')->upsert($rows, ['symbol'], ['name', 'currency', 'meta_data'])
);
$this->rows = []; $this->rows = [];
} catch (\Throwable $e) { } catch (\Throwable $e) {
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -21,7 +21,7 @@ class MarketDataTest extends TestCase
'--force' => true, '--force' => true,
]); ]);
$this->assertEquals(14464, MarketData::count('symbol')); $this->assertEquals(14262, MarketData::count('symbol'));
} }
public function test_can_get_quote_from_provider() public function test_can_get_quote_from_provider()
+33 -1
View File
@@ -225,8 +225,40 @@ class MultiCurrencyTest extends TestCase
->andReturn(['rates' => $results]); ->andReturn(['rates' => $results]);
$result = CurrencyRate::timeSeriesRates('ZZZ', $start, $end); $result = CurrencyRate::timeSeriesRates('ZZZ', $start, $end);
$this->assertEquals(count($period) - 1, count($result)); $this->assertEquals(count($period) - 1, count($result));
$result = CurrencyRate::all();
$this->assertEquals(count($period), count($result));
}
public function test_can_get_time_series_rates_with_null_currency()
{
$start = now()->subWeeks(2);
$end = now();
$period = CarbonPeriod::create($start, $end);
// mock response from Frankfurter
$results = [];
collect($period->copy()->filter('isWeekday'))->each(function ($date) use (&$results) {
$date = $date->toDateString();
$results[$date] = [
'FOO' => random_int(10, 150) / 1000,
];
});
Frankfurter::expects('setSymbols')
->andReturnSelf();
Frankfurter::expects('timeSeries')
->andReturn(['rates' => $results]);
$result = CurrencyRate::timeSeriesRates(null, $start, $end);
$this->assertEquals(0, count($result));
$result = CurrencyRate::all();
$this->assertEquals(count($period), count($result));
} }
public function test_time_series_rate_calls_are_chunked() public function test_time_series_rate_calls_are_chunked()