aerospike 2.25.0 → 2.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12a4c3d56df63146053710f4438b8030672d76d9fa01cf4ddf5453429d275e11
4
- data.tar.gz: '025678955679feb936123140c4bce14117a85ac954eb0e3d294960269cfa9b92'
3
+ metadata.gz: 569388197af73988d3965e15f8b7caf42605896f21183a0e6f7d507690dec816
4
+ data.tar.gz: dfe35172403817d176aecfd83747e6155a961b92960a97f8efc713a6b7540d23
5
5
  SHA512:
6
- metadata.gz: 2e5d828c912aaa9a189de8c7d1441bb255b4ae73a6075d262b75b3cb10f8315b4afc2d5853cf015cfd829f9fd4cbc14014bd007a76f2e2de2426aad6e489ae62
7
- data.tar.gz: 53d8e293b39e14b99ce747c06f125b2cdc695c7654ea7d21cbce927e2f8f1064eab0ab2f0b585308353a36a8f345eeafb4c21854b0184ebe652a32a83afddf19
6
+ metadata.gz: e4de68155586c168c75a51c71749531becdf066cb22888745f8473237cb775dd9054c6401e44a04b00bee517848859d128141692da3fc7c970df2f202e5e49b9
7
+ data.tar.gz: 7c041a196f2bf45a3ff575426b9269ba45c10e16f641c82f5ce11e362ace013d2480c407b8f1e9a663a27bcf78df1988d6af46de2bd22d41c0fce5366fb2a52c
data/CHANGELOG.md CHANGED
@@ -2,10 +2,19 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.26.0] 2022-12-02
6
+
7
+ - **New Features**
8
+ - [CLIENT-1808] Support creating a secondary index on elements within a CDT using `Context`.
9
+ - [CLIENT-1991] Add base64 encoding methods to `Context`.
10
+ - [CLIENT-2007] Support using `Context` in query filters.
11
+
5
12
  ## [2.25.0] 2022-11-28
6
13
 
7
14
  - **New Features**
8
15
 
16
+ - [CLIENT-1984] Support scan-show and query-show info commands.
17
+
9
18
  - [CLIENT-1362] Adds support Aerospike Expression filters. Expression filters are now supported on all commands, including `Client#get`, `Client#put`, `Client#delete`, `Client#operate`, `Client#scan`, `Client#query`, `Client#execute_udf`, etc.
10
19
 
11
20
  - Adds `Policy#filter_exp` and `Policy#fail_on_filtered_out`
@@ -17,16 +17,17 @@
17
17
  # License for the specific language governing permissions and limitations under
18
18
  # the License.
19
19
 
20
+ require "base64"
21
+
20
22
  module Aerospike
21
23
  module CDT
22
24
 
23
- ##
24
- # Nested CDT context. Identifies the location of nested list/map to apply the operation.
25
- # for the current level.
26
- # An array of CTX identifies location of the list/map on multiple
27
- # levels on nesting.
25
+ ##
26
+ # Nested CDT context. Identifies the location of nested list/map to apply the operation.
27
+ # for the current level.
28
+ # An array of CTX identifies location of the list/map on multiple
29
+ # levels on nesting.
28
30
  class Context
29
-
30
31
  attr_accessor :id, :value
31
32
 
32
33
  def initialize(id, value)
@@ -37,64 +38,64 @@ module Aerospike
37
38
  ##
38
39
  # Create list with given type at index offset, given an order and pad.
39
40
  def self.list_index_create(index, order, pad)
