diff --git a/lib/couchbase/protostellar/collection.rb b/lib/couchbase/protostellar/collection.rb index ace6a29d..ace73fa2 100644 --- a/lib/couchbase/protostellar/collection.rb +++ b/lib/couchbase/protostellar/collection.rb @@ -132,12 +132,16 @@ def mutate_in(id, specs, options = Couchbase::Options::MutateIn::DEFAULT) ResponseConverter::KV.to_mutate_in_result(resp, specs, options) end - def get_any_replica(_id, _options = Couchbase::Options::GetAnyReplica::DEFAULT) - raise Couchbase::Error::FeatureNotAvailable, "The #{Protostellar::NAME} protocol does not support get any replica" + def get_any_replica(id, options = Couchbase::Options::GetAnyReplica::DEFAULT) + req = @kv_request_generator.get_any_replica_request(id, options) + resp = @client.send_request(req) + ResponseConverter::KV.to_get_any_replica_result(resp, options) end - def get_all_replicas(_id, _options = Couchbase::Options::GetAllReplicas::DEFAULT) - raise Couchbase::Error::FeatureNotAvailable, "The #{Protostellar::NAME} protocol does not support get all replicas" + def get_all_replicas(id, options = Couchbase::Options::GetAllReplicas::DEFAULT) + req = @kv_request_generator.get_all_replicas_request(id, options) + resp = @client.send_request(req) + ResponseConverter::KV.to_get_all_replicas_result(resp, options) end def scan(_scan_type, _options = Options::Scan::DEFAULT) diff --git a/lib/couchbase/protostellar/request_generator/kv.rb b/lib/couchbase/protostellar/request_generator/kv.rb index 4a686044..a6206ce0 100644 --- a/lib/couchbase/protostellar/request_generator/kv.rb +++ b/lib/couchbase/protostellar/request_generator/kv.rb @@ -341,6 +341,20 @@ def prepend_request(id, content, options) create_kv_request(proto_req, :prepend, options) end + def get_all_replicas_request(id, options) + proto_req = Generated::KV::V1::GetAllReplicasRequest.new( + key: id, + **location + ) + + create_kv_request(proto_req, :get_all_replicas, options, idempotent: true) + end + + def get_any_replica_request(id, options) + # Uses the GetAllReplicas request and returns the first item from the result + get_all_replicas_request(id, options) + end + private def create_kv_request(proto_request, rpc, options, idempotent: false) diff --git a/lib/couchbase/protostellar/response_converter/kv.rb b/lib/couchbase/protostellar/response_converter/kv.rb index fd3da369..bed9f1e0 100644 --- a/lib/couchbase/protostellar/response_converter/kv.rb +++ b/lib/couchbase/protostellar/response_converter/kv.rb @@ -75,6 +75,33 @@ def self.to_lookup_in_result(resp, specs, options, request) end end + def self.to_get_any_replica_result(resps, options) + begin + entry = resps.next + rescue StopIteration + raise Couchbase::Error::DocumentIrretrievable, "unable to get replica of the document" + end + Couchbase::Collection::GetReplicaResult.new do |res| + res.transcoder = options.transcoder + res.cas = entry.cas + res.flags = entry.content_flags + res.encoded = entry.content + res.is_replica = entry.is_replica + end + end + + def self.to_get_all_replicas_result(resps, options) + resps.map do |entry| + Couchbase::Collection::GetReplicaResult.new do |res| + res.transcoder = options.transcoder + res.cas = entry.cas + res.flags = entry.content_flags + res.encoded = entry.content + res.is_replica = entry.is_replica + end + end + end + def self.to_mutate_in_result(resp, specs, options) Couchbase::Collection::MutateInResult.new do |res| res.cas = resp.cas diff --git a/test/crud_test.rb b/test/crud_test.rb index ab32986c..eeac78c5 100644 --- a/test/crud_test.rb +++ b/test/crud_test.rb @@ -52,8 +52,6 @@ def test_removes_documents end def test_reads_from_replica - skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support replica reads yet") if env.protostellar? - doc_id = uniq_id(:foo) document = {"value" => 42} options = @@ -78,6 +76,22 @@ def test_reads_from_replica end end + def test_reads_from_replica_does_not_exist + doc_id = uniq_id(:foo) + + assert_raises(Couchbase::Error::DocumentIrretrievable) do + @collection.get_any_replica(doc_id) + end + + if env.protostellar? + assert_empty @collection.get_all_replicas(doc_id) + else + assert_raises(Couchbase::Error::DocumentNotFound) do + @collection.get_all_replicas(doc_id) + end + end + end + def test_touch_sets_expiration document = {"value" => 42} doc_id = uniq_id(:foo)