tablestore-ruby-sdk 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,481 @@
1
+ require 'protobuf'
2
+ require 'os'
3
+ require 'protobuf/ots_pb'
4
+ require 'protobuf/ots_filiter_pb'
5
+ require 'consts'
6
+ require 'tablestore/plain_buffer_coded_output_stream'
7
+ require 'tablestore/plain_buffer_output_stream'
8
+ require 'tablestore/plain_buffer_coded_input_stream'
9
+ require 'tablestore/plain_buffer_input_stream'
10
+
11
+ class OTS
12
+ def encode_get_range_request(request)
13
+ proto = GetRangeRequest.new
14
+ proto.table_name = request[:table_name]
15
+ proto.direction = request[:direction]
16
+ proto.inclusive_start_primary_key = serialize_primary_key(request[:inclusive_start_primary_key])
17
+ proto.exclusive_end_primary_key = serialize_primary_key(request[:exclusive_end_primary_key])
18
+ proto.max_versions = request[:max_version]
19
+ proto.limit = request[:limit]
20
+ proto_string = GetRangeRequest.encode(proto)
21
+ if proto_string.match("#{request[:table_name]}\x10\x02")
22
+ proto_string.sub("#{request[:table_name]}\x10\x02", "#{request[:table_name]}\x10\x00")
23
+ end
24
+ proto_string.sub("#{request[:table_name]}\x10\x02", "#{request[:table_name]}\x10\x00")
25
+ end
26
+
27
+ def decode_get_range_request(api_name, headers, body)
28
+ proto = GetRangeResponse.decode(body)
29
+ #capacity_unit = parse_capacity_unit(proto.consumed.capacity_unit)
30
+
31
+ next_start_pk = nil
32
+ row_list = []
33
+
34
+ # if proto.next_start_primary_key.length != 0
35
+ # inputStream = PlainBufferInputStream.new(proto.next_start_primary_key)
36
+ # codedInputStream = PlainBufferCodedInputStream.new(inputStream)
37
+ # next_start_pk, att = codedInputStream.read_row
38
+ # end
39
+ if proto.rows.length != 0
40
+ inputStream = PlainBufferInputStream.new(proto.rows)
41
+ codedInputStream = PlainBufferCodedInputStream.new(inputStream)
42
+ row_list = codedInputStream.read_rows
43
+ end
44
+
45
+ #next_token = proto.next_token
46
+
47
+ row_list
48
+ #return capacity_unit, next_start_pk, row_list, next_token
49
+ end
50
+
51
+ def encode_put_row(table_name, row, condition)
52
+ proto = PutRowRequest.new
53
+ proto.table_name = table_name
54
+ condition = Condition(RowExistenceExpectation::IGNORE, nil) if condition.nil?
55
+ contion_proto = Condition.new
56
+ proto.condition = make_condition(contion_proto, condition)
57
+ proto.row = serialize_for_put_row(row.primary_key, row.attribute_columns)
58
+ proto_string = PutRowRequest.encode(proto)
59
+ proto_string = proto_string[0..-2] + [0].pack('C') if proto_string[-1] == "\x03"
60
+ proto_string
61
+ end
62
+
63
+ def encode_get_row(table_name, primary_key, columns_to_get, column_filter, max_version)
64
+ proto = GetRowRequest.new
65
+ proto.table_name = table_name
66
+ make_repeated_column_names(proto.columns_to_get, columns_to_get)
67
+ if column_filter.present?
68
+ pb_filter = make_column_condition(column_filter)
69
+ proto.filter = Filter.encode(pb_filter)
70
+ end
71
+ proto.primary_key = serialize_primary_key(primary_key)
72
+ proto.max_versions = max_version if max_version.present?
73
+ GetRowRequest.encode(proto)
74
+ end
75
+
76
+ def decode_get_row(body)
77
+ proto = GetRowResponse.decode(body)
78
+
79
+ return_row = nil
80
+ if proto.row.length > 0
81
+ inputStream = PlainBufferInputStream.new(proto.row)
82
+ codedInputStream = PlainBufferCodedInputStream.new(inputStream)
83
+ return_row = codedInputStream.read_row
84
+ end
85
+ return_row
86
+ end
87
+
88
+ def decode_put_row(body)
89
+ proto = PutRowResponse.decode(body)
90
+ return_row = nil
91
+ if proto.row.length != 0
92
+ inputStream = PlainBufferInputStream.new(proto.row)
93
+ codedInputStream = PlainBufferCodedInputStream.new(inputStream)
94
+ return_row = codedInputStream.read_row
95
+ end
96
+ return_row
97
+ end
98
+
99
+ def make_batch_get_row(request)
100
+ proto = BatchGetRowRequest.new
101
+ request.items.each do |item|
102
+ table_value = item[1]
103
+ table_item = TableInBatchGetRowRequest.new
104
+ table_item.table_name = table_value.table_name
105
+ make_repeated_column_names(table_item.columns_to_get, table_value.columns_to_get)
106
+
107
+ if table_value.column_filter.present?
108
+ pb_filter = make_column_condition(table_value.column_filter)
109
+ table_item.filter = Filter.encode(pb_filter)
110
+ end
111
+
112
+ table_value.primary_keys.each do |pk|
113
+ table_item.primary_key << serialize_primary_key(pk)
114
+ end
115
+
116
+ if table_value.token.present?
117
+ table_value.token.each do |tk|
118
+ table_item.token << tk
119
+ end
120
+ end
121
+ if table_value.max_version.present?
122
+ table_item.max_versions = table_value.max_version
123
+ end
124
+ if table_value.time_range.present?
125
+ if table_value.time_range.is_a?(Array)
126
+ table_item.time_range.start_time = table_value.time_range[0]
127
+ table_item.time_range.end_time = table_value.time_range[1]
128
+ elsif table_value.is_a?(Fixnum)
129
+ table_item.time_range.specific_time = table_value.time_range
130
+ end
131
+ end
132
+ if table_value.start_column.present?
133
+ table_item.start_column = table_value.start_column
134
+ end
135
+ if table_value.end_column.present?
136
+ table_item.end_column = table_value.end_column
137
+ end
138
+ proto.tables << table_item
139
+ end
140
+ BatchGetRowRequest.encode(proto)
141
+ end
142
+
143
+ def decode_batch_get_row(body)
144
+ proto = BatchGetRowResponse.decode(body)
145
+ rows = []
146
+ proto.tables.each do |table_item|
147
+ rows << parse_get_row_item(table_item.rows)
148
+ end
149
+ rows
150
+ end
151
+
152
+ def make_batch_write_row(request)
153
+ proto = BatchWriteRowRequest.new
154
+ request.items.each do |item|
155
+ table_value = item[1]
156
+ table_item = TableInBatchWriteRowRequest.new
157
+ table_item.table_name = table_value.table_name
158
+
159
+ table_value.row_items.each do |row_item|
160
+ if row_item.type == Metadata::BatchWriteRowType::PUT
161
+ row = RowInBatchWriteRowRequest.new
162
+ table_item.rows << make_put_row_item(row, row_item)
163
+ end
164
+ if row_item.type == Metadata::BatchWriteRowType::UPDATE
165
+ row = RowInBatchWriteRowRequest.new
166
+ table_item.rows << make_update_row_item(row, row_item)
167
+ end
168
+ end
169
+ proto.tables << table_item
170
+ end
171
+ batch_string = BatchWriteRowRequest.encode(proto)
172
+ batch_string.gsub("\x08\x03", "\x08\x00")
173
+ end
174
+
175
+ def make_put_row_item(proto, put_row_item)
176
+ condition = put_row_item.condition
177
+ if condition.nil?
178
+ condition = Metadata::Condition.new(Metadata::RowExistenceExpectation::IGNORE, nil)
179
+ end
180
+ condition_proto = Condition.new
181
+ proto.condition = make_condition(condition_proto, condition)
182
+ if put_row_item.return_type == ReturnType::RT_PK
183
+ proto.return_content.return_type = :RT_PK
184
+ end
185
+
186
+ proto.row_change = serialize_for_put_row(put_row_item.row.primary_key, put_row_item.row.attribute_columns)
187
+ proto.type = :PUT
188
+ proto
189
+ end
190
+
191
+ def make_update_row_item(proto, update_row_item)
192
+ condition = update_row_item.condition
193
+ if condition.nil?
194
+ condition = Metadata::Condition(Metadata::RowExistenceExpectation::IGNORE, nil)
195
+ end
196
+
197
+ make_condition(proto.condition, condition)
198
+
199
+ if update_row_item.return_type == Metadata::ReturnType::RT_PK
200
+ proto.return_content.return_type = :RT_PK
201
+ end
202
+
203
+ proto.row_change = serialize_for_update_row(update_row_item.row.primary_key, update_row_item.row.attribute_columns)
204
+ proto.type = :UPDATE
205
+ proto
206
+ end
207
+
208
+ def make_repeated_column_names(proto, columns_to_get)
209
+ if columns_to_get.nil?
210
+ return
211
+ end
212
+
213
+ columns_to_get.each do |column_name|
214
+ proto << column_name
215
+ end
216
+ end
217
+
218
+ def make_condition(proto, condition)
219
+ raise TableStoreClientError.new("condition should be an instance of Condition, not #{condition.class}") unless condition.is_a?(Metadata::Condition)
220
+ expectation_str = condition.get_row_existence_expectation
221
+ proto.row_existence = expectation_str
222
+ raise TableStoreClientError.new("row_existence_expectation should be one of [#{join(', ')}], not #{expectation_str}") if proto.row_existence.nil?
223
+
224
+ if condition.get_column_condition.present?
225
+ pb_filter = make_column_condition(condition.column_condition)
226
+ proto.column_condition = Filter.encode(pb_filter)
227
+ end
228
+ proto
229
+ end
230
+
231
+ def make_column_condition(column_condition)
232
+ return if column_condition.nil?
233
+ proto = Filter.new
234
+ proto.type = column_condition.get_type
235
+
236
+ # condition
237
+ if column_condition.is_a?(Metadata::CompositeColumnCondition)
238
+ proto.filter = make_composite_condition(column_condition)
239
+ elsif column_condition.is_a?(Metadata::SingleColumnCondition)
240
+ proto.filter = make_relation_condition(column_condition)
241
+ else
242
+ raise TableStoreClientError.new("expect CompositeColumnCondition, SingleColumnCondition but not #{column_condition.class}")
243
+ end
244
+ proto
245
+ end
246
+
247
+ def make_composite_condition(condition)
248
+ proto = CompositeColumnValueFilter.new
249
+ proto.combinator = condition.get_combinator
250
+
251
+ condition.sub_conditions.each do |sub|
252
+ proto.sub_filters << make_column_condition(sub)
253
+ end
254
+
255
+ CompositeColumnValueFilter.encode(proto)
256
+ end
257
+
258
+ def make_relation_condition(condition)
259
+ proto = SingleColumnValueFilter.new
260
+ proto.comparator = condition.get_comparator
261
+
262
+ proto.column_name = condition.get_column_name
263
+ proto.column_value = serialize_column_value(condition.get_column_value)
264
+ proto.filter_if_missing = !condition.pass_if_missing
265
+ proto.latest_version_only = condition.latest_version_only
266
+ filter_string = SingleColumnValueFilter.encode(proto)
267
+
268
+ if proto.filter_if_missing.blank? && proto.latest_version_only.blank?
269
+ filter_string += [32, 0, 40, 0].pack("C*")
270
+ elsif proto.filter_if_missing.blank?
271
+ filter_string.insert(-3, [32, 0].pack("C*"))
272
+ elsif proto.latest_version_only.blank?
273
+ filter_string += [40, 0].pack("C*")
274
+ end
275
+
276
+ filter_string
277
+ end
278
+
279
+ def parse_get_row_item(proto)
280
+ row_list = []
281
+ proto.each do |row_item|
282
+ primary_key_columns = nil
283
+ attribute_columns = nil
284
+
285
+ if row_item.is_ok
286
+ # error_code = nil
287
+ # error_message = nil
288
+ # capacity_unit = parse_capacity_unit(row_item.consumed.capacity_unit)
289
+
290
+ if row_item.row.length != 0
291
+ inputStream = PlainBufferInputStream.new(row_item.row)
292
+ codedInputStream = PlainBufferCodedInputStream.new(inputStream)
293
+ primary_key_columns, attribute_columns = codedInputStream.read_row
294
+ end
295
+ else
296
+ # error_code = row_item.error.code
297
+ # error_message = row_item.error.HasField('message') ? row_item.error.message : ''
298
+ # if row_item.HasField('consumed')
299
+ # capacity_unit = parse_capacity_unit(row_item.consumed.capacity_unit)
300
+ # else
301
+ # capacity_unit = nil
302
+ # end
303
+ end
304
+
305
+ row_list << {pk: primary_key_columns, attr: attribute_columns} if primary_key_columns.present?
306
+ end
307
+ row_list
308
+ end
309
+
310
+ def parse_batch_write_row(proto)
311
+ result_list = {}
312
+ proto.each do |table_item|
313
+ table_name = table_item.table_name
314
+ result_list[table_name] = []
315
+
316
+ table_item.rows.each do |row_item|
317
+ row = parse_write_row_item(row_item)
318
+ result_list[table_name] << row
319
+ end
320
+ end
321
+
322
+ result_list
323
+ end
324
+
325
+ def parse_write_row_item(row_item)
326
+ primary_key_columns = nil
327
+
328
+ if row_item.is_ok
329
+ error_code = nil
330
+ error_message = nil
331
+
332
+ if row_item.row.length != 0
333
+ inputStream = PlainBufferInputStream.new(row_item.row)
334
+ codedInputStream = PlainBufferCodedInputStream.new(inputStream)
335
+ primary_key_columns, attribute_columns = codedInputStream.read_row
336
+ end
337
+ end
338
+ primary_key_columns
339
+
340
+ #BatchWriteRowResponseItem.new(row_item.is_ok, error_code, error_message, consumed, primary_key_columns)
341
+ end
342
+
343
+ private
344
+ def serialize_primary_key(primary_key)
345
+ buf_size = LITTLE_ENDIAN_SIZE
346
+ buf_size += compute_primary_key_size(primary_key)
347
+ buf_size += 2
348
+ output_stream = PlainBufferOutputStream.new(buf_size)
349
+ coded_output_stream = PlainBufferCodedOutputStream.new(output_stream)
350
+ row_checksum = 0
351
+ coded_output_stream.write_header
352
+
353
+ row_checksum = coded_output_stream.write_primary_key(primary_key, row_checksum)
354
+ row_checksum = coded_output_stream.crc_int8(row_checksum, 0)
355
+ coded_output_stream.write_row_checksum(row_checksum)
356
+ output_stream.get_buffer.join('')
357
+ end
358
+
359
+ def serialize_column_value(value)
360
+ buf_size = compute_variant_value_size(value)
361
+ stream = PlainBufferOutputStream.new(buf_size)
362
+ coded_stream = PlainBufferCodedOutputStream.new(stream)
363
+
364
+ coded_stream.write_column_value(value)
365
+ stream.get_buffer.join('')
366
+ end
367
+
368
+ def compute_variant_value_size(value)
369
+ compute_primary_key_value_size(value) - LITTLE_ENDIAN_SIZE - 1
370
+ end
371
+
372
+ def parse_capacity_unit(proto)
373
+ if proto.nil?
374
+ capacity_unit = nil
375
+ else
376
+ cu_read = proto.HasField('read') ? proto.read : 0
377
+ cu_write = proto.HasField('write') ? proto.write : 0
378
+ capacity_unit = CapacityUnit(cu_read, cu_write)
379
+ end
380
+ capacity_unit
381
+ end
382
+
383
+ def compute_primary_key_size(primary_key)
384
+ size = 1
385
+ primary_key.each do |pk|
386
+ size += compute_primary_key_column_size(pk[0], pk[1])
387
+ end
388
+ size
389
+ end
390
+
391
+ def compute_primary_key_column_size(pk_name, pk_value)
392
+ size = 1
393
+ size += 1 + LITTLE_ENDIAN_SIZE
394
+ size += pk_name.length
395
+ size += compute_primary_key_value_size(pk_value)
396
+ size += 2
397
+ size
398
+ end
399
+
400
+ def compute_primary_key_value_size(value)
401
+ size = 1
402
+ size += LITTLE_ENDIAN_SIZE + 1
403
+ if ["INF_MIN", "INF_MAX", "PK_AUTO_INCR"].include?value
404
+ size += 1
405
+ return size
406
+ end
407
+ if value.is_a?(Numeric)
408
+ size += 8
409
+ elsif value.is_a?(String)
410
+ size += LITTLE_ENDIAN_SIZE
411
+ size += value.length
412
+ end
413
+ size
414
+ end
415
+
416
+ def serialize_for_put_row(primary_key, attribute_columns)
417
+ buf_size = compute_put_row_size(primary_key, attribute_columns)
418
+ output_stream = PlainBufferOutputStream.new(buf_size)
419
+ coded_output_stream = PlainBufferCodedOutputStream.new(output_stream)
420
+
421
+ row_checksum = 0
422
+ coded_output_stream.write_header
423
+ row_checksum = coded_output_stream.write_primary_key(primary_key, row_checksum)
424
+ row_checksum = coded_output_stream.write_columns(attribute_columns, row_checksum)
425
+ row_checksum = PlainBufferCrc8.crc_int8(row_checksum, 0)
426
+ coded_output_stream.write_row_checksum(row_checksum)
427
+
428
+ output_stream.get_buffer.join('')
429
+ end
430
+
431
+ def compute_put_row_size(primary_key, attribute_columns)
432
+ size = LITTLE_ENDIAN_SIZE
433
+ size += compute_primary_key_size(primary_key)
434
+
435
+ if attribute_columns.length != 0
436
+ size += 1
437
+ attribute_columns.each do |attr|
438
+ if attr.length == 2
439
+ size += compute_column_size(attr[0], attr[1])
440
+ else
441
+ size += compute_column_size(attr[0], attr[1], attr[2])
442
+ end
443
+ end
444
+ end
445
+ size += 2
446
+ size
447
+ end
448
+
449
+ def compute_column_size(column_name, column_value, timestamp = nil)
450
+ size = 1
451
+ size += 1 + LITTLE_ENDIAN_SIZE
452
+ size += column_name.length
453
+ unless column_value.nil?
454
+ size += compute_column_value_size(column_value)
455
+ end
456
+ unless timestamp.nil?
457
+ size += 1 + LITTLE_ENDIAN_64_SIZE
458
+ end
459
+ size += 2
460
+ size
461
+ end
462
+
463
+ def compute_column_value_size(value)
464
+ size = 1
465
+ size += LITTLE_ENDIAN_SIZE + 1
466
+
467
+ if value.is_a?(TrueClass) || value.is_a?(FalseClass)
468
+ size += 1
469
+ elsif value.is_a?(Fixnum)
470
+ size += LITTLE_ENDIAN_64_SIZE
471
+ elsif value.is_a?(String)
472
+ size += LITTLE_ENDIAN_SIZE
473
+ size += value.length
474
+ elsif value.is_a?(Float)
475
+ size += LITTLE_ENDIAN_64_SIZE
476
+ else
477
+ raise TableStoreClientError("Unsupported column type: " + value.class)
478
+ end
479
+ size
480
+ end
481
+ end