From 5a179ea2c7855f76c56ba2c9664d39953e6a7cc8 Mon Sep 17 00:00:00 2001 From: Gary Lockett Date: Sun, 27 Sep 2020 22:05:03 +0100 Subject: [PATCH] feature: add replaceDoc and replaceMany methods --- src/PostgresDocumentStore.php | 75 +++++++++++++++++++++++++++++ tests/PostgresDocumentStoreTest.php | 58 ++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/src/PostgresDocumentStore.php b/src/PostgresDocumentStore.php index 8bf7265..b18817b 100644 --- a/src/PostgresDocumentStore.php +++ b/src/PostgresDocumentStore.php @@ -19,6 +19,7 @@ use EventEngine\DocumentStore\Postgres\Exception\InvalidArgumentException; use EventEngine\DocumentStore\Postgres\Exception\RuntimeException; use EventEngine\Util\VariableType; + use function implode; use function is_string; use function json_decode; @@ -433,6 +434,80 @@ public function upsertDoc(string $collectionName, string $docId, array $docOrSub } } + /** + * @param string $collectionName + * @param string $docId + * @param array $doc + * @throws \Throwable if updating did not succeed + */ + public function replaceDoc(string $collectionName, string $docId, array $doc): void + { + $metadataStr = ''; + $metadata = []; + + if($this->useMetadataColumns && array_key_exists('metadata', $doc)) { + $metadata = $doc['metadata']; + unset($doc['metadata']); + + + foreach ($metadata as $k => $v) { + $metadataStr .= ', '.$k.' = :'.$k; + } + } + + $cmd = <<schemaName($collectionName)}.{$this->tableName($collectionName)} +SET doc = :doc{$metadataStr} +WHERE id = :id +; +EOT; + $this->transactional(function () use ($cmd, $docId, $doc, $metadata) { + $this->connection->prepare($cmd)->execute(array_merge([ + 'id' => $docId, + 'doc' => json_encode($doc) + ], $metadata)); + }); + } + + /** + * @param string $collectionName + * @param Filter $filter + * @param array $set + * @throws \Throwable in case of connection error or other issues + */ + public function replaceMany(string $collectionName, Filter $filter, array $set): void + { + [$filterStr, $args] = $this->filterToWhereClause($filter); + + $where = $filterStr? "WHERE $filterStr" : ''; + + $metadataStr = ''; + $metadata = []; + + if($this->useMetadataColumns && array_key_exists('metadata', $set)) { + $metadata = $set['metadata']; + unset($set['metadata']); + + + foreach ($metadata as $k => $v) { + $metadataStr .= ', '.$k.' = :'.$k; + } + } + + $cmd = <<schemaName($collectionName)}.{$this->tableName($collectionName)} +SET doc = :doc{$metadataStr} +$where; +EOT; + + $args['doc'] = json_encode($set); + $args = array_merge($args, $metadata); + + $this->transactional(function () use ($cmd, $args) { + $this->connection->prepare($cmd)->execute($args); + }); + } + /** * @param string $collectionName * @param string $docId diff --git a/tests/PostgresDocumentStoreTest.php b/tests/PostgresDocumentStoreTest.php index b8dc9b0..10671d5 100644 --- a/tests/PostgresDocumentStoreTest.php +++ b/tests/PostgresDocumentStoreTest.php @@ -151,6 +151,64 @@ public function it_adds_collection_with_multi_field_index_unique(): void $this->assertStringStartsWith('CREATE UNIQUE INDEX', $indexes[1]['indexdef']); } + /** + * @test + */ + public function it_replaces_a_doc() + { + $collectionName = 'test_replaces_a_doc'; + $this->documentStore->addCollection($collectionName); + + $doc = [ + 'some' => [ + 'prop' => 'foo', + 'other' => [ + 'nested' => 42 + ] + ], + 'baz' => 'bat', + ]; + + $docId = Uuid::uuid4()->toString(); + $this->documentStore->addDoc($collectionName, $docId, $doc); + + $doc = ['baz' => 'changed val']; + + $this->documentStore->replaceDoc($collectionName, $docId, $doc); + + $filter = new EqFilter('baz', 'changed val'); + + $filteredDocs = $this->documentStore->findDocs($collectionName, $filter); + + $this->assertCount(1, $filteredDocs); + } + + /** + * @test + */ + public function it_replaces_many() + { + $collectionName = 'test_replaces_many'; + $this->documentStore->addCollection($collectionName); + + $this->documentStore->addDoc($collectionName, Uuid::uuid4()->toString(), ['some' => ['prop' => 'foo', 'other' => ['prop' => 'bat']]]); + $this->documentStore->addDoc($collectionName, Uuid::uuid4()->toString(), ['some' => ['prop' => 'bar', 'other' => ['prop' => 'bat']]]); + $this->documentStore->addDoc($collectionName, Uuid::uuid4()->toString(), ['some' => ['prop' => 'bar']]); + + $doc = ['some' => ['prop' => 'fuzz']]; + $this->documentStore->replaceMany( + $collectionName, + new EqFilter('some.other.prop', 'bat'), + $doc + ); + + $filteredDocs = array_values(iterator_to_array($this->documentStore->findDocs($collectionName, new EqFilter('some.prop', 'fuzz')))); + + $this->assertCount(2, $filteredDocs); + $this->assertEquals($doc, $filteredDocs[0]); + $this->assertEquals($doc, $filteredDocs[1]); + } + /** * @test */