diff --git a/firestore/composer.json b/firestore/composer.json index fc60256a3b..3d4eba7ce5 100644 --- a/firestore/composer.json +++ b/firestore/composer.json @@ -24,9 +24,11 @@ "src/end_at_field_query_cursor.php", "src/get_all.php", "src/get_all_docs.php", + "src/get_distributed_counter_value.php", "src/get_document.php", "src/get_multiple_docs.php", "src/initialize.php", + "src/initialize_distributed_counter.php", "src/initialize_project_id.php", "src/invalid_range_order_by_query.php", "src/invalid_range_query.php", @@ -49,6 +51,7 @@ "src/start_at_field_query_cursor.php", "src/start_at_snapshot_query_cursor.php", "src/subcollection_ref.php", + "src/update_distributed_counter.php", "src/update_doc.php", "src/update_doc_array.php", "src/update_nested_fields.php", diff --git a/firestore/firestore.php b/firestore/firestore.php index da3f9995fe..8b0fc5beb9 100644 --- a/firestore/firestore.php +++ b/firestore/firestore.php @@ -939,6 +939,57 @@ }) ); +//Create distributed counter +$application->add((new Command('initialize-distributed-counter')) + ->setDefinition($inputDefinition) + ->setDescription('Creates a subcollection from the specified multiple shards.') + ->setHelp(<<%command.name% command creates a distributed counter as a sub collection in Google Cloud Firestore, consisting of several empty shards. + + php %command.full_name% + +EOF + ) + ->setCode(function ($input, $output) { + $projectId = $input->getArgument('project'); + initialize_distributed_counter($projectId); + }) +); + +//Increment (distributed counter) +$application->add((new Command('update-distributed-counter')) + ->setDefinition($inputDefinition) + ->setDescription('Increments a randomly picked shard of a distributed counter.') + ->setHelp(<<%command.name% command increments the randomly selected shard of a distributed counter using the Google Cloud Firestore API. + + php %command.full_name% + +EOF + ) + ->setCode(function ($input, $output) { + $projectId = $input->getArgument('project'); + update_distributed_counter($projectId); + }) +); + +//get value (distributed counter) +$application->add((new Command('get-distributed-counter-value')) + ->setDefinition($inputDefinition) + ->setDescription('Returns the total count across all the shards of a distributed counter.') + ->setHelp(<<%command.name% command returns the total count across all the shards of a distributed counter, using the Google Cloud Firestore API. + + php %command.full_name% + +EOF + ) + ->setCode(function ($input, $output) { + $projectId = $input->getArgument('project'); + get_distributed_counter_value($projectId); + }) +); + // for testing if (getenv('PHPUNIT_TESTS') === '1') { return $application; diff --git a/firestore/src/get_distributed_counter_value.php b/firestore/src/get_distributed_counter_value.php new file mode 100644 index 0000000000..b413f44ff2 --- /dev/null +++ b/firestore/src/get_distributed_counter_value.php @@ -0,0 +1,49 @@ + $projectId, + ]); + $ref = $db->collection('Shards_collection')->document('Distributed_counters'); + # [START fs_get_distributed_counter_value] + $result = 0; + $docCollection = $ref->collection('SHARDS')->documents(); + foreach ($docCollection as $doc) { + $result += $doc->data()['Cnt']; + } + # [END fs_get_distributed_counter_value] + printf('The current value of the distributed counter: %d' . PHP_EOL, $result); +} diff --git a/firestore/src/initialize_distributed_counter.php b/firestore/src/initialize_distributed_counter.php new file mode 100644 index 0000000000..56a3486849 --- /dev/null +++ b/firestore/src/initialize_distributed_counter.php @@ -0,0 +1,49 @@ + $projectId, + ]); + $ref = $db->collection('Shards_collection')->document('Distributed_counters'); + # [START fs_initialize_distributed_counter] + $numShards = 10; + $colRef = $ref->collection('SHARDS'); + for ($i = 0; $i < $numShards; $i++) { + $doc = $colRef->document($i); + $doc->set(['Cnt' => 0]); + } + # [END fs_initialize_distributed_counter] +} diff --git a/firestore/src/update_distributed_counter.php b/firestore/src/update_distributed_counter.php new file mode 100644 index 0000000000..f0cffc30cb --- /dev/null +++ b/firestore/src/update_distributed_counter.php @@ -0,0 +1,55 @@ + $projectId, + ]); + $ref = $db->collection('Shards_collection')->document('Distributed_counters'); + # [START fs_update_distributed_counter] + $colRef = $ref->collection('SHARDS'); + $numShards = 0; + $docCollection = $colRef->documents(); + foreach ($docCollection as $doc) { + $numShards++; + } + $shardIdx = random_int(0, $numShards-1); + $doc = $colRef->document($shardIdx); + $doc->update([ + ['path' => 'Cnt', 'value' => FieldValue::increment(1)] + ]); + # [END fs_update_distributed_counter] +} diff --git a/firestore/test/firestoreTest.php b/firestore/test/firestoreTest.php index 7a7d72b3b1..9074719007 100644 --- a/firestore/test/firestoreTest.php +++ b/firestore/test/firestoreTest.php @@ -17,6 +17,7 @@ namespace Google\Cloud\Samples\Firestore\Tests; +use Google\Cloud\Firestore\FirestoreClient; use Google\Cloud\TestUtils\TestTrait; use Google\Cloud\TestUtils\ExecuteCommandTrait; use PHPUnit\Framework\TestCase; @@ -507,4 +508,38 @@ private function runFirestoreCommand($commandName) 'project' => self::$firestoreProjectId ]); } + + public function testDistributedCounter() + { + $this->runFirestoreCommand('initialize-distributed-counter'); + $outputZero = $this->runFirestoreCommand('get-distributed-counter-value'); + $this->assertContains('0', $outputZero); + + //check count of shards + $db = new FirestoreClient([ + 'projectId' => self::$firestoreProjectId, + ]); + $ref = $db->collection('Shards_collection')->document('Distributed_counters'); + $collect = $ref->collection('SHARDS'); + $docCollection = $collect->documents(); + + $docIdList = []; + foreach ($docCollection as $docSnap) { + $docIdList[] = $docSnap->id(); + } + $this->assertEquals(10, count($docIdList)); + + //call thrice and check the value + $this->runFirestoreCommand('update-distributed-counter'); + $this->runFirestoreCommand('update-distributed-counter'); + $this->runFirestoreCommand('update-distributed-counter'); + + $output = $this->runFirestoreCommand('get-distributed-counter-value'); + $this->assertContains('3', $output); + + //remove temporary data + foreach ($docIdList as $docId) { + $collect->document($docId)->delete(); + } + } }