#35 - Add Limit support for departure repository

This commit is contained in:
Kacper Donat 2020-03-15 22:35:12 +01:00
parent f3a6c3e8eb
commit db30d69cdb
6 changed files with 106 additions and 30 deletions

View File

@ -5,7 +5,10 @@ namespace App\Controller\Api\v1;
use App\Controller\Controller; use App\Controller\Controller;
use App\Model\Departure; use App\Model\Departure;
use App\Modifier\FieldFilter;
use App\Modifier\IdFilter; use App\Modifier\IdFilter;
use App\Modifier\Limit;
use App\Modifier\With;
use App\Provider\DepartureRepository; use App\Provider\DepartureRepository;
use App\Provider\StopRepository; use App\Provider\StopRepository;
use App\Service\SerializerContextFactory; use App\Service\SerializerContextFactory;
@ -33,11 +36,11 @@ class DeparturesController extends Controller
* @SWG\Schema(type="array", @SWG\Items(ref=@Model(type=Departure::class))) * @SWG\Schema(type="array", @SWG\Items(ref=@Model(type=Departure::class)))
* ) * )
*/ */
public function stop(DepartureRepository $departures, StopRepository $stops, $stop) public function stop(DepartureRepository $departures, StopRepository $stops, $stop, Request $request)
{ {
$stop = $stops->first(new IdFilter($stop)); $stop = $stops->first(new IdFilter($stop));
return $this->json($departures->getForStop($stop)); return $this->json($departures->current(collect($stop), ...$this->getModifiersFromRequest($request)));
} }
/** /**
@ -65,16 +68,21 @@ class DeparturesController extends Controller
*/ */
public function stops(DepartureRepository $departures, StopRepository $stops, Request $request) public function stops(DepartureRepository $departures, StopRepository $stops, Request $request)
{ {
$stops = $stops $stops = $stops->all(new IdFilter($request->query->get('stop')));
->all(new IdFilter($request->query->get('stop'))) $result = $departures->current($stops, ...$this->getModifiersFromRequest($request));
->flatMap(ref([ $departures, 'getForStop' ]))
->sortBy(property('departure'));
return $this->json( return $this->json(
$stops->values()->slice(0, (int)$request->query->get('limit', 8)), $result->values()->slice(0, (int)$request->query->get('limit', 8)),
200, 200,
[], [],
$this->serializerContextFactory->create(Departure::class, ['Default']) $this->serializerContextFactory->create(Departure::class, ['Default'])
); );
} }
private function getModifiersFromRequest(Request $request)
{
if ($request->query->has('limit')) {
yield Limit::count($request->query->getInt('limit'));
}
}
} }

View File

@ -72,7 +72,7 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub
if (!array_key_exists($modifier->getRelationship(), $this->mapping[$type])) { if (!array_key_exists($modifier->getRelationship(), $this->mapping[$type])) {
throw new \InvalidArgumentException( throw new \InvalidArgumentException(
sprintf("Relationship %s is not supported for .", $type) sprintf("Relationship %s is not supported for %s.", $modifier->getRelationship(), $type)
); );
} }

View File

@ -5,9 +5,10 @@ namespace App\Provider;
use App\Model\Stop; use App\Model\Stop;
use App\Modifier\Modifier;
use Tightenco\Collect\Support\Collection; use Tightenco\Collect\Support\Collection;
interface DepartureRepository extends Repository interface DepartureRepository extends Repository
{ {
public function getForStop(Stop $stop): Collection; public function current(iterable $stops, Modifier ...$modifiers);
} }

View File

