couchbase 3.5.0-x86_64-darwin-20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +202 -0
  3. data/README.md +154 -0
  4. data/ext/extconf.rb +0 -0
  5. data/lib/active_support/cache/couchbase_store.rb +339 -0
  6. data/lib/couchbase/3.0/libcouchbase.bundle +0 -0
  7. data/lib/couchbase/3.1/libcouchbase.bundle +0 -0
  8. data/lib/couchbase/3.2/libcouchbase.bundle +0 -0
  9. data/lib/couchbase/3.3/libcouchbase.bundle +0 -0
  10. data/lib/couchbase/analytics_options.rb +107 -0
  11. data/lib/couchbase/authenticator.rb +64 -0
  12. data/lib/couchbase/binary_collection.rb +128 -0
  13. data/lib/couchbase/binary_collection_options.rb +24 -0
  14. data/lib/couchbase/bucket.rb +144 -0
  15. data/lib/couchbase/cluster.rb +460 -0
  16. data/lib/couchbase/cluster_registry.rb +49 -0
  17. data/lib/couchbase/collection.rb +705 -0
  18. data/lib/couchbase/collection_options.rb +399 -0
  19. data/lib/couchbase/config_profiles.rb +55 -0
  20. data/lib/couchbase/configuration.rb +56 -0
  21. data/lib/couchbase/datastructures/couchbase_list.rb +160 -0
  22. data/lib/couchbase/datastructures/couchbase_map.rb +194 -0
  23. data/lib/couchbase/datastructures/couchbase_queue.rb +134 -0
  24. data/lib/couchbase/datastructures/couchbase_set.rb +128 -0
  25. data/lib/couchbase/datastructures.rb +24 -0
  26. data/lib/couchbase/diagnostics.rb +181 -0
  27. data/lib/couchbase/errors.rb +376 -0
  28. data/lib/couchbase/json_transcoder.rb +39 -0
  29. data/lib/couchbase/key_value_scan.rb +117 -0
  30. data/lib/couchbase/libcouchbase.rb +6 -0
  31. data/lib/couchbase/logger.rb +85 -0
  32. data/lib/couchbase/management/analytics_index_manager.rb +1127 -0
  33. data/lib/couchbase/management/bucket_manager.rb +443 -0
  34. data/lib/couchbase/management/collection_manager.rb +470 -0
  35. data/lib/couchbase/management/collection_query_index_manager.rb +222 -0
  36. data/lib/couchbase/management/query_index_manager.rb +617 -0
  37. data/lib/couchbase/management/scope_search_index_manager.rb +198 -0
  38. data/lib/couchbase/management/search_index_manager.rb +424 -0
  39. data/lib/couchbase/management/user_manager.rb +468 -0
  40. data/lib/couchbase/management/view_index_manager.rb +237 -0
  41. data/lib/couchbase/management.rb +29 -0
  42. data/lib/couchbase/mutation_state.rb +63 -0
  43. data/lib/couchbase/options.rb +2837 -0
  44. data/lib/couchbase/protostellar/binary_collection.rb +55 -0
  45. data/lib/couchbase/protostellar/bucket.rb +51 -0
  46. data/lib/couchbase/protostellar/client.rb +99 -0
  47. data/lib/couchbase/protostellar/cluster.rb +163 -0
  48. data/lib/couchbase/protostellar/collection.rb +152 -0
  49. data/lib/couchbase/protostellar/connect_options.rb +63 -0
  50. data/lib/couchbase/protostellar/error_handling.rb +203 -0
  51. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_pb.rb +61 -0
  52. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_services_pb.rb +35 -0
  53. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_pb.rb +57 -0
  54. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_services_pb.rb +36 -0
  55. data/lib/couchbase/protostellar/generated/admin/query/v1/query_pb.rb +61 -0
  56. data/lib/couchbase/protostellar/generated/admin/query/v1/query_services_pb.rb +37 -0
  57. data/lib/couchbase/protostellar/generated/admin/search/v1/search_pb.rb +72 -0
  58. data/lib/couchbase/protostellar/generated/admin/search/v1/search_services_pb.rb +44 -0
  59. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_pb.rb +52 -0
  60. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_services_pb.rb +30 -0
  61. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_pb.rb +70 -0
  62. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_services_pb.rb +36 -0
  63. data/lib/couchbase/protostellar/generated/kv/v1/kv_pb.rb +97 -0
  64. data/lib/couchbase/protostellar/generated/kv/v1/kv_services_pb.rb +46 -0
  65. data/lib/couchbase/protostellar/generated/query/v1/query_pb.rb +57 -0
  66. data/lib/couchbase/protostellar/generated/query/v1/query_services_pb.rb +30 -0
  67. data/lib/couchbase/protostellar/generated/routing/v1/routing_pb.rb +52 -0
  68. data/lib/couchbase/protostellar/generated/routing/v1/routing_services_pb.rb +30 -0
  69. data/lib/couchbase/protostellar/generated/search/v1/search_pb.rb +99 -0
  70. data/lib/couchbase/protostellar/generated/search/v1/search_services_pb.rb +30 -0
  71. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_pb.rb +57 -0
  72. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_services_pb.rb +36 -0
  73. data/lib/couchbase/protostellar/generated/view/v1/view_pb.rb +51 -0
  74. data/lib/couchbase/protostellar/generated/view/v1/view_services_pb.rb +30 -0
  75. data/lib/couchbase/protostellar/generated.rb +9 -0
  76. data/lib/couchbase/protostellar/management/bucket_manager.rb +67 -0
  77. data/lib/couchbase/protostellar/management/collection_manager.rb +94 -0
  78. data/lib/couchbase/protostellar/management/collection_query_index_manager.rb +124 -0
  79. data/lib/couchbase/protostellar/management/query_index_manager.rb +112 -0
  80. data/lib/couchbase/protostellar/management.rb +24 -0
  81. data/lib/couchbase/protostellar/request.rb +78 -0
  82. data/lib/couchbase/protostellar/request_behaviour.rb +42 -0
  83. data/lib/couchbase/protostellar/request_generator/admin/bucket.rb +124 -0
  84. data/lib/couchbase/protostellar/request_generator/admin/collection.rb +94 -0
  85. data/lib/couchbase/protostellar/request_generator/admin/query.rb +130 -0
  86. data/lib/couchbase/protostellar/request_generator/admin.rb +24 -0
  87. data/lib/couchbase/protostellar/request_generator/kv.rb +474 -0
  88. data/lib/couchbase/protostellar/request_generator/query.rb +133 -0
  89. data/lib/couchbase/protostellar/request_generator/search.rb +387 -0
  90. data/lib/couchbase/protostellar/request_generator.rb +26 -0
  91. data/lib/couchbase/protostellar/response_converter/admin/bucket.rb +55 -0
  92. data/lib/couchbase/protostellar/response_converter/admin/collection.rb +42 -0
  93. data/lib/couchbase/protostellar/response_converter/admin/query.rb +59 -0
  94. data/lib/couchbase/protostellar/response_converter/admin.rb +24 -0
  95. data/lib/couchbase/protostellar/response_converter/kv.rb +151 -0
  96. data/lib/couchbase/protostellar/response_converter/query.rb +84 -0
  97. data/lib/couchbase/protostellar/response_converter/search.rb +136 -0
  98. data/lib/couchbase/protostellar/response_converter.rb +26 -0
  99. data/lib/couchbase/protostellar/retry/action.rb +38 -0
  100. data/lib/couchbase/protostellar/retry/orchestrator.rb +60 -0
  101. data/lib/couchbase/protostellar/retry/reason.rb +67 -0
  102. data/lib/couchbase/protostellar/retry/strategies/best_effort.rb +49 -0
  103. data/lib/couchbase/protostellar/retry/strategies.rb +26 -0
  104. data/lib/couchbase/protostellar/retry.rb +28 -0
  105. data/lib/couchbase/protostellar/scope.rb +57 -0
  106. data/lib/couchbase/protostellar/timeout_defaults.rb +30 -0
  107. data/lib/couchbase/protostellar/timeouts.rb +83 -0
  108. data/lib/couchbase/protostellar.rb +29 -0
  109. data/lib/couchbase/query_options.rb +120 -0
  110. data/lib/couchbase/railtie.rb +45 -0
  111. data/lib/couchbase/raw_binary_transcoder.rb +37 -0
  112. data/lib/couchbase/raw_json_transcoder.rb +38 -0
  113. data/lib/couchbase/raw_string_transcoder.rb +40 -0
  114. data/lib/couchbase/scope.rb +256 -0
  115. data/lib/couchbase/search_options.rb +1622 -0
  116. data/lib/couchbase/subdoc.rb +290 -0
  117. data/lib/couchbase/transcoder_flags.rb +62 -0
  118. data/lib/couchbase/utils/generic_logger_adapter.rb +38 -0
  119. data/lib/couchbase/utils/stdlib_logger_adapter.rb +65 -0
  120. data/lib/couchbase/utils/time.rb +69 -0
  121. data/lib/couchbase/utils.rb +21 -0
  122. data/lib/couchbase/version.rb +23 -0
  123. data/lib/couchbase/view_options.rb +65 -0
  124. data/lib/couchbase.rb +28 -0
  125. data/lib/rails/generators/couchbase/config/config_generator.rb +27 -0
  126. 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