public function testToPbRow() { $now = new \DateTime(); $row = [(new Cell('string'))->setValue('test'), (new Cell('int'))->setIntValue(1), (new Cell('double'))->setDoubleValue(1.1), (new Cell('bool'))->setBooleanValue(true), (new Cell('timestamp'))->setTimestampValue($now->getTimestamp()), (new Cell('timestampdt'))->setDateTimeValue($now)]; $tsRow = TimeSeries::toPbRow($row); $this->assertEquals('test', $tsRow->getCellsAt(0)->getVarcharValue()); $this->assertEquals(1, $tsRow->getCellsAt(1)->getSint64Value()); $this->assertEquals(1.1, $tsRow->getCellsAt(2)->getDoubleValue()); $this->assertEquals(true, $tsRow->getCellsAt(3)->getBooleanValue()); $this->assertEquals($now->getTimestamp(), $tsRow->getCellsAt(4)->getTimestampValue()); $this->assertEquals($now->getTimestamp(), $tsRow->getCellsAt(5)->getTimestampValue()); }
/** * Parses the Protobuff response and builds the proper response object to forward on. Note: This method attempts to * maintain parity with the HTTP interface for the status codes returned for consistency purposes. * * 200 = Success, content returned * 201 = Created * 204 = Success, no content returned * 300 = Multiple choices * 404 = Not found * 503 = Service Unavailable / Timeout * * @param $message_code PB Message identifier @see Basho\Riak\Api\Pb\Message * @param string $message Binary message * @throws Exception * @internal param string $response */ protected function parseResponse($message_code, $message = '') { $this->success = true; $code = 204; $location = null; switch ($message_code) { case Api\Pb\Message::RpbErrorResp: $pbResponse = new Api\Pb\Message\RpbErrorResp(); $pbResponse->parseFromString($message); $this->error = $pbResponse->getErrmsg(); // intercept certain "errors" to provide consistent cross interface behavior if (strpos($message, "Query unsuccessful") !== false) { // HTTP status code for bad request, consider it a request success $code = 400; $this->response = new Command\Search\Response($this->success, $code, '', null); break; } elseif (strpos($message, "timeout") !== false) { // set HTTP status code for service unavailable, consider it a request success $code = 503; $this->response = new Command\Indexes\Response($this->success, $code, $this->error); break; } elseif (strpos($message, "notfound") !== false) { // set HTTP status code for not found, consider it a request success $code = 404; } else { $code = $pbResponse->getErrcode(); $this->success = false; } $this->response = new Command\Response($this->success, $code, $this->error); break; case Api\Pb\Message::RpbPutResp: $pbResponse = new Api\Pb\Message\RpbPutResp(); $pbResponse->parseFromString($message); if ($pbResponse->getKey()) { $code = 201; $location = new Location($pbResponse->getKey(), $this->getCommand()->getBucket()); } $objects = []; foreach ($pbResponse->getContent() as $content) { /** @var Command\Object $command */ $command = $this->command; $object = (new Object())->setData($command->getDecodedData($content->getValue(), $content->getContentType()))->setContentType($content->getContentType())->setContentEncoding($content->getContentEncoding())->setVclock($pbResponse->getVclock()); foreach ($content->getIndexes() as $rpbPair) { $object->addValueToIndex($rpbPair->getKey(), $rpbPair->getValue()); } foreach ($content->getUsermeta() as $meta) { $object->setMetaDataValue($meta->getKey(), $meta->getValue()); } $objects[] = $object; } if ($objects) { $code = 200; } $this->response = new Command\Object\Response($this->success, $code, '', $location, $objects); break; case Api\Pb\Message::RpbGetResp: $code = 404; $pbResponse = new Api\Pb\Message\RpbGetResp(); $pbResponse->parseFromString($message); $objects = []; foreach ($pbResponse->getContent() as $content) { /** @var Command\Object $command */ $command = $this->command; $object = (new Object())->setData($command->getDecodedData($content->getValue(), $content->getContentType()))->setRawData($content->getValue())->setContentType($content->getContentType())->setContentEncoding($content->getContentEncoding())->setVclock($pbResponse->getVclock()); foreach ($content->getIndexes() as $rpbPair) { $isIntIndex = Api\Http\Translator\SecondaryIndex::isIntIndex($rpbPair->getKey()); if ($isIntIndex) { $value = intval($rpbPair->getValue()); } else { $value = $rpbPair->getValue(); } $object->addValueToIndex($rpbPair->getKey(), $value); } foreach ($content->getUsermeta() as $meta) { $object->setMetaDataValue($meta->getKey(), $meta->getValue()); } $objects[] = $object; } $object_count = count($objects); if ($object_count == 1) { $code = 200; } elseif ($object_count > 1) { $code = 300; } $this->response = new Command\Object\Response($this->success, $code, '', $location, $objects); break; case Api\Pb\Message::RpbGetBucketKeyPreflistResp: $code = 200; $pbResponse = new Api\Pb\Message\RpbGetBucketKeyPreflistResp(); $pbResponse->parseFromString($message); $items = []; foreach ($pbResponse->getPreflist() as $preflistItem) { $item = new \stdClass(); $item->node = $preflistItem->getNode(); $item->partition = $preflistItem->getPartition(); $item->primary = $preflistItem->getPrimary(); $items[] = $item; } // for consistent interface with http $preflist = new \stdClass(); $preflist->preflist = $items; $this->response = new Command\Object\Response($this->success, $code, '', $location, [new Object($preflist)]); break; /** @noinspection PhpMissingBreakStatementInspection */ /** @noinspection PhpMissingBreakStatementInspection */ case Api\Pb\Message::RpbPingResp: $code = 200; case Api\Pb\Message::RpbDelResp: case Api\Pb\Message::RpbSetBucketResp: $this->response = new Command\Response($this->success, $code, ''); break; case Api\Pb\Message::RpbGetBucketResp: $code = 200; $pbResponse = new Api\Pb\Message\RpbGetBucketResp(); $pbResponse->parseFromString($message); $pbProps = $pbResponse->getProps(); $props = []; foreach ($pbProps->fields() as $field_position => $field_meta) { $props[$field_meta['name']] = $pbProps->get($field_position); } $bucket = new Bucket($this->command->getBucket()->getName(), $this->command->getBucket()->getType(), $props); $this->response = new Command\Bucket\Response($this->success, $code, '', $bucket); break; case Api\Pb\Message::DtUpdateResp: $pbResponse = new Api\Pb\Message\DtUpdateResp(); $pbResponse->parseFromString($message); if ($pbResponse->getKey()) { $code = 201; $location = new Location($pbResponse->getKey(), $this->getCommand()->getBucket()); } if ($pbResponse->getCounterValue()) { $counter = new DataType\Counter($pbResponse->getCounterValue()); $this->response = new Command\DataType\Counter\Response($this->success, $code, '', $location, $counter); } elseif ($pbResponse->getSetValueCount()) { $set = new DataType\Set($pbResponse->getSetValue(), $pbResponse->getContext()); $this->response = new Command\DataType\Set\Response($this->success, $code, '', $location, $set); } elseif ($pbResponse->getMapValueCount()) { $map = new DataType\Map(Api\Pb\Translator\DataType::mapEntriesToArray($pbResponse->getMapValue()), $pbResponse->getContext()); $this->response = new Command\DataType\Map\Response($this->success, $code, '', $location, $map); } else { $command = get_class($this->command); if ($command == 'Basho\\Riak\\Command\\DataType\\Counter\\Store') { $this->response = new Command\DataType\Counter\Response($this->success, $code, '', $location); } elseif ($command == 'Basho\\Riak\\Command\\DataType\\Set\\Store') { $this->response = new Command\DataType\Set\Response($this->success, $code, '', $location); } elseif ($command == 'Basho\\Riak\\Command\\DataType\\Map\\Store') { $this->response = new Command\DataType\Map\Response($this->success, $code, '', $location); } elseif ($command == 'Basho\\Riak\\Command\\DataType\\Hll\\Store') { $this->response = new Command\DataType\Hll\Response($this->success, $code, '', $location); } } break; case Api\Pb\Message::DtFetchResp: $code = 200; $pbResponse = new Api\Pb\Message\DtFetchResp(); $pbResponse->parseFromString($message); // if value is null, the DT couldn't be found if ($pbResponse->getValue()) { switch ($pbResponse->getType()) { case Api\Pb\Message\DtFetchResp\DataType::COUNTER: $counter = new DataType\Counter($pbResponse->getValue()->getCounterValue()); $this->response = new Command\DataType\Counter\Response($this->success, $code, '', null, $counter); break; case Api\Pb\Message\DtFetchResp\DataType::SET: $set = new DataType\Set($pbResponse->getValue()->getSetValue(), $pbResponse->getContext()); $this->response = new Command\DataType\Set\Response($this->success, $code, '', null, $set); break; case Api\Pb\Message\DtFetchResp\DataType::MAP: $map = new DataType\Map(Api\Pb\Translator\DataType::mapEntriesToArray($pbResponse->getValue()->getMapValue()), $pbResponse->getContext()); $this->response = new Command\DataType\Map\Response($this->success, $code, '', null, $map); break; case Api\Pb\Message\DtFetchResp\DataType::HLL: $hll = new DataType\Hll($pbResponse->getValue()->getHllValue()); $this->response = new Command\DataType\Hll\Response($this->success, $code, '', null, $hll); break; default: throw new Exception('Unknown data type.'); } } else { $this->response = new Command\Response($this->success, 404, ''); } break; case Api\Pb\Message::RpbMapRedResp: $code = null; $results = []; $pbResponse = new Api\Pb\Message\RpbMapRedResp(); $pbResponse->parseFromString($message); while ($code === null) { if (!$pbResponse->getDone()) { // We haven't received all responses from Riak, merge the results $results = array_merge($results, json_decode($pbResponse->getResponse())); // Continue reading from the socket $length = $this->readMessageLength(); if ($this->readMessageCode() != Api\Pb\Message::RpbMapRedResp) { throw new Exception('Unknown response from Riak.'); } $message = $this->readMessage($length); $pbResponse = new Api\Pb\Message\RpbMapRedResp(); $pbResponse->parseFromString($message); } else { // All responses from Riak are complete, return a 200 code $code = 200; } } $this->response = new Command\MapReduce\Response($this->success, $code, '', $results); break; case Api\Pb\Message::RpbSearchQueryResp: $code = 200; $docs = []; $pbResponse = new Api\Pb\Message\RpbSearchQueryResp(); $pbResponse->parseFromString($message); foreach ($pbResponse->getDocs() as $pbDoc) { $doc = new \stdClass(); foreach ($pbDoc->getFields() as $rpbPair) { $doc->{$rpbPair->getKey()} = $rpbPair->getValue(); } $docs[] = new Doc($doc); } $this->response = new Command\Search\Response($this->success, $code, '', $pbResponse->getNumFound(), $docs); break; case Api\Pb\Message::RpbYokozunaIndexGetResp: $code = 200; $pbResponse = new Api\Pb\Message\RpbYokozunaIndexGetResp(); $pbResponse->parseFromString($message); $index = new \stdClass(); $index->name = $pbResponse->getIndexAt(0)->getName(); $index->n_val = $pbResponse->getIndexAt(0)->getNVal(); $index->schema = $pbResponse->getIndexAt(0)->getSchema(); $this->response = new Command\Search\Index\Response($this->success, $code, '', $index); break; case Api\Pb\Message::RpbYokozunaSchemaGetResp: $code = 200; $pbResponse = new Api\Pb\Message\RpbYokozunaSchemaGetResp(); $pbResponse->parseFromString($message); $this->response = new Command\Search\Schema\Response($this->success, $code, '', $pbResponse->getSchema()->getContent(), Http::CONTENT_TYPE_XML); break; case Api\Pb\Message::RpbIndexResp: $code = 200; $pbResponse = new Api\Pb\Message\RpbIndexResp(); $pbResponse->parseFromString($message); // sane defaults $results = []; $termsReturned = false; $continuation = null; $done = true; if ($pbResponse->getKeys()) { $results = $pbResponse->getKeys(); } if ($pbResponse->getResultsCount()) { foreach ($pbResponse->getResults() as $result) { $results[] = [$result->getKey() => $result->getValue()]; } $termsReturned = true; } if ($pbResponse->getContinuation()) { $continuation = $pbResponse->getContinuation(); $done = false; } $this->response = new Command\Indexes\Response($this->success, $code, '', $results, $termsReturned, $continuation, $done); break; case Api\Pb\Message::TsDelResp: case Api\Pb\Message::TsPutResp: $this->success = true; $this->response = new Command\TimeSeries\Response($this->success, $code, ''); break; case Api\Pb\Message::TsGetResp: $this->success = true; $pbResponse = new Api\Pb\Message\TsGetResp(); $pbResponse->parseFromString($message); $rows = []; foreach ($pbResponse->getRows() as $row) { $rows[] = Api\Pb\Translator\TimeSeries::fromPbRow($row, $pbResponse->getColumns()); } $this->response = new Command\TimeSeries\Response($this->success, count($rows) ? 200 : 404, '', $rows); break; case Api\Pb\Message::TsQueryResp: $this->success = true; $pbResponse = new Api\Pb\Message\TsQueryResp(); $pbResponse->parseFromString($message); $rows = []; foreach ($pbResponse->getRows() as $row) { $rows[] = Api\Pb\Translator\TimeSeries::fromPbRow($row, $pbResponse->getColumns()); } $this->response = new Command\TimeSeries\Query\Response($this->success, count($rows) ? 200 : 204, '', $rows); break; default: throw new Api\Exception('Mishandled PB response.'); } }