@ -6,6 +6,7 @@ use App\Model\Departure;
use App\Model\Line; use App\Model\Line;
use App\Model\Stop; use App\Model\Stop;
use App\Model\Vehicle; use App\Model\Vehicle;
use App\Modifier\Modifier;
use App\Provider\DepartureRepository; use App\Provider\DepartureRepository;
use App\Service\Proxy\ReferenceFactory; use App\Service\Proxy\ReferenceFactory;
use Carbon\Carbon; use Carbon\Carbon;
@ -25,7 +26,7 @@ class DummyDepartureRepository implements DepartureRepository
$this->reference = $reference; $this->reference = $reference;
} }
public function getForStop(Stop $stop): Collection public function current(iterable $stops, Modifier ...$modifiers)
{ {
return collect([ return collect([
[1, Line::TYPE_TRAM, 'lorem ipsum', 2137], [1, Line::TYPE_TRAM, 'lorem ipsum', 2137],
@ -39,7 +40,7 @@ class DummyDepartureRepository implements DepartureRepository
[1, Line::TYPE_TRAM, 'lorem ipsum', 2137], [1, Line::TYPE_TRAM, 'lorem ipsum', 2137],
[1, Line::TYPE_TRAM, 'lorem ipsum', 2137], [1, Line::TYPE_TRAM, 'lorem ipsum', 2137],
])->map(function ($departure) use ($stop) { ])->map(function ($departure) use ($stop) {
list($symbol, $type, $display, $vehicle) = $departure; [$symbol, $type, $display, $vehicle] = $departure;
$scheduled = new Carbon(); $scheduled = new Carbon();
$estimated = (clone $scheduled)->addSeconds(40); $estimated = (clone $scheduled)->addSeconds(40);

View File

@ -10,18 +10,22 @@ use App\Model\Vehicle;
use App\Modifier\FieldFilter; use App\Modifier\FieldFilter;
use App\Modifier\IdFilter; use App\Modifier\IdFilter;
use App\Modifier\Limit; use App\Modifier\Limit;
use App\Modifier\Modifier;
use App\Modifier\RelatedFilter; use App\Modifier\RelatedFilter;
use App\Modifier\With; use App\Modifier\With;
use App\Provider\Database\GenericScheduleRepository; use App\Provider\Database\GenericScheduleRepository;
use App\Provider\DepartureRepository; use App\Provider\DepartureRepository;
use App\Provider\LineRepository; use App\Provider\LineRepository;
use App\Provider\ScheduleRepository; use App\Provider\ScheduleRepository;
use App\Service\IterableUtils;
use App\Service\ModifierUtils;
use App\Service\Proxy\ReferenceFactory; use App\Service\Proxy\ReferenceFactory;
use Carbon\Carbon; use Carbon\Carbon;
use JMS\Serializer\Tests\Fixtures\Discriminator\Car; use JMS\Serializer\Tests\Fixtures\Discriminator\Car;
use Tightenco\Collect\Support\Collection; use Tightenco\Collect\Support\Collection;
use Kadet\Functional\Transforms as t; use Kadet\Functional\Transforms as t;
use function App\Functions\setup; use function App\Functions\setup;
use function Kadet\Functional\ref;
class ZtmGdanskDepartureRepository implements DepartureRepository class ZtmGdanskDepartureRepository implements DepartureRepository
{ {
@ -46,16 +50,22 @@ class ZtmGdanskDepartureRepository implements DepartureRepository
$this->schedule = $schedule; $this->schedule = $schedule;
} }
public function getForStop(Stop $stop): Collection public function current(iterable $stops, Modifier ...$modifiers)
{ {
$real = $this->getRealDepartures($stop); $real = IterableUtils::toCollection($stops)
->flatMap(ref([$this, 'getRealDepartures']))
->sortBy(t\property('estimated'))
;
$now = Carbon::now()->second(0); $now = Carbon::now()->second(0);
$first = $real->map(t\getter('scheduled'))->min() ?? $now; $first = $real->map(t\getter('scheduled'))->min() ?? $now;
$scheduled = $this->getScheduledDepartures($stop, $first); $scheduled = $this->getScheduledDepartures($stops, $first, ...$this->extractModifiers($modifiers));
return $this->pair($scheduled, $real)->filter(function (Departure $departure) use ($now) { $result = $this->pair($scheduled, $real)->filter(function (Departure $departure) use ($now) {
return $departure->getDeparture() > $now; return $departure->getDeparture() > $now;
}); });
return $this->processResultWithModifiers($result, $modifiers);
} }
private function getRealDepartures(Stop $stop) private function getRealDepartures(Stop $stop)
@ -94,14 +104,14 @@ class ZtmGdanskDepartureRepository implements DepartureRepository
})->values(); })->values();
} }
private function getScheduledDepartures(Stop $stop, Carbon $time) private function getScheduledDepartures($stop, Carbon $time, Modifier ...$modifiers)
{ {
return $this->schedule->all( return $this->schedule->all(
new RelatedFilter($stop), new RelatedFilter($stop, Stop::class),
new FieldFilter('departure', $time, '>='), new FieldFilter('departure', $time, '>='),
new With('track'), new With('track'),
new With('destination'), new With('destination'),
Limit::count(16) ...$modifiers
); );
} }
@ -181,4 +191,31 @@ class ZtmGdanskDepartureRepository implements DepartureRepository
$converted->setStop($stop->getStop()); $converted->setStop($stop->getStop());
}); });
} }
private function extractModifiers(iterable $modifiers)
{
$result = [];
/** @var Limit $limit */
if ($limit = ModifierUtils::getOfType($modifiers, Limit::class)) {
$result[] = new Limit($limit->getOffset(), $limit->getCount() * 2);
} else {
$result[] = Limit::count(16);
}
return $result;
}
private function processResultWithModifiers(Collection $result, iterable $modifiers)
{
foreach ($modifiers as $modifier) {
switch (true) {
case $modifier instanceof Limit:
$result = $result->slice($modifier->getOffset(), $modifier->getCount());
break;
}
}
return $result;
}
} }

View File

@ -0,0 +1,29 @@
<?php
namespace App\Service;
use Kadet\Functional\Predicate;
use function Kadet\Functional\Predicates\instance;
final class ModifierUtils
{
public static function get(iterable $modifiers, Predicate $predicate)
{
return collect($modifiers)->first($predicate);
}
public static function getOfType(iterable $modifiers, $class)
{
return self::get($modifiers, instance($class));
}
public static function hasAny(iterable $modifiers, Predicate $predicate)
{
return collect($modifiers)->contains($predicate);
}
public static function hasAnyOfType(iterable $modifiers, $class)
{
return collect($modifiers)->contains(instance($class));
}
}