Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
27pchrisl committed Apr 10, 2021
1 parent f544abd commit 1d8f870
Show file tree
Hide file tree
Showing 18 changed files with 487 additions and 144 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,9 @@ using:
A Lodata 'driver' represents any storage system that could implement one or more of the `\Flat3\Lodata\Interfaces\EntitySet` interfaces
including `QueryInterface`, `ReadInterface`, `UpdateInterface`, `DeleteInterface`, and `CreateInterface`. In addition to the query
interface the driver may implement `SearchInterface` and `FilterInterface` to support `$search` and `$filter`, and other system
query parameters can be supported through `ExpandInterface`, `PaginationInterface` and `OrderByInterface`. Implementation of any
of these interfaces is optional, and Lodata will detect support and return a 'Not Implemented' exception to a client trying to use
an interface that is not available.
query parameters can be supported through `ExpandInterface`, `TokenPaginationInterface`, `PaginationInterface` and `OrderByInterface`.
Implementation of any of these interfaces is optional, and Lodata will detect support and return a 'Not Implemented' exception
to a client trying to use an interface that is not available.

A wide variety of different services can support these interfaces in whatever way makes sense to that service. Services could be
other databases, NoSQL services, other REST APIs or simple on-disk text files.
Expand Down
44 changes: 20 additions & 24 deletions src/Drivers/RedisEntitySet.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
use Flat3\Lodata\Interfaces\EntitySet\CountInterface;
use Flat3\Lodata\Interfaces\EntitySet\CreateInterface;
use Flat3\Lodata\Interfaces\EntitySet\DeleteInterface;
use Flat3\Lodata\Interfaces\EntitySet\PaginationInterface;
use Flat3\Lodata\Interfaces\EntitySet\QueryInterface;
use Flat3\Lodata\Interfaces\EntitySet\ReadInterface;
use Flat3\Lodata\Interfaces\EntitySet\TokenPaginationInterface;
use Flat3\Lodata\Interfaces\EntitySet\UpdateInterface;
use Flat3\Lodata\Type;
use Generator;
Expand All @@ -25,11 +25,14 @@
* Class RedisEntitySet
* @package Flat3\Lodata\Drivers
*/
class RedisEntitySet extends EntitySet implements CreateInterface, UpdateInterface, DeleteInterface, ReadInterface, QueryInterface, PaginationInterface, CountInterface
class RedisEntitySet extends EntitySet implements CreateInterface, UpdateInterface, DeleteInterface, ReadInterface, QueryInterface, TokenPaginationInterface, CountInterface
{
/** @var ?Connection $connection */
protected $connection = null;

/** @var int $pageSize */
protected $pageSize = 100;

public function __construct(string $identifier, EntityType $entityType)
{
parent::__construct($identifier, $entityType);
Expand Down Expand Up @@ -148,35 +151,28 @@ public function update(PropertyValue $key): Entity
*/
public function query(): Generator
{
$skipToken = $this->getSkipToken();
$token = $this->getSkipToken()->hasValue() ? $this->getSkipToken()->getValue() : 0;

if ($skipToken->isPaginationComplete()) {
return;
$pageSize = $this->pageSize;
if ($this->getTop()->hasValue()) {
$pageSize = min($pageSize, $this->getTop()->getValue());
}

$config = [];

$top = $this->getTop();

if ($top->hasValue()) {
$config['COUNT'] = $top->getValue();
}
do {
list($token, $keys) = $this->getConnection()->scan($token, ['COUNT' => $pageSize]);

list($redisPage, $results) = $this->getConnection()->scan($skipToken->getValue() ?: 0, $config);
foreach ($keys as $key) {
$keyValue = new PropertyValue();
$keyValue->setProperty($this->getType()->getKey());
$keyValue->setValue(Type\String_::factory(Str::after($key, config('database.redis.options.prefix'))));

if ($redisPage == 0) {
$skipToken->setPaginationComplete();
} else {
$skipToken->setValue($redisPage);
}
yield $this->read($keyValue);
}

foreach ($results as $key) {
$keyValue = new PropertyValue();
$keyValue->setProperty($this->getType()->getKey());
$keyValue->setValue(Type\String_::factory(Str::after($key, config('database.redis.options.prefix'))));
$this->getSkipToken()->setValue($token);
} while ($token > 0);

yield $this->read($keyValue);
}
$this->getSkipToken()->clearValue();
}

/**
Expand Down
88 changes: 41 additions & 47 deletions src/EntitySet.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use Flat3\Lodata\Interfaces\EntitySet\QueryInterface;
use Flat3\Lodata\Interfaces\EntitySet\ReadInterface;
use Flat3\Lodata\Interfaces\EntitySet\SearchInterface;
use Flat3\Lodata\Interfaces\EntitySet\TokenPaginationInterface;
use Flat3\Lodata\Interfaces\EntityTypeInterface;
use Flat3\Lodata\Interfaces\IdentifierInterface;
use Flat3\Lodata\Interfaces\JsonInterface;
Expand Down Expand Up @@ -93,12 +94,6 @@ abstract class EntitySet implements EntityTypeInterface, ReferenceInterface, Ide
*/
protected $applyQueryOptions = true;

/**
* Running total of emitted entities
* @var int $emittedEntityCount Emitted entities
*/
private $emittedEntityCount = 0;

public function __construct(string $identifier, EntityType $entityType)
{
$this->setIdentifier($identifier);
Expand Down Expand Up @@ -208,8 +203,7 @@ public function emitJson(Transaction $transaction): void
}

$entity->emitJson($transaction);
$this->emittedEntityCount++;

$this->getSkip()->increment();
$results->next();

if (!$results->valid() || --$limit === 0) {
Expand Down Expand Up @@ -675,56 +669,56 @@ public function addTrailingMetadata(Transaction $transaction, MetadataContainer
$count = $this->count();

if ($transaction->getCount()->hasValue()) {
$metadata['count'] = $count;
$metadata->offsetSet('count', $count);
}
}

$top = $transaction->getTop();
$skip = $transaction->getSkip();
$skipToken = $transaction->getSkipToken();
if ($this instanceof PaginationInterface) {
$top = $transaction->getTop();
$paginationParams = [];

if ($skipToken->isPaginationComplete()) {
return;
}
if ($top->hasValue()) {
switch (true) {
case $this instanceof TokenPaginationInterface:
$skipToken = $transaction->getSkipToken();

$transactionParams = array_diff_key(
$transaction->getQueryParams(),
array_flip(['$top', '$skip', '$skiptoken'])
);
if ($skipToken->hasValue()) {
$paginationParams['$top'] = $top->getValue();
$paginationParams['$skiptoken'] = $skipToken->getValue();
}
break;

$paginationParams = [];
case $this instanceof PaginationInterface:
$skip = $transaction->getSkip();

if ($top->hasValue()) {
if ($skipToken->hasValue()) {
$paginationParams['$top'] = $top->getValue();
$paginationParams['$skiptoken'] = $skipToken->getValue();
} else {
if ($top->hasValue()) {
$nextSkipValue = $this->emittedEntityCount + $skip->getValue();
if ($count === null || $nextSkipValue < $count) {
$paginationParams['$top'] = $top->getValue();
$paginationParams['$skip'] = $nextSkipValue;
}
if ($skip->hasValue() && ($count === null || $skip->getValue() < $count)) {
$paginationParams['$top'] = $top->getValue();
$paginationParams['$skip'] = $skip->getValue();
}
break;
}
}
}

if (!$paginationParams) {
return;
}
if ($paginationParams) {
$transactionParams = array_diff_key(
$transaction->getQueryParams(),
array_flip(['$top', '$skip', '$skiptoken'])
);

$metadata['nextLink'] = Url::http_build_url(
$resourceUrl,
[
'query' => http_build_query(
array_merge($transactionParams, $paginationParams),
null,
'&',
PHP_QUERY_RFC3986
),
],
Url::HTTP_URL_JOIN_QUERY
);
$metadata['nextLink'] = Url::http_build_url(
$resourceUrl,
[
'query' => http_build_query(
array_merge($transactionParams, $paginationParams),
null,
'&',
PHP_QUERY_RFC3986
),
],
Url::HTTP_URL_JOIN_QUERY
);
}
}
}

/**
Expand Down
11 changes: 11 additions & 0 deletions src/Interfaces/EntitySet/TokenPaginationInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Flat3\Lodata\Interfaces\EntitySet;

/**
* Token Pagination Interface
* @package Flat3\Lodata\Interfaces\EntitySet
*/
interface TokenPaginationInterface extends PaginationInterface
{
}
Loading

0 comments on commit 1d8f870

Please sign in to comment.