refactor: split oil price ingestion and prediction into separate services + commands
- BrentPriceFetcher owns ingestion (fetchFromEia / fetchFromFred, each throws on failure) - BrentPricePredictor owns prediction and marks latest brent_prices row as generated - oil:fetch command tries EIA, falls back to FRED, fails loudly if both fail - oil:predict command prompts if latest price already has a prediction; --force bypasses - add prediction_generated_at column to brent_prices - delete OilPriceService (replaced by the two focused services)
This commit is contained in:
44
app/Services/BrentPriceFetcher.php
Normal file
44
app/Services/BrentPriceFetcher.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\BrentPrice;
|
||||
use App\Services\BrentPriceSources\BrentPriceFetchException;
|
||||
use App\Services\BrentPriceSources\EiaBrentPriceSource;
|
||||
use App\Services\BrentPriceSources\FredBrentPriceSource;
|
||||
|
||||
final readonly class BrentPriceFetcher
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EiaBrentPriceSource $eia,
|
||||
private readonly FredBrentPriceSource $fred,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Fetch from EIA and persist. Throws on failure.
|
||||
*/
|
||||
public function fetchFromEia(): void
|
||||
{
|
||||
$rows = $this->eia->fetch();
|
||||
|
||||
if ($rows === null) {
|
||||
throw new BrentPriceFetchException('EIA fetch returned no data');
|
||||
}
|
||||
|
||||
BrentPrice::upsert($rows, ['date'], ['price_usd']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch from FRED and persist. Throws on failure.
|
||||
*/
|
||||
public function fetchFromFred(): void
|
||||
{
|
||||
$rows = $this->fred->fetch();
|
||||
|
||||
if ($rows === null) {
|
||||
throw new BrentPriceFetchException('FRED fetch returned no data');
|
||||
}
|
||||
|
||||
BrentPrice::upsert($rows, ['date'], ['price_usd']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user