Skip to content

Commit

Permalink
Merge pull request #15 from event-engine/feature/filter_partial_docs
Browse files Browse the repository at this point in the history
Add method to filter partial documents
  • Loading branch information
codeliner authored Mar 29, 2020
2 parents f5d9caa + dae2b5f commit 350ebd4
Show file tree
Hide file tree
Showing 5 changed files with 505 additions and 22 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
composer.lock
vendor
vendor
.php_cs.cache
25 changes: 25 additions & 0 deletions src/DocumentStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ public function deleteMany(string $collectionName, Filter $filter): void;
public function getDoc(string $collectionName, string $docId): ?array;

/**
* @deprecated use findDocs instead
*
* @param string $collectionName
* @param Filter $filter
* @param int|null $skip
Expand All @@ -137,6 +139,29 @@ public function getDoc(string $collectionName, string $docId): ?array;
*/
public function filterDocs(string $collectionName, Filter $filter, int $skip = null, int $limit = null, OrderBy $orderBy = null): \Traversable;

/**
* @param string $collectionName
* @param Filter $filter
* @param int|null $skip
* @param int|null $limit
* @param OrderBy|null $orderBy
* @return \Traversable list of docs with key being the docId and value being the stored doc
* @throws UnknownCollection
*/
public function findDocs(string $collectionName, Filter $filter, int $skip = null, int $limit = null, OrderBy $orderBy = null): \Traversable;

/**
* @param string $collectionName
* @param PartialSelect $partialSelect
* @param Filter $filter
* @param int|null $skip
* @param int|null $limit
* @param OrderBy|null $orderBy
* @return \Traversable list of docs with key being the docId and value being the stored doc
* @throws UnknownCollection
*/
public function findPartialDocs(string $collectionName, PartialSelect $partialSelect, Filter $filter, int $skip = null, int $limit = null, OrderBy $orderBy = null): \Traversable;

/**
* @param string $collectionName
* @param Filter $filter
Expand Down
166 changes: 150 additions & 16 deletions src/InMemoryDocumentStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@
use EventEngine\DocumentStore\Exception\RuntimeException;
use EventEngine\DocumentStore\Exception\UnknownCollection;
use EventEngine\DocumentStore\Filter\AndFilter;
use EventEngine\DocumentStore\Filter\AnyFilter;
use EventEngine\DocumentStore\Filter\EqFilter;
use EventEngine\DocumentStore\Filter\Filter;
use EventEngine\DocumentStore\OrderBy\AndOrder;
use EventEngine\DocumentStore\OrderBy\Asc;
use EventEngine\DocumentStore\OrderBy\Desc;
use EventEngine\DocumentStore\OrderBy\OrderBy;
use EventEngine\Persistence\InMemoryConnection;
use function array_key_exists;
use function count;
use function explode;
use function is_array;
use function json_encode;

final class InMemoryDocumentStore implements DocumentStore
{
Expand Down Expand Up @@ -283,16 +287,100 @@ public function getDoc(string $collectionName, string $docId): ?array
return $this->inMemoryConnection['documents'][$collectionName][$docId] ?? null;
}

/**
* @inheritDoc
*/
public function filterDocs(
string $collectionName,
Filter $filter,
int $skip = null,
int $limit = null,
OrderBy $orderBy = null): \Traversable
{
$this->assertHasCollection($collectionName);

$filteredDocs = [];

foreach ($this->inMemoryConnection['documents'][$collectionName] as $docId => $doc) {
if ($filter->match($doc, (string)$docId)) {
$filteredDocs[$docId] = ['doc' => $doc, 'docId' => $docId];
}
}

$filteredDocs = \array_values($filteredDocs);

if ($orderBy !== null) {
$this->sort($filteredDocs, $orderBy);
}

if ($skip !== null) {
$filteredDocs = \array_slice($filteredDocs, $skip, $limit);
} elseif ($limit !== null) {
$filteredDocs = \array_slice($filteredDocs, 0, $limit);
}

$docsMap = [];

foreach ($filteredDocs as $docAndId) {
$docsMap[] = $docAndId['doc'];
}

return new \ArrayIterator($docsMap);
}