40
- Context.new(0x10 | ListOrder.flag(order, pad), index)
41
- end
42
-
43
- ##
44
- # Lookup list by index offset.
45
- # If the index is negative, the resolved index starts backwards from end of list.
46
- # If an index is out of bounds, a parameter error will be returned.
47
- # Examples:
48
- # 0: First item.
49
- # 4: Fifth item.
50
- # -1: Last item.
51
- # -3: Third to last item.
52
- def self.list_index(index)
53
- Context.new(0x10, index)
54
- end
55
-
56
- ##
57
- # Lookup list by rank.
58
- # 0 = smallest value
59
- # N = Nth smallest value
60
- # -1 = largest value
61
- def self.list_rank(rank)
62
- Context.new(0x11, rank)
63
- end
64
-
65
- ##
66
- # Lookup list by value.
67
- def self.list_value(key)
68
- Context.new(0x13, key)
69
- end
70
-
71
- ##
72
- # Lookup map by index offset.
73
- # If the index is negative, the resolved index starts backwards from end of list.
74
- # If an index is out of bounds, a parameter error will be returned.
75
- # Examples:
76
- # 0: First item.
77
- # 4: Fifth item.
78
- # -1: Last item.
79
- # -3: Third to last item.
80
- def self.map_index(index)
81
- Context.new(0x20, index)
82
- end
83
-
84
- ##
85
- # Lookup map by rank.
86
- # 0 = smallest value
87
- # N = Nth smallest value
88
- # -1 = largest value
89
- def self.map_rank(rank)
90
- Context.new(0x21, rank)
91
- end
92
-
93
- ##
94
- # Lookup map by key.
95
- def self.map_key(key)
96
- Context.new(0x22, key)
97
- end
41
+ Context.new(0x10 | ListOrder.flag(order, pad), index)
42
+ end
43
+
44
+ ##
45
+ # Lookup list by index offset.
46
+ # If the index is negative, the resolved index starts backwards from end of list.
47
+ # If an index is out of bounds, a parameter error will be returned.
48
+ # Examples:
49
+ # 0: First item.
50
+ # 4: Fifth item.
51
+ # -1: Last item.
52
+ # -3: Third to last item.
53
+ def self.list_index(index)
54
+ Context.new(0x10, index)
55
+ end
56
+
57
+ ##
58
+ # Lookup list by rank.
59
+ # 0 = smallest value
60
+ # N = Nth smallest value
61
+ # -1 = largest value
62
+ def self.list_rank(rank)
63
+ Context.new(0x11, rank)
64
+ end
65
+
66
+ ##
67
+ # Lookup list by value.
68
+ def self.list_value(key)
69
+ Context.new(0x13, key)
70
+ end
71
+
72
+ ##
73
+ # Lookup map by index offset.
74
+ # If the index is negative, the resolved index starts backwards from end of list.
75
+ # If an index is out of bounds, a parameter error will be returned.
76
+ # Examples:
77
+ # 0: First item.
78
+ # 4: Fifth item.
79
+ # -1: Last item.
80
+ # -3: Third to last item.
81
+ def self.map_index(index)
82
+ Context.new(0x20, index)
83
+ end
84
+
85
+ ##
86
+ # Lookup map by rank.
87
+ # 0 = smallest value
88
+ # N = Nth smallest value
89
+ # -1 = largest value
90
+ def self.map_rank(rank)
91
+ Context.new(0x21, rank)
92
+ end
93
+
94
+ ##
95
+ # Lookup map by key.
96
+ def self.map_key(key)
97
+ Context.new(0x22, key)
98
+ end
98
99
 
99
100
  ##
100
101
  # Create map with given type at map key.
@@ -102,12 +103,78 @@ module Aerospike
102
103
  Context.new(0x22 | order[:flag], key)
103
104
  end
104
105
 
105
- ##
106
- # Lookup map by value.
107
- def self.map_value(key)
108
- Context.new(0x23, key)
109
- end
106
+ ##
107
+ # Lookup map by value.
108
+ def self.map_value(key)
109
+ Context.new(0x23, key)
110
+ end
111
+
112
+ ##
113
+ # Encodes the context via message pack.
114
+ def self.pack(packer, ctx)
115
+ unless ctx.to_a.empty?
116
+ packer.write_array_header(2)
117
+ ctx.each do |c|
118
+ packer.write(c.id)
119
+ Value.of(c.value)
120
+ end
121
+ end
122
+ end
123
+
124
+ ##
125
+ # Encodes the context via message pack and return the results.
126
+ def self.bytes(ctx)
127
+ unless ctx.to_a.empty?
128
+ Packer.use do |packer|
129
+ packer.write_array_header(ctx.length * 2)
130
+ ctx.each do |c|
131
+ packer.write(c.id)
132
+ Value.of(c.value).pack(packer)
133
+ end
134
+ return packer.bytes
135
+ end
136
+ end
137
+ nil
138
+ end
139
+
140
+ def ==(other)
141
+ self.id == other.id && self.value == other.value
142
+ end
110
143
 
144
+ ##
145
+ # decodes the base64 encoded messagepack byte array
146
+ # and converts it to an array of Context.
147
+ def self.from_bytes(buf)
148
+ list = nil
149
+ Unpacker.use do |unpacker|
150
+ list = unpacker.unpack(buf)
151
+ end
152
+
153
+ unless list.length % 2 == 0
154
+ raise Exceptions::Aerospike.new(Aerospike::ResultCode::PARAMETER_ERROR, "Invalid buffer")
155
+ end
156
+
157
+ list.each_slice(2).map { |id, value| Context.new(id, value) }
158
+ end
159
+
160
+ ##
161
+ # Encodes the context array to messagepack and then encodes
162
+ # the resulting byte array to base64.
163
+ def self.base64(ctx)
164
+ unless ctx.to_a.empty?
165
+ data = self.bytes(ctx)
166
+ return Base64.strict_encode64(data).force_encoding("binary")
167
+ end
168
+ ""
169
+ end
170
+
171
+ ##
172
+ # Decodes the byte array to messagepack and then decodes
173
+ # the resulting byte array to an array of Context.
174
+ def self.from_base64(buf)
175
+ bytes = Base64.strict_decode64(buf)
176
+ self.from_bytes(bytes)
177
+ end
111
178
  end
