couchbase 3.5.0-arm64-darwin-23
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +202 -0
- data/README.md +154 -0
- data/ext/extconf.rb +0 -0
- data/lib/active_support/cache/couchbase_store.rb +339 -0
- data/lib/couchbase/3.0/libcouchbase.bundle +0 -0
- data/lib/couchbase/3.1/libcouchbase.bundle +0 -0
- data/lib/couchbase/3.2/libcouchbase.bundle +0 -0
- data/lib/couchbase/3.3/libcouchbase.bundle +0 -0
- data/lib/couchbase/analytics_options.rb +107 -0
- data/lib/couchbase/authenticator.rb +64 -0
- data/lib/couchbase/binary_collection.rb +128 -0
- data/lib/couchbase/binary_collection_options.rb +24 -0
- data/lib/couchbase/bucket.rb +144 -0
- data/lib/couchbase/cluster.rb +460 -0
- data/lib/couchbase/cluster_registry.rb +49 -0
- data/lib/couchbase/collection.rb +705 -0
- data/lib/couchbase/collection_options.rb +399 -0
- data/lib/couchbase/config_profiles.rb +55 -0
- data/lib/couchbase/configuration.rb +56 -0
- data/lib/couchbase/datastructures/couchbase_list.rb +160 -0
- data/lib/couchbase/datastructures/couchbase_map.rb +194 -0
- data/lib/couchbase/datastructures/couchbase_queue.rb +134 -0
- data/lib/couchbase/datastructures/couchbase_set.rb +128 -0
- data/lib/couchbase/datastructures.rb +24 -0
- data/lib/couchbase/diagnostics.rb +181 -0
- data/lib/couchbase/errors.rb +376 -0
- data/lib/couchbase/json_transcoder.rb +39 -0
- data/lib/couchbase/key_value_scan.rb +117 -0
- data/lib/couchbase/libcouchbase.rb +6 -0
- data/lib/couchbase/logger.rb +85 -0
- data/lib/couchbase/management/analytics_index_manager.rb +1127 -0
- data/lib/couchbase/management/bucket_manager.rb +443 -0
- data/lib/couchbase/management/collection_manager.rb +470 -0
- data/lib/couchbase/management/collection_query_index_manager.rb +222 -0
- data/lib/couchbase/management/query_index_manager.rb +617 -0
- data/lib/couchbase/management/scope_search_index_manager.rb +198 -0
- data/lib/couchbase/management/search_index_manager.rb +424 -0
- data/lib/couchbase/management/user_manager.rb +468 -0
- data/lib/couchbase/management/view_index_manager.rb +237 -0
- data/lib/couchbase/management.rb +29 -0
- data/lib/couchbase/mutation_state.rb +63 -0
- data/lib/couchbase/options.rb +2837 -0
- data/lib/couchbase/protostellar/binary_collection.rb +55 -0
- data/lib/couchbase/protostellar/bucket.rb +51 -0
- data/lib/couchbase/protostellar/client.rb +99 -0
- data/lib/couchbase/protostellar/cluster.rb +163 -0
- data/lib/couchbase/protostellar/collection.rb +152 -0
- data/lib/couchbase/protostellar/connect_options.rb +63 -0
- data/lib/couchbase/protostellar/error_handling.rb +203 -0
- data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_pb.rb +61 -0
- data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_services_pb.rb +35 -0
- data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_pb.rb +57 -0
- data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_services_pb.rb +36 -0
- data/lib/couchbase/protostellar/generated/admin/query/v1/query_pb.rb +61 -0
- data/lib/couchbase/protostellar/generated/admin/query/v1/query_services_pb.rb +37 -0
- data/lib/couchbase/protostellar/generated/admin/search/v1/search_pb.rb +72 -0
- data/lib/couchbase/protostellar/generated/admin/search/v1/search_services_pb.rb +44 -0
- data/lib/couchbase/protostellar/generated/analytics/v1/analytics_pb.rb +52 -0
- data/lib/couchbase/protostellar/generated/analytics/v1/analytics_services_pb.rb +30 -0
- data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_pb.rb +70 -0
- data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_services_pb.rb +36 -0
- data/lib/couchbase/protostellar/generated/kv/v1/kv_pb.rb +97 -0
- data/lib/couchbase/protostellar/generated/kv/v1/kv_services_pb.rb +46 -0
- data/lib/couchbase/protostellar/generated/query/v1/query_pb.rb +57 -0
- data/lib/couchbase/protostellar/generated/query/v1/query_services_pb.rb +30 -0
- data/lib/couchbase/protostellar/generated/routing/v1/routing_pb.rb +52 -0
- data/lib/couchbase/protostellar/generated/routing/v1/routing_services_pb.rb +30 -0
- data/lib/couchbase/protostellar/generated/search/v1/search_pb.rb +99 -0
- data/lib/couchbase/protostellar/generated/search/v1/search_services_pb.rb +30 -0
- data/lib/couchbase/protostellar/generated/transactions/v1/transactions_pb.rb +57 -0
- data/lib/couchbase/protostellar/generated/transactions/v1/transactions_services_pb.rb +36 -0
- data/lib/couchbase/protostellar/generated/view/v1/view_pb.rb +51 -0
- data/lib/couchbase/protostellar/generated/view/v1/view_services_pb.rb +30 -0
- data/lib/couchbase/protostellar/generated.rb +9 -0
- data/lib/couchbase/protostellar/management/bucket_manager.rb +67 -0
- data/lib/couchbase/protostellar/management/collection_manager.rb +94 -0
- data/lib/couchbase/protostellar/management/collection_query_index_manager.rb +124 -0
- data/lib/couchbase/protostellar/management/query_index_manager.rb +112 -0
- data/lib/couchbase/protostellar/management.rb +24 -0
- data/lib/couchbase/protostellar/request.rb +78 -0
- data/lib/couchbase/protostellar/request_behaviour.rb +42 -0
- data/lib/couchbase/protostellar/request_generator/admin/bucket.rb +124 -0
- data/lib/couchbase/protostellar/request_generator/admin/collection.rb +94 -0
- data/lib/couchbase/protostellar/request_generator/admin/query.rb +130 -0
- data/lib/couchbase/protostellar/request_generator/admin.rb +24 -0
- data/lib/couchbase/protostellar/request_generator/kv.rb +474 -0
- data/lib/couchbase/protostellar/request_generator/query.rb +133 -0
- data/lib/couchbase/protostellar/request_generator/search.rb +387 -0
- data/lib/couchbase/protostellar/request_generator.rb +26 -0
- data/lib/couchbase/protostellar/response_converter/admin/bucket.rb +55 -0
- data/lib/couchbase/protostellar/response_converter/admin/collection.rb +42 -0
- data/lib/couchbase/protostellar/response_converter/admin/query.rb +59 -0
- data/lib/couchbase/protostellar/response_converter/admin.rb +24 -0
- data/lib/couchbase/protostellar/response_converter/kv.rb +151 -0
- data/lib/couchbase/protostellar/response_converter/query.rb +84 -0
- data/lib/couchbase/protostellar/response_converter/search.rb +136 -0
- data/lib/couchbase/protostellar/response_converter.rb +26 -0
- data/lib/couchbase/protostellar/retry/action.rb +38 -0
- data/lib/couchbase/protostellar/retry/orchestrator.rb +60 -0
- data/lib/couchbase/protostellar/retry/reason.rb +67 -0
- data/lib/couchbase/protostellar/retry/strategies/best_effort.rb +49 -0
- data/lib/couchbase/protostellar/retry/strategies.rb +26 -0
- data/lib/couchbase/protostellar/retry.rb +28 -0
- data/lib/couchbase/protostellar/scope.rb +57 -0
- data/lib/couchbase/protostellar/timeout_defaults.rb +30 -0
- data/lib/couchbase/protostellar/timeouts.rb +83 -0
- data/lib/couchbase/protostellar.rb +29 -0
- data/lib/couchbase/query_options.rb +120 -0
- data/lib/couchbase/railtie.rb +45 -0
- data/lib/couchbase/raw_binary_transcoder.rb +37 -0
- data/lib/couchbase/raw_json_transcoder.rb +38 -0
- data/lib/couchbase/raw_string_transcoder.rb +40 -0
- data/lib/couchbase/scope.rb +256 -0
- data/lib/couchbase/search_options.rb +1622 -0
- data/lib/couchbase/subdoc.rb +290 -0
- data/lib/couchbase/transcoder_flags.rb +62 -0
- data/lib/couchbase/utils/generic_logger_adapter.rb +38 -0
- data/lib/couchbase/utils/stdlib_logger_adapter.rb +65 -0
- data/lib/couchbase/utils/time.rb +69 -0
- data/lib/couchbase/utils.rb +21 -0
- data/lib/couchbase/version.rb +23 -0
- data/lib/couchbase/view_options.rb +65 -0
- data/lib/couchbase.rb +28 -0
- data/lib/rails/generators/couchbase/config/config_generator.rb +27 -0
- metadata +191 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright 2023. Couchbase, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# frozen_string_literal: true
|
16
|
+
|
17
|
+
require "couchbase/management/query_index_manager"
|
18
|
+
|
19
|
+
module Couchbase
|
20
|
+
module Protostellar
|
21
|
+
module ResponseConverter
|
22
|
+
module Admin
|
23
|
+
class Query
|
24
|
+
INDEX_TYPE_MAP = {
|
25
|
+
:INDEX_TYPE_VIEW => :view,
|
26
|
+
:INDEX_TYPE_GSI => :gsi,
|
27
|
+
}.freeze
|
28
|
+
|
29
|
+
INDEX_STATE_MAP = {
|
30
|
+
:INDEX_STATE_DEFERRED => :deferred,
|
31
|
+
:INDEX_STATE_BUILDING => :building,
|
32
|
+
:INDEX_STATE_PENDING => :pending,
|
33
|
+
:INDEX_STATE_ONLINE => :online,
|
34
|
+
:INDEX_STATE_OFFLINE => :offline,
|
35
|
+
:INDEX_STATE_ABRIDGED => :abridged,
|
36
|
+
:INDEX_STATE_SCHEDULED => :scheduled,
|
37
|
+
}.freeze
|
38
|
+
|
39
|
+
def self.to_query_index_array(resp)
|
40
|
+
resp.indexes.map do |proto_idx|
|
41
|
+
Couchbase::Management::QueryIndex.new do |idx|
|
42
|
+
idx.bucket = proto_idx.bucket_name
|
43
|
+
idx.scope = proto_idx.scope_name
|
44
|
+
idx.collection = proto_idx.collection_name
|
45
|
+
idx.name = proto_idx.name
|
46
|
+
idx.is_primary = proto_idx.is_primary
|
47
|
+
idx.type = INDEX_TYPE_MAP[proto_idx.type]
|
48
|
+
idx.state = INDEX_STATE_MAP[proto_idx.state]
|
49
|
+
idx.index_key = proto_idx.fields.to_a
|
50
|
+
idx.condition = proto_idx.condition if proto_idx.has_condition?
|
51
|
+
idx.partition = proto_idx.partition if proto_idx.has_partition?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright 2023. Couchbase, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# frozen_string_literal: true
|
16
|
+
|
17
|
+
module Couchbase
|
18
|
+
module Protostellar
|
19
|
+
module ResponseConverter
|
20
|
+
module Admin
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# Copyright 2023. Couchbase, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# frozen_string_literal: true
|
16
|
+
|
17
|
+
require "couchbase/collection_options"
|
18
|
+
require "couchbase/binary_collection_options"
|
19
|
+
|
20
|
+
module Couchbase
|
21
|
+
module Protostellar
|
22
|
+
module ResponseConverter
|
23
|
+
class KV
|
24
|
+
def self.to_get_result(resp, options)
|
25
|
+
Couchbase::Collection::GetResult.new do |res|
|
26
|
+
res.transcoder = options.transcoder
|
27
|
+
res.cas = resp.cas
|
28
|
+
res.expiry = extract_expiry_time(resp) if options.respond_to?(:with_expiry) && options.with_expiry
|
29
|
+
res.encoded = if resp.content_uncompressed == "null" && !options.projections.empty?
|
30
|
+
"{}"
|
31
|
+
else
|
32
|
+
resp.content_uncompressed
|
33
|
+
end
|
34
|
+
res.flags = resp.content_flags
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.to_mutation_result(resp)
|
39
|
+
Couchbase::Collection::MutationResult.new do |res|
|
40
|
+
res.cas = resp.cas
|
41
|
+
res.mutation_token = extract_mutation_token(resp)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.to_exists_result(resp)
|
46
|
+
Couchbase::Collection::ExistsResult.new do |res|
|
47
|
+
res.cas = resp.cas
|
48
|
+
res.exists = resp.result
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.to_lookup_in_result(resp, specs, options, request)
|
53
|
+
Couchbase::Collection::LookupInResult.new do |res|
|
54
|
+
res.cas = resp.cas
|
55
|
+
res.transcoder = options.transcoder
|
56
|
+
res.encoded = resp.specs.each_with_index.map do |s, idx|
|
57
|
+
Couchbase::Collection::SubDocumentField.new do |f|
|
58
|
+
# TODO: What to do with the status?
|
59
|
+
error = s.status.nil? ? nil : ErrorHandling.convert_rpc_status(s.status, request)
|
60
|
+
f.error = error unless error.nil?
|
61
|
+
f.index = idx
|
62
|
+
f.path = specs[idx].path
|
63
|
+
if specs[idx].type == :exists
|
64
|
+
f.exists = s.content == "true"
|
65
|
+
f.value = s.content
|
66
|
+
elsif s.content.empty?
|
67
|
+
f.value = nil
|
68
|
+
f.exists = false
|
69
|
+
else
|
70
|
+
f.value = s.content
|
71
|
+
f.exists = true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.to_get_any_replica_result(resps, options)
|
79
|
+
begin
|
80
|
+
entry = resps.next
|
81
|
+
rescue StopIteration
|
82
|
+
raise Couchbase::Error::DocumentIrretrievable, "unable to get replica of the document"
|
83
|
+
end
|
84
|
+
Couchbase::Collection::GetReplicaResult.new do |res|
|
85
|
+
res.transcoder = options.transcoder
|
86
|
+
res.cas = entry.cas
|
87
|
+
res.flags = entry.content_flags
|
88
|
+
res.encoded = entry.content
|
89
|
+
res.is_replica = entry.is_replica
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.to_get_all_replicas_result(resps, options)
|
94
|
+
resps.map do |entry|
|
95
|
+
Couchbase::Collection::GetReplicaResult.new do |res|
|
96
|
+
res.transcoder = options.transcoder
|
97
|
+
res.cas = entry.cas
|
98
|
+
res.flags = entry.content_flags
|
99
|
+
res.encoded = entry.content
|
100
|
+
res.is_replica = entry.is_replica
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.to_mutate_in_result(resp, specs, options)
|
106
|
+
Couchbase::Collection::MutateInResult.new do |res|
|
107
|
+
res.cas = resp.cas
|
108
|
+
res.transcoder = options.transcoder
|
109
|
+
res.deleted = nil # TODO: gRPC response has no deleted field
|
110
|
+
res.mutation_token = extract_mutation_token(resp)
|
111
|
+
res.encoded = resp.specs.each_with_index.map do |s, idx|
|
112
|
+
Couchbase::Collection::SubDocumentField.new do |f|
|
113
|
+
f.index = idx
|
114
|
+
f.path = specs[idx].path
|
115
|
+
f.value = s.content
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.to_counter_result(resp)
|
122
|
+
Couchbase::BinaryCollection::CounterResult.new do |res|
|
123
|
+
res.cas = resp.cas
|
124
|
+
res.content = resp.content
|
125
|
+
res.mutation_token = extract_mutation_token(resp)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.extract_mutation_token(resp)
|
130
|
+
proto_token = resp.mutation_token
|
131
|
+
return nil if proto_token.nil?
|
132
|
+
|
133
|
+
Couchbase::MutationToken.new do |token|
|
134
|
+
token.bucket_name = proto_token.bucket_name
|
135
|
+
token.partition_id = proto_token.vbucket_id
|
136
|
+
token.partition_uuid = proto_token.vbucket_uuid
|
137
|
+
token.sequence_number = proto_token.seq_no
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.extract_expiry_time(resp)
|
142
|
+
timestamp = resp.expiry
|
143
|
+
|
144
|
+
return nil if timestamp.nil?
|
145
|
+
|
146
|
+
Time.at(timestamp.seconds, timestamp.nanos, :nsec)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Copyright 2023. Couchbase, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# frozen_string_literal: true
|
16
|
+
|
17
|
+
require "json"
|
18
|
+
|
19
|
+
require "couchbase/query_options"
|
20
|
+
|
21
|
+
module Couchbase
|
22
|
+
module Protostellar
|
23
|
+
module ResponseConverter
|
24
|
+
class Query
|
25
|
+
STATUS_MAP = {
|
26
|
+
:STATUS_RUNNING => :running,
|
27
|
+
:STATUS_SUCCESS => :success,
|
28
|
+
:STATUS_ERRORS => :errors,
|
29
|
+
:STATUS_COMPLETED => :completed,
|
30
|
+
:STATUS_STOPPED => :stopped,
|
31
|
+
:STATUS_TIMEOUT => :timeout,
|
32
|
+
:STATUS_CLOSED => :closed,
|
33
|
+
:STATUS_FATAL => :fatal,
|
34
|
+
:STATUS_ABORTED => :aborted,
|
35
|
+
:STATUS_UNKNOWN => :unknown,
|
36
|
+
}.freeze
|
37
|
+
|
38
|
+
def self.to_query_result(resps)
|
39
|
+
Couchbase::Cluster::QueryResult.new do |res|
|
40
|
+
rows = []
|
41
|
+
resps.each do |resp|
|
42
|
+
rows.push(*resp.rows)
|
43
|
+
res.meta_data = convert_query_metadata(resp.meta_data) unless resp.meta_data.nil?
|
44
|
+
end
|
45
|
+
res.instance_variable_set(:@rows, rows)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.convert_query_metadata(proto_metadata)
|
50
|
+
Couchbase::Cluster::QueryMetaData.new do |meta|
|
51
|
+
meta.status = STATUS_MAP[proto_metadata.status]
|
52
|
+
meta.request_id = proto_metadata.request_id
|
53
|
+
meta.client_context_id = proto_metadata.client_context_id
|
54
|
+
meta.signature = JSON.parse(proto_metadata.signature) unless proto_metadata.signature.nil? || proto_metadata.signature.empty?
|
55
|
+
meta.profile = JSON.parse(proto_metadata.profile) unless proto_metadata.profile.nil? || proto_metadata.profile.empty?
|
56
|
+
meta.metrics = if proto_metadata.has_metrics?
|
57
|
+
convert_query_metrics(proto_metadata.metrics)
|
58
|
+
else
|
59
|
+
Couchbase::Cluster::QueryMetrics.new
|
60
|
+
end
|
61
|
+
meta.warnings = proto_metadata.warnings.map { |w| convert_query_warning(w) } unless proto_metadata.warnings.empty?
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.convert_query_warning(proto_warning)
|
66
|
+
Couchbase::Cluster::QueryWarning.new(proto_warning.code, proto_warning.message)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.convert_query_metrics(proto_metrics)
|
70
|
+
Couchbase::Cluster::QueryMetrics.new do |metrics|
|
71
|
+
metrics.elapsed_time = proto_metrics.elapsed_time.nanos + (proto_metrics.elapsed_time.seconds * (10**9))
|
72
|
+
metrics.execution_time = proto_metrics.execution_time.nanos + (proto_metrics.execution_time.seconds * (10**9))
|
73
|
+
metrics.result_count = proto_metrics.result_count
|
74
|
+
metrics.result_size = proto_metrics.result_size
|
75
|
+
metrics.mutation_count = proto_metrics.mutation_count
|
76
|
+
metrics.sort_count = proto_metrics.sort_count
|
77
|
+
metrics.error_count = proto_metrics.error_count
|
78
|
+
metrics.warning_count = proto_metrics.warning_count
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# Copyright 2023. Couchbase, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# frozen_string_literal: true
|
16
|
+
|
17
|
+
require "couchbase/search_options"
|
18
|
+
|
19
|
+
module Couchbase
|
20
|
+
module Protostellar
|
21
|
+
module ResponseConverter
|
22
|
+
class Search
|
23
|
+
def self.to_search_result(resps, options)
|
24
|
+
Couchbase::Cluster::SearchResult.new do |res|
|
25
|
+
res.rows = []
|
26
|
+
res.facets = {}
|
27
|
+
resps.each do |resp|
|
28
|
+
resp.hits.each do |hit|
|
29
|
+
res.rows.append(convert_search_row(hit, options))
|
30
|
+
end
|
31
|
+
resp.facets.each do |k, facet_res|
|
32
|
+
res.facets[k] = convert_facet_result(facet_res)
|
33
|
+
end
|
34
|
+
res.meta_data = convert_meta_data(resp.meta_data) if resp.has_meta_data?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.convert_search_row(proto_row, options)
|
40
|
+
Couchbase::Cluster::SearchRow.new do |r|
|
41
|
+
r.instance_variable_set(:@fields, (proto_row.fields.to_h.transform_values { |v| JSON.parse(v) }).to_json)
|
42
|
+
r.transcoder = options.transcoder
|
43
|
+
r.index = proto_row.index
|
44
|
+
r.id = proto_row.id
|
45
|
+
r.score = proto_row.score.to_f
|
46
|
+
unless proto_row.locations.empty?
|
47
|
+
r.locations = Couchbase::Cluster::SearchRowLocations.new(
|
48
|
+
proto_row.locations.map { |loc| convert_search_row_location(loc) }
|
49
|
+
)
|
50
|
+
end
|
51
|
+
r.fragments = convert_fragments(proto_row.fragments)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.convert_fragments(proto_fragments)
|
56
|
+
proto_fragments.to_h.transform_values { |f| f.content.to_a }
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.convert_search_row_location(proto_location)
|
60
|
+
Couchbase::Cluster::SearchRowLocation.new do |loc|
|
61
|
+
loc.field = proto_location.field
|
62
|
+
loc.term = proto_location.term
|
63
|
+
loc.position = proto_location.position
|
64
|
+
loc.start_offset = proto_location.start
|
65
|
+
loc.end_offset = proto_location.end
|
66
|
+
loc.array_positions = proto_location.array_positions.to_a
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.convert_facet_result(proto_facet_res)
|
71
|
+
facet_type = proto_facet_res.search_facet
|
72
|
+
case facet_type
|
73
|
+
when :term_facet
|
74
|
+
res = proto_facet_res.term_facet
|
75
|
+
Couchbase::Cluster::SearchFacetResult::TermFacetResult.new do |f|
|
76
|
+
f.name = res.name
|
77
|
+
f.field = res.field
|
78
|
+
f.total = res.total
|
79
|
+
f.missing = res.missing
|
80
|
+
f.other = res.other
|
81
|
+
f.terms = res.terms.map do |term_res|
|
82
|
+
Couchbase::Cluster::SearchFacetResult::TermFacetResult::TermFacet.new(term_res.name, term_res.size)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
when :date_range_facet
|
86
|
+
res = proto_facet_res.date_range_facet
|
87
|
+
Couchbase::Cluster::SearchFacetResult::DateRangeFacetResult.new do |f|
|
88
|
+
f.name = res.name
|
89
|
+
f.field = res.field
|
90
|
+
f.total = res.total
|
91
|
+
f.missing = res.missing
|
92
|
+
f.other = res.other
|
93
|
+
f.date_ranges = res.date_ranges.map do |date_range|
|
94
|
+
start_time = Time.at(date_range.start.seconds).strftime("%Y-%m-%d")
|
95
|
+
end_time = Time.at(date_range.end.seconds).strftime("%Y-%m-%d")
|
96
|
+
Couchbase::Cluster::SearchFacetResult::DateRangeFacetResult::DateRangeFacet.new(
|
97
|
+
date_range.name, date_range.size, start_time, end_time
|
98
|
+
)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
when :numeric_range_facet
|
102
|
+
res = proto_facet_res.numeric_range_facet
|
103
|
+
Couchbase::Cluster::SearchFacetResult::NumericRangeFacetResult.new do |f|
|
104
|
+
f.name = res.name
|
105
|
+
f.field = res.field
|
106
|
+
f.total = res.total
|
107
|
+
f.missing = res.missing
|
108
|
+
f.other = res.other
|
109
|
+
f.numeric_ranges = res.numeric_ranges.map do |numeric_range|
|
110
|
+
Couchbase::Cluster::NumericRangeResult::NumericRangeFacetResult::NumericRangeFacet.new(
|
111
|
+
numeric_range.name, numeric_range.size, numeric_range.min, numeric_range.max
|
112
|
+
)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
else
|
116
|
+
raise ProtostellarError, "Unrecognised facet type"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.convert_meta_data(proto_meta_data)
|
121
|
+
Couchbase::Cluster::SearchMetaData.new do |meta|
|
122
|
+
proto_metrics = proto_meta_data.metrics
|
123
|
+
dur = proto_metrics.execution_time
|
124
|
+
meta.metrics.took = (dur.seconds * 1000) + (dur.nanos / 1000.0).round # `took` is in milliseconds
|
125
|
+
meta.metrics.total_rows = proto_metrics.total_rows
|
126
|
+
meta.metrics.max_score = proto_metrics.max_score
|
127
|
+
meta.metrics.success_partition_count = proto_metrics.success_partition_count
|
128
|
+
meta.metrics.error_partition_count = proto_metrics.error_partition_count
|
129
|
+
|
130
|
+
meta.errors = proto_meta_data.errors.to_h
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Copyright 2023. Couchbase, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# frozen_string_literal: true
|
16
|
+
|
17
|
+
require_relative "response_converter/kv"
|
18
|
+
require_relative "response_converter/query"
|
19
|
+
|
20
|
+
module Couchbase
|
21
|
+
module Protostellar
|
22
|
+
# @api private
|
23
|
+
module ResponseConverter
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Copyright 2023. Couchbase, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# frozen_string_literal: true
|
16
|
+
|
17
|
+
module Couchbase
|
18
|
+
module Protostellar
|
19
|
+
module Retry
|
20
|
+
# @api private
|
21
|
+
class Action
|
22
|
+
attr_reader :duration
|
23
|
+
|
24
|
+
def initialize(duration)
|
25
|
+
@duration = duration
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.with_duration(duration)
|
29
|
+
Action.new(duration)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.no_retry
|
33
|
+
Action.new(nil)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Copyright 2023. Couchbase, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# frozen_string_literal: true
|
16
|
+
|
17
|
+
require_relative '../request_behaviour'
|
18
|
+
require_relative 'action'
|
19
|
+
require 'couchbase/errors'
|
20
|
+
require 'couchbase/logger'
|
21
|
+
|
22
|
+
module Couchbase
|
23
|
+
module Protostellar
|
24
|
+
module Retry
|
25
|
+
# @api private
|
26
|
+
class Orchestrator
|
27
|
+
def self.maybe_retry(request, reason)
|
28
|
+
if reason.always_retry
|
29
|
+
retry_duration = get_controlled_backoff(request)
|
30
|
+
request.add_retry_attempt(reason)
|
31
|
+
# TODO: Log retry
|
32
|
+
RequestBehaviour.retry(retry_duration)
|
33
|
+
else
|
34
|
+
retry_action = request.retry_strategy.retry_after(request, reason)
|
35
|
+
duration = retry_action.duration
|
36
|
+
if duration.nil?
|
37
|
+
# TODO: Log not retried
|
38
|
+
RequestBehaviour.fail(Couchbase::Error::RequestCanceled.new('Cannot retry request', request.error_context))
|
39
|
+
else
|
40
|
+
request.add_retry_attempt(reason)
|
41
|
+
# TODO: Log retry
|
42
|
+
RequestBehaviour.retry(duration)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.get_controlled_backoff(request)
|
48
|
+
case request.retry_attempts
|
49
|
+
when 0 then 1
|
50
|
+
when 1 then 10
|
51
|
+
when 2 then 50
|
52
|
+
when 3 then 100
|
53
|
+
when 4 then 500
|
54
|
+
else 1000
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Copyright 2023. Couchbase, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# frozen_string_literal: true
|
16
|
+
|
17
|
+
module Couchbase
|
18
|
+
module Protostellar
|
19
|
+
module Retry
|
20
|
+
class Reason
|
21
|
+
attr_reader :allows_non_idempotent_retry
|
22
|
+
attr_reader :always_retry
|
23
|
+
attr_reader :name
|
24
|
+
|
25
|
+
def self.reason(name, allows_non_idempotent_retry:, always_retry:)
|
26
|
+
const_set(
|
27
|
+
name,
|
28
|
+
new(name: name,
|
29
|
+
allows_non_idempotent_retry: allows_non_idempotent_retry,
|
30
|
+
always_retry: always_retry).freeze
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(name:, allows_non_idempotent_retry:, always_retry:)
|
35
|
+
@name = name
|
36
|
+
@allows_non_idempotent_retry = allows_non_idempotent_retry
|
37
|
+
@always_retry = always_retry
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
@name.downcase.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
reason :UNKNOWN, allows_non_idempotent_retry: false, always_retry: false
|
45
|
+
reason :SOCKET_NOT_AVAILABLE, allows_non_idempotent_retry: true, always_retry: false
|
46
|
+
reason :SERVICE_NOT_AVAILABLE, allows_non_idempotent_retry: true, always_retry: false
|
47
|
+
reason :NODE_NOT_AVAILABLE, allows_non_idempotent_retry: true, always_retry: false
|
48
|
+
reason :KV_NOT_MY_VBUCKET, allows_non_idempotent_retry: true, always_retry: true
|
49
|
+
reason :KV_COLLECTION_OUTDATED, allows_non_idempotent_retry: true, always_retry: true
|
50
|
+
reason :KV_ERROR_MAP_RETRY_INDICATED, allows_non_idempotent_retry: true, always_retry: false
|
51
|
+
reason :KV_LOCKED, allows_non_idempotent_retry: true, always_retry: false
|
52
|
+
reason :KV_TEMPORARY_FAILURE, allows_non_idempotent_retry: true, always_retry: false
|
53
|
+
reason :KV_SYNC_WRITE_IN_PROGRESS, allows_non_idempotent_retry: true, always_retry: false
|
54
|
+
reason :KV_SYNC_WRITE_RE_COMMIT_IN_PROGRESS, allows_non_idempotent_retry: true, always_retry: false
|
55
|
+
reason :SERVICE_RESPONSE_CODE_INDICATED, allows_non_idempotent_retry: true, always_retry: false
|
56
|
+
reason :SOCKET_CLOSED_WHILE_IN_FLIGHT, allows_non_idempotent_retry: false, always_retry: false
|
57
|
+
reason :CIRCUIT_BREAKER_OPEN, allows_non_idempotent_retry: true, always_retry: false
|
58
|
+
reason :QUERY_PREPARED_STATEMENT_FAILURE, allows_non_idempotent_retry: true, always_retry: false
|
59
|
+
reason :QUERY_INDEX_NOT_FOUND, allows_non_idempotent_retry: true, always_retry: false
|
60
|
+
reason :ANALYTICS_TEMPORARY_FAILURE, allows_non_idempotent_retry: true, always_retry: false
|
61
|
+
reason :SEARCH_TOO_MANY_REQUESTS, allows_non_idempotent_retry: true, always_retry: false
|
62
|
+
reason :VIEWS_TEMPORARY_FAILURE, allows_non_idempotent_retry: true, always_retry: false
|
63
|
+
reason :VIEWS_NO_ACTIVE_PARTITION, allows_non_idempotent_retry: true, always_retry: true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|