/**
* @inheritDoc
*/
public function findDocs(
string $collectionName,
Filter $filter,
int $skip = null,
int $limit = null,
OrderBy $orderBy = null): \Traversable
{
$this->assertHasCollection($collectionName);

$filteredDocs = [];

foreach ($this->inMemoryConnection['documents'][$collectionName] as $docId => $doc) {
if ($filter->match($doc, (string)$docId)) {
$filteredDocs[$docId] = ['doc' => $doc, 'docId' => $docId];
}
}

$filteredDocs = \array_values($filteredDocs);

if ($orderBy !== null) {
$this->sort($filteredDocs, $orderBy);
}

if ($skip !== null) {
$filteredDocs = \array_slice($filteredDocs, $skip, $limit);
} elseif ($limit !== null) {
$filteredDocs = \array_slice($filteredDocs, 0, $limit);
}

$docsMap = [];

foreach ($filteredDocs as $docAndId) {
$docsMap[$docAndId['docId']] = $docAndId['doc'];
}

return new \ArrayIterator($docsMap);
}

/**
* @param string $collectionName
* @param PartialSelect $partialSelect
* @param Filter $filter
* @param int|null $skip
* @param int|null $limit
* @param OrderBy|null $orderBy
* @return \Traversable list of docs
*/
public function filterDocs(
public function findPartialDocs(
string $collectionName,
PartialSelect $partialSelect,
Filter $filter,
int $skip = null,
int $limit = null,
Expand All @@ -304,7 +392,7 @@ public function filterDocs(

foreach ($this->inMemoryConnection['documents'][$collectionName] as $docId => $doc) {
if ($filter->match($doc, (string)$docId)) {
$filteredDocs[$docId] = $doc;
$filteredDocs[$docId] = ['doc' => $doc, 'docId' => $docId];
}
}

Expand All @@ -320,7 +408,13 @@ public function filterDocs(
$filteredDocs = \array_slice($filteredDocs, 0, $limit);
}

return new \ArrayIterator($filteredDocs);
$docsMap = [];

foreach ($filteredDocs as $docAndId) {
$docsMap[$docAndId['docId']] = $this->transformToPartialDoc($docAndId['doc'], $partialSelect);
}

return new \ArrayIterator($docsMap);
}

/**
Expand All @@ -344,6 +438,23 @@ public function filterDocIds(
return $docIds;
}

/**
* @inheritDoc
*/
public function countDocs(string $collectionName, Filter $filter) : int
{
$this->assertHasCollection($collectionName);

$counter = 0;
foreach ($this->inMemoryConnection['documents'][$collectionName] as $docId => $doc) {
if ($filter->match($doc, $docId)) {
$counter++;
}
}

return $counter;
}

private function hasDoc(string $collectionName, string $docId): bool
{
if (! $this->hasCollection($collectionName)) {
Expand Down Expand Up @@ -489,12 +600,12 @@ private function sort(&$docs, OrderBy $orderBy)
if ($orderBy instanceof Asc || $orderBy instanceof Desc) {
$field = $orderBy->prop();

return (new ArrayReader($doc))->mixedValue($field);
return (new ArrayReader($doc['doc']))->mixedValue($field);
}

throw new \RuntimeException(\sprintf(
'Unable to get field from doc: %s. Given OrderBy is neither an instance of %s nor %s',
\json_encode($doc),
\json_encode($doc['doc']),
Asc::class,
Desc::class
));
Expand Down Expand Up @@ -573,20 +684,43 @@ private function isSequentialArray(array $array): bool
return \array_keys($array) === \range(0, \count($array) - 1);
}

/**
* @inheritDoc
*/
public function countDocs(string $collectionName, Filter $filter) : int
private function transformToPartialDoc(array $doc, PartialSelect $partialSelect): array
{
$this->assertHasCollection($collectionName);
$partialDoc = [];
$reader = new ArrayReader($doc);

$counter = 0;
foreach ($this->inMemoryConnection['documents'][$collectionName] as $docId => $doc) {
if ($filter->match($doc, $docId)) {
$counter++;
foreach ($partialSelect->fieldAliasMap() as ['field' => $field, 'alias' => $alias]) {
$value = $reader->mixedValue($field);

if($alias === PartialSelect::MERGE_ALIAS) {
if(null === $value) {
continue;
}

if(!is_array($value)) {
throw new RuntimeException('Merge not possible. $merge alias was specified for field: ' . $field . ' but field value is not an array: ' . json_encode($value));
}

foreach ($value as $k => $v) {
$partialDoc[$k] = $v;
}

continue;
}

$keys = explode('.', $alias);

$ref = &$partialDoc;
foreach ($keys as $i => $key) {
if(!array_key_exists($key, $ref)) {
$ref[$key] = [];
}
$ref = &$ref[$key];
}
$ref = $value;
unset($ref);
}

return $counter;
return $partialDoc;
}
}
Loading

0 comments on commit 350ebd4

Please sign in to comment.