112
179
  end
113
180
  end
@@ -566,7 +566,8 @@ module Aerospike
566
566
  # This method is only supported by Aerospike 3 servers.
567
567
  # index_type should be :string, :numeric or :geo2dsphere (requires server version 3.7 or later)
568
568
  # collection_type should be :list, :mapkeys or :mapvalues
569
- def create_index(namespace, set_name, index_name, bin_name, index_type, collection_type = nil, options = nil)
569
+ # ctx is an optional list of context. Supported on server v6.1+.
570
+ def create_index(namespace, set_name, index_name, bin_name, index_type, collection_type = nil, options = nil, ctx: nil)
570
571
  if options.nil? && collection_type.is_a?(Hash)
571
572
  options, collection_type = collection_type, nil
572
573
  end
@@ -575,6 +576,7 @@ module Aerospike
575
576
  str_cmd = "sindex-create:ns=#{namespace}"
576
577
  str_cmd << ";set=#{set_name}" unless set_name.to_s.strip.empty?
577
578
  str_cmd << ";indexname=#{index_name};numbins=1"
579
+ str_cmd << ";context=#{CDT::Context.base64(ctx)}" unless ctx.to_a.empty?
578
580
  str_cmd << ";indextype=#{collection_type.to_s.upcase}" if collection_type
579
581
  str_cmd << ";indexdata=#{bin_name},#{index_type.to_s.upcase}"
580
582
  str_cmd << ";priority=normal"
@@ -15,39 +15,51 @@
15
15
  # the License.
16
16
 
17
17
  module Aerospike
18
-
19
18
  class Filter
19
+ attr_reader :packed_ctx
20
20
 
21
- def self.Equal(bin_name, value)
22
- Filter.new(bin_name, value, value)
23
- end
21
+ # open up the class to alias the class methods for naming consistency
22
+ class << self
23
+ def equal(bin_name, value, ctx: nil)
24
+ Filter.new(bin_name, value, value, nil, nil, ctx)
25
+ end
24
26
 
25
- def self.Contains(bin_name, value, col_type)
26
- Filter.new(bin_name, value, value, nil, col_type)
27
- end
27
+ def contains(bin_name, value, col_type, ctx: nil)
28
+ Filter.new(bin_name, value, value, nil, col_type, ctx)
29
+ end
28
30
 
29
- def self.Range(bin_name, from, to, col_type = nil)
30
- Filter.new(bin_name, from, to, nil, col_type)
31
- end
31
+ def range(bin_name, from, to, col_type = nil, ctx: nil)
32
+ Filter.new(bin_name, from, to, nil, col_type, ctx)
33
+ end
32
34
 
33
- def self.geoWithinGeoJSONRegion(bin_name, region, col_type = nil)
34
- region = region.to_json
35
- Filter.new(bin_name, region, region, ParticleType::GEOJSON, col_type)
36
- end
35
+ def geo_within_geo_region(bin_name, region, col_type = nil, ctx: nil)
36
+ region = region.to_json
37
+ Filter.new(bin_name, region, region, ParticleType::GEOJSON, col_type, ctx)
38
+ end
37
39
 
38
- def self.geoWithinRadius(bin_name, lon, lat, radius_meter, col_type = nil)
39
- region = GeoJSON.new({type: "AeroCircle", coordinates: [[lon, lat], radius_meter]})
40
- geoWithinGeoJSONRegion(bin_name, region, col_type)
41
- end
40
+ def geo_within_radius(bin_name, lon, lat, radius_meter, col_type = nil, ctx: nil)
41
+ region = GeoJSON.new({ type: "AeroCircle", coordinates: [[lon, lat], radius_meter] })
42
+ geo_within_geo_region(bin_name, region, col_type, ctx: ctx)
43
+ end
42
44
 
43
- def self.geoContainsGeoJSONPoint(bin_name, point, col_type = nil)
44
- point = point.to_json
45
- Filter.new(bin_name, point, point, ParticleType::GEOJSON, col_type)
46
- end
45
+ def geo_contains_geo_point(bin_name, point, col_type = nil, ctx: nil)
46
+ point = point.to_json
47
+ Filter.new(bin_name, point, point, ParticleType::GEOJSON, col_type, ctx)
48
+ end
47
49
 
48
- def self.geoContainsPoint(bin_name, lon, lat, col_type = nil)
49
- point = GeoJSON.new({type: "Point", coordinates: [lon, lat]})
50
- geoContainsGeoJSONPoint(bin_name, point, col_type)
50
+ def geo_contains_point(bin_name, lon, lat, col_type = nil, ctx: nil)
51
+ point = GeoJSON.new({ type: "Point", coordinates: [lon, lat] })
52
+ geo_contains_geo_point(bin_name, point, col_type, ctx: ctx)
53
+ end
54
+
55
+ # alias the old names for compatibility
56
+ alias :Equal :equal
57
+ alias :Contains :contains
58
+ alias :Range :range
59
+ alias :geoWithinGeoJSONRegion :geo_within_geo_region
60
+ alias :geoWithinRadius :geo_within_radius
61
+ alias :geoContainsGeoJSONPoint :geo_contains_geo_point
62
+ alias :geoContainsPoint :geo_contains_point
51
63
  end
52
64
 
53
65
  def estimate_size
@@ -56,21 +68,21 @@ module Aerospike
56
68
 
57
69
  def write(buf, offset)
58
70
  # Write name.
59
- len = buf.write_binary(@name, offset+1)
71
+ len = buf.write_binary(@name, offset + 1)
60
72
  buf.write_byte(len, offset)
61
73
  offset += len + 1
62
74
 
63
75
  # Write particle type.
64
76
  buf.write_byte(@val_type, offset)
65
- offset+=1
77
+ offset += 1
66
78
 
67
79
  # Write filter begin.
68
- len = @begin.write(buf, offset+4)
80
+ len = @begin.write(buf, offset + 4)
69
81
  buf.write_int32(len, offset)
70
82
  offset += len + 4
71
83
 
72
84
  # Write filter end.
73
- len = @end.write(buf, offset+4)
85
+ len = @end.write(buf, offset + 4)
74
86
  buf.write_int32(len, offset)
75
87
  offset += len + 4
76
88
 
@@ -98,7 +110,7 @@ module Aerospike
98
110
 
99
111
  private
100
112
 
101
- def initialize(bin_name, begin_value, end_value, val_type = nil, col_type = nil)
113
+ def initialize(bin_name, begin_value, end_value, val_type = nil, col_type = nil, ctx = nil)
102
114
  @name = bin_name
103
115
  @begin = Aerospike::Value.of(begin_value)
104
116
  @end = Aerospike::Value.of(end_value)
@@ -107,8 +119,8 @@ module Aerospike
107
119
  # but in certain cases caller can override the type.
108
120
  @val_type = val_type || @begin.type
109
121
  @col_type = col_type
110
- end
111
122
 
123
+ @packed_ctx = CDT::Context.bytes(ctx)
124
+ end
112
125
  end # class
113
-
114
126
  end
@@ -82,12 +82,11 @@ module Aerospike
82
82
  @data_offset += filter_size
83
83
  field_count += 1
84
84
 
85
- # TODO: Implement
86
- # packed_ctx = filter.packed_ctx
87
- # if packed_ctx
88
- # @data_offset += FIELD_HEADER_SIZE + packed_ctx.length
89
- # field_count+=1
90
- # end
85
+ packed_ctx = filter.packed_ctx
86
+ if packed_ctx
87
+ @data_offset += FIELD_HEADER_SIZE + packed_ctx.length
88
+ field_count += 1
89
+ end
91
90
  end
92
91
 
93
92
  @statement.set_task_id
@@ -210,11 +209,10 @@ module Aerospike
210
209
  @data_offset += @data_buffer.write_byte(1, @data_offset)
211
210
  @data_offset = filter.write(@data_buffer, @data_offset)
212
211
 
213
- # TODO: Implement
214
- # if packed_ctx
215
- # write_field_header(packed_ctx.length, FieldType::INDEX_CONTEXT)
216
- # @data_buffer.write_binary(packed_ctx, @data_offset)
217
- # end
212
+ if packed_ctx
213
+ write_field_header(packed_ctx.length, FieldType::INDEX_CONTEXT)
214
+ @data_offset += @data_buffer.write_binary(packed_ctx, @data_offset)
215
+ end
218
216
  end
219
217
 
220
218
  if @statement.function_name
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Aerospike
3
- VERSION = "2.25.0"
3
+ VERSION = "2.26.0"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aerospike
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.25.0
4
+ version: 2.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Khosrow Afroozeh
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-11-28 00:00:00.000000000 Z
12
+ date: 2022-12-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: msgpack