mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-10 06:32:05 +00:00
Optimize query for period statistics.
This commit is contained in:
@@ -546,6 +546,7 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
|
|||||||
#[Override]
|
#[Override]
|
||||||
public function periodCollection(Account $account, Carbon $start, Carbon $end): array
|
public function periodCollection(Account $account, Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
|
Log::debug(sprintf('periodCollection(#%d, %s, %s)', $account->id, $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||||
return $account->transactions()
|
return $account->transactions()
|
||||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||||
|
@@ -27,32 +27,31 @@ use Carbon\Carbon;
|
|||||||
use FireflyIII\Models\PeriodStatistic;
|
use FireflyIII\Models\PeriodStatistic;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class PeriodStatisticRepository implements PeriodStatisticRepositoryInterface
|
class PeriodStatisticRepository implements PeriodStatisticRepositoryInterface
|
||||||
{
|
{
|
||||||
public function findPeriodStatistics(Model $model, Carbon $start, Carbon $end, array $types): Collection
|
public function findPeriodStatistics(Model $model, Carbon $start, Carbon $end, array $types): Collection
|
||||||
{
|
{
|
||||||
return $model->primaryPeriodStatistics()
|
return $model->primaryPeriodStatistics()
|
||||||
->where('start', $start)
|
->where('start', $start)
|
||||||
->where('end', $end)
|
->where('end', $end)
|
||||||
->whereIn('type', $types)
|
->whereIn('type', $types)
|
||||||
->get()
|
->get();
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findPeriodStatistic(Model $model, Carbon $start, Carbon $end, string $type): Collection
|
public function findPeriodStatistic(Model $model, Carbon $start, Carbon $end, string $type): Collection
|
||||||
{
|
{
|
||||||
return $model->primaryPeriodStatistics()
|
return $model->primaryPeriodStatistics()
|
||||||
->where('start', $start)
|
->where('start', $start)
|
||||||
->where('end', $end)
|
->where('end', $end)
|
||||||
->where('type', $type)
|
->where('type', $type)
|
||||||
->get()
|
->get();
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveStatistic(Model $model, int $currencyId, Carbon $start, Carbon $end, string $type, int $count, string $amount): PeriodStatistic
|
public function saveStatistic(Model $model, int $currencyId, Carbon $start, Carbon $end, string $type, int $count, string $amount): PeriodStatistic
|
||||||
{
|
{
|
||||||
$stat = new PeriodStatistic();
|
$stat = new PeriodStatistic();
|
||||||
$stat->primaryStatable()->associate($model);
|
$stat->primaryStatable()->associate($model);
|
||||||
$stat->transaction_currency_id = $currencyId;
|
$stat->transaction_currency_id = $currencyId;
|
||||||
$stat->start = $start;
|
$stat->start = $start;
|
||||||
@@ -64,11 +63,15 @@ class PeriodStatisticRepository implements PeriodStatisticRepositoryInterface
|
|||||||
$stat->type = $type;
|
$stat->type = $type;
|
||||||
$stat->save();
|
$stat->save();
|
||||||
|
|
||||||
|
Log::debug(sprintf('Saved #%d [currency #%d, Model %s #%d, %s to %s, %d, %s] as new statistic.',
|
||||||
|
$stat->id, get_class($model), $model->id, $stat->transaction_currency_id, $stat->start->toW3cString(), $stat->end->toW3cString(), $count, $amount
|
||||||
|
));
|
||||||
|
|
||||||
return $stat;
|
return $stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function allInRangeForModel(Model $model, Carbon $start, Carbon $end): Collection
|
public function allInRangeForModel(Model $model, Carbon $start, Carbon $end): Collection
|
||||||
{
|
{
|
||||||
return $model->primaryPeriodStatistics()->where('start','>=', $start)->where('end','<=', $end)->get();
|
return $model->primaryPeriodStatistics()->where('start', '>=', $start)->where('end', '<=', $end)->get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -90,6 +90,9 @@ trait PeriodOverview
|
|||||||
$range = Navigation::getViewRange(true);
|
$range = Navigation::getViewRange(true);
|
||||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||||
|
|
||||||
|
/** @var array $dates */
|
||||||
|
$dates = Navigation::blockPeriods($start, $end, $range);
|
||||||
|
[$start, $end] = $this->getPeriodFromBlocks($dates, $start, $end);
|
||||||
$this->statistics = $this->periodStatisticRepo->allInRangeForModel($account, $start, $end);
|
$this->statistics = $this->periodStatisticRepo->allInRangeForModel($account, $start, $end);
|
||||||
|
|
||||||
// TODO needs to be re-arranged:
|
// TODO needs to be re-arranged:
|
||||||
@@ -97,10 +100,8 @@ trait PeriodOverview
|
|||||||
// loop blocks, an loop the types, and select the missing ones.
|
// loop blocks, an loop the types, and select the missing ones.
|
||||||
// create new ones, or use collected.
|
// create new ones, or use collected.
|
||||||
|
|
||||||
/** @var array $dates */
|
|
||||||
$dates = Navigation::blockPeriods($start, $end, $range);
|
|
||||||
$entries = [];
|
$entries = [];
|
||||||
$types = ['spent', 'earned', 'transferred_in', 'transferred_away'];
|
|
||||||
Log::debug(sprintf('Count of loops: %d', count($dates)));
|
Log::debug(sprintf('Count of loops: %d', count($dates)));
|
||||||
foreach ($dates as $currentDate) {
|
foreach ($dates as $currentDate) {
|
||||||
$entries[] = $this->getSingleAccountPeriod($account, $currentDate['period'], $currentDate['start'], $currentDate['end']);
|
$entries[] = $this->getSingleAccountPeriod($account, $currentDate['period'], $currentDate['start'], $currentDate['end']);
|
||||||
@@ -110,6 +111,25 @@ trait PeriodOverview
|
|||||||
return $entries;
|
return $entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getPeriodFromBlocks(array $dates, Carbon $start, Carbon $end): array
|
||||||
|
{
|
||||||
|
Log::debug('Filter generated periods to select the oldest and newest date.');
|
||||||
|
foreach ($dates as $row) {
|
||||||
|
$currentStart = clone $row['start'];
|
||||||
|
$currentEnd = clone $row['end'];
|
||||||
|
if ($currentStart->lt($start)) {
|
||||||
|
Log::debug(sprintf('New start: was %s, now %s', $start->format('Y-m-d'), $currentStart->format('Y-m-d')));
|
||||||
|
$start = $currentStart;
|
||||||
|
}
|
||||||
|
if ($currentEnd->gt($end)) {
|
||||||
|
Log::debug(sprintf('New end: was %s, now %s', $end->format('Y-m-d'), $currentEnd->format('Y-m-d')));
|
||||||
|
$end = $currentEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$start, $end];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overview for single category. Has been refactored recently.
|
* Overview for single category. Has been refactored recently.
|
||||||
*
|
*
|
||||||
@@ -326,7 +346,7 @@ trait PeriodOverview
|
|||||||
{
|
{
|
||||||
return $this->statistics->filter(
|
return $this->statistics->filter(
|
||||||
function (PeriodStatistic $statistic) use ($start, $end, $type) {
|
function (PeriodStatistic $statistic) use ($start, $end, $type) {
|
||||||
if(
|
if (
|
||||||
!$statistic->end->equalTo($end)
|
!$statistic->end->equalTo($end)
|
||||||
&& $statistic->end->format('Y-m-d H:i:s') === $end->format('Y-m-d H:i:s')
|
&& $statistic->end->format('Y-m-d H:i:s') === $end->format('Y-m-d H:i:s')
|
||||||
) {
|
) {
|
||||||
@@ -377,9 +397,9 @@ trait PeriodOverview
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// each result must be grouped by currency, then saved as period statistic.
|
// each result must be grouped by currency, then saved as period statistic.
|
||||||
|
Log::debug(sprintf('Going to group %d found journal(s)', count($result)));
|
||||||
$grouped = $this->groupByCurrency($result);
|
$grouped = $this->groupByCurrency($result);
|
||||||
|
|
||||||
// TODO save as statistic.
|
|
||||||
$this->saveGroupedAsStatistics($account, $start, $end, $type, $grouped);
|
$this->saveGroupedAsStatistics($account, $start, $end, $type, $grouped);
|
||||||
|
|
||||||
return $grouped;
|
return $grouped;
|
||||||
@@ -547,10 +567,12 @@ trait PeriodOverview
|
|||||||
protected function saveGroupedAsStatistics(Account $account, Carbon $start, Carbon $end, string $type, array $array): void
|
protected function saveGroupedAsStatistics(Account $account, Carbon $start, Carbon $end, string $type, array $array): void
|
||||||
{
|
{
|
||||||
unset($array['count']);
|
unset($array['count']);
|
||||||
|
Log::debug(sprintf('saveGroupedAsStatistics(#%d, %s, %s, "%s", array(%d))', $account->id, $start->format('Y-m-d'), $end->format('Y-m-d'), $type, count($array)));
|
||||||
foreach ($array as $entry) {
|
foreach ($array as $entry) {
|
||||||
$this->periodStatisticRepo->saveStatistic($account, $entry['currency_id'], $start, $end, $type, $entry['count'], $entry['amount']);
|
$this->periodStatisticRepo->saveStatistic($account, $entry['currency_id'], $start, $end, $type, $entry['count'], $entry['amount']);
|
||||||
}
|
}
|
||||||
if(0 === count($array)) {
|
if (0 === count($array)) {
|
||||||
|
Log::debug('Save empty statistic.');
|
||||||
$this->periodStatisticRepo->saveStatistic($account, $this->primaryCurrency->id, $start, $end, $type, 0, '0');
|
$this->periodStatisticRepo->saveStatistic($account, $this->primaryCurrency->id, $start, $end, $type, 0, '0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user