Skip to content

Commit cba1047

Browse files
author
codeliner
committed
Find partial docs
1 parent 7edb158 commit cba1047

File tree

3 files changed

+336
-7
lines changed

3 files changed

+336
-7
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"require": {
1919
"php": "^7.1",
2020
"ext-pdo": "*",
21-
"event-engine/php-persistence": "^0.5"
21+
"event-engine/php-persistence": "^0.6"
2222
},
2323
"require-dev": {
2424
"roave/security-advisories": "dev-master",

src/PostgresDocumentStore.php

Lines changed: 152 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,28 @@
1111

1212
namespace EventEngine\DocumentStore\Postgres;
1313

14+
use ArrayIterator;
1415
use EventEngine\DocumentStore;
1516
use EventEngine\DocumentStore\Filter\Filter;
1617
use EventEngine\DocumentStore\Index;
1718
use EventEngine\DocumentStore\OrderBy\OrderBy;
19+
use EventEngine\DocumentStore\PartialSelect;
1820
use EventEngine\DocumentStore\Postgres\Exception\InvalidArgumentException;
1921
use EventEngine\DocumentStore\Postgres\Exception\RuntimeException;
2022
use EventEngine\Util\VariableType;
23+
use function implode;
24+
use function is_string;
25+
use function json_decode;
26+
use function mb_strlen;
27+
use function mb_substr;
28+
use function sprintf;
29+
use function var_dump;
2130

2231
final class PostgresDocumentStore implements DocumentStore\DocumentStore
2332
{
33+
private const PARTIAL_SELECT_DOC_ID = '__partial_sel_doc_id__';
34+
private const PARTIAL_SELECT_MERGE = '__partial_sel_merge__';
35+
2436
/**
2537
* @var \PDO
2638
*/
@@ -489,12 +501,7 @@ public function getDoc(string $collectionName, string $docId): ?array
489501
}
490502

491503
/**
492-
* @param string $collectionName
493-
* @param Filter $filter
494-
* @param int|null $skip
495-
* @param int|null $limit
496-
* @param OrderBy|null $orderBy
497-
* @return \Traversable list of docs
504+
* @inheritDoc
498505
*/
499506
public function filterDocs(string $collectionName, Filter $filter, int $skip = null, int $limit = null, OrderBy $orderBy = null): \Traversable
500507
{
@@ -524,6 +531,68 @@ public function filterDocs(string $collectionName, Filter $filter, int $skip = n
524531
}
525532
}
526533

534+
/**
535+
* @inheritDoc
536+
*/
537+
public function findDocs(string $collectionName, Filter $filter, int $skip = null, int $limit = null, OrderBy $orderBy = null): \Traversable
538+
{
539+
[$filterStr, $args] = $this->filterToWhereClause($filter);
540+
541+
$where = $filterStr ? "WHERE $filterStr" : '';
542+
543+
$offset = $skip !== null ? "OFFSET $skip" : '';
544+
$limit = $limit !== null ? "LIMIT $limit" : '';
545+
546+
$orderBy = $orderBy ? "ORDER BY " . implode(', ', $this->orderByToSort($orderBy)) : '';
547+
548+
$query = <<<EOT
549+
SELECT id, doc
550+
FROM {$this->schemaName($collectionName)}.{$this->tableName($collectionName)}
551+
$where
552+
$orderBy
553+
$limit
554+
$offset;
555+
EOT;
556+
$stmt = $this->connection->prepare($query);
557+
558+
$stmt->execute($args);
559+
560+
while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
561+
yield $row['id'] => json_decode($row['doc'], true);
562+
}
563+
}
564+
565+
public function findPartialDocs(string $collectionName, PartialSelect $partialSelect, Filter $filter, int $skip = null, int $limit = null, OrderBy $orderBy = null): \Traversable
566+
{
567+
[$filterStr, $args] = $this->filterToWhereClause($filter);
568+
569+
$select = $this->makeSelect($partialSelect);
570+
571+
$where = $filterStr ? "WHERE $filterStr" : '';
572+
573+
$offset = $skip !== null ? "OFFSET $skip" : '';
574+
$limit = $limit !== null ? "LIMIT $limit" : '';
575+
576+
$orderBy = $orderBy ? "ORDER BY " . implode(', ', $this->orderByToSort($orderBy)) : '';
577+
578+
$query = <<<EOT
579+
SELECT $select
580+
FROM {$this->schemaName($collectionName)}.{$this->tableName($collectionName)}
581+
$where
582+
$orderBy
583+
$limit
584+
$offset;
585+
EOT;
586+
587+
$stmt = $this->connection->prepare($query);
588+
589+
$stmt->execute($args);
590+
591+
while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
592+
yield $row[self::PARTIAL_SELECT_DOC_ID] => $this->transformPartialDoc($partialSelect, $row);
593+
}
594+
}
595+
527596
/**
528597
* @param string $collectionName
529598
* @param Filter $filter
@@ -714,6 +783,83 @@ private function makeInClause(string $prop, array $valList, int $argsCount, bool
714783
return ["$prop IN($params)", $argList, $argsCount];
715784
}
716785

786+
private function makeSelect(PartialSelect $partialSelect): string
787+
{
788+
$select = 'id as "'.self::PARTIAL_SELECT_DOC_ID.'", ';
789+
790+
foreach ($partialSelect->fieldAliasMap() as $mapItem) {
791+
792+
if($mapItem['alias'] === self::PARTIAL_SELECT_DOC_ID) {
793+
throw new RuntimeException(sprintf(
794+
"Invalid select alias. You cannot use %s as alias, because it is reserved for internal use",
795+
self::PARTIAL_SELECT_DOC_ID
796+
));
797+
}
798+
799+
if($mapItem['alias'] === self::PARTIAL_SELECT_MERGE) {
800+
throw new RuntimeException(sprintf(
801+
"Invalid select alias. You cannot use %s as alias, because it is reserved for internal use",
802+
self::PARTIAL_SELECT_MERGE
803+
));
804+
}
805+
806+
if($mapItem['alias'] === PartialSelect::MERGE_ALIAS) {
807+
$mapItem['alias'] = self::PARTIAL_SELECT_MERGE;
808+
}
809+
810+
$select.= $this->propToJsonPath($mapItem['field']) . ' as "' . $mapItem['alias'] . '", ';
811+
}
812+
813+
$select = mb_substr($select, 0, mb_strlen($select) - 2);
814+
815+
return $select;
816+
}
817+
818+
private function transformPartialDoc(PartialSelect $partialSelect, array $selectedDoc): array
819+
{
820+
$partialDoc = [];
821+
822+
foreach ($partialSelect->fieldAliasMap() as ['field' => $field, 'alias' => $alias]) {
823+
if($alias === PartialSelect::MERGE_ALIAS) {
824+
if(null === $selectedDoc[self::PARTIAL_SELECT_MERGE] ?? null) {
825+
continue;
826+
}
827+
828+
$value = json_decode($selectedDoc[self::PARTIAL_SELECT_MERGE], true);
829+
830+
if(!is_array($value)) {
831+
throw new RuntimeException('Merge not possible. $merge alias was specified for field: ' . $field . ' but field value is not an array: ' . json_encode($value));
832+
}
833+
834+
foreach ($value as $k => $v) {
835+
$partialDoc[$k] = $v;
836+
}
837+
838+
continue;
839+
}
840+
841+
$value = $selectedDoc[$alias] ?? null;
842+
843+
if(is_string($value)) {
844+
$value = json_decode($value, true);
845+
}
846+
847+
$keys = explode('.', $alias);
848+
849+
$ref = &$partialDoc;
850+
foreach ($keys as $i => $key) {
851+
if(!array_key_exists($key, $ref)) {
852+
$ref[$key] = [];
853+
}
854+
$ref = &$ref[$key];
855+
}
856+
$ref = $value;
857+
unset($ref);
858+
}
859+
860+
return $partialDoc;
861+
}
862+
717863
private function orderByToSort(DocumentStore\OrderBy\OrderBy $orderBy): array
718864
{
719865
$sort = [];

0 commit comments

Comments
 (0)