riak-client 2.2.2 → 2.3.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 +4 -4
- data/.rspec +1 -0
- data/RELEASE_NOTES.md +16 -0
- data/Rakefile +3 -2
- data/lib/riak/client/beefcake/message_codes.rb +12 -0
- data/lib/riak/client/beefcake/messages.rb +205 -5
- data/lib/riak/client/beefcake/object_methods.rb +1 -2
- data/lib/riak/client/beefcake/operator.rb +9 -0
- data/lib/riak/client/beefcake/time_series_delete_operator.rb +24 -0
- data/lib/riak/client/beefcake/time_series_get_operator.rb +35 -0
- data/lib/riak/client/beefcake/time_series_list_operator.rb +42 -0
- data/lib/riak/client/beefcake/time_series_put_operator.rb +32 -0
- data/lib/riak/client/beefcake/time_series_query_operator.rb +42 -0
- data/lib/riak/client/beefcake/ts_cell_codec.rb +63 -0
- data/lib/riak/client/beefcake_protobuffs_backend.rb +5 -0
- data/lib/riak/client.rb +3 -0
- data/lib/riak/errors/time_series.rb +23 -0
- data/lib/riak/locale/en.yml +5 -0
- data/lib/riak/time_series/collection.rb +5 -0
- data/lib/riak/time_series/deletion.rb +26 -0
- data/lib/riak/time_series/list.rb +66 -0
- data/lib/riak/time_series/query.rb +43 -0
- data/lib/riak/time_series/read.rb +18 -0
- data/lib/riak/time_series/row.rb +4 -0
- data/lib/riak/time_series/submission.rb +32 -0
- data/lib/riak/time_series.rb +17 -0
- data/lib/riak/version.rb +1 -1
- data/lib/riak.rb +16 -0
- data/spec/integration/riak/bucket_types_spec.rb +6 -6
- data/spec/integration/riak/time_series_spec.rb +168 -0
- data/spec/riak/beefcake_protobuffs_backend/object_methods_spec.rb +31 -2
- data/spec/riak/beefcake_protobuffs_backend/ts_cell_codec_spec.rb +116 -0
- data/spec/riak/client_spec.rb +11 -0
- data/spec/riak/crdt/inner_flag_spec.rb +1 -1
- data/spec/riak/time_series/deletion_spec.rb +33 -0
- data/spec/riak/time_series/listing_spec.rb +50 -0
- data/spec/riak/time_series/submission_spec.rb +35 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/test_client.yml +0 -1
- metadata +29 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8eb1ae6b34bdb0bc9e7ace398e001f570dfe0782
|
4
|
+
data.tar.gz: f4b53df09ae0c37710f74bc6fa4bb2bc2e47e82e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9bb8412b0efd79d81d486a87302c0985e59420d7d1a2d1cd9119f60afef9dbffbed2fc19a003c4e31917080c14816830545d3bcebab200d23b0f6ab0e8c3374f
|
7
|
+
data.tar.gz: 3ffebec87cfddc2ddd8422785f49e9814452ed94720c27d8666ff815e224f072c046302741c34d2b77aa4026f872a1e928cd25f7a4b93a901367518ad83a3b13
|
data/.rspec
CHANGED
data/RELEASE_NOTES.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# Riak Ruby Client Release Notes
|
2
2
|
|
3
|
+
## 2.3.0 Release - 2015-12-15
|
4
|
+
|
5
|
+
Version 2.3.0 is a feature release, introducing support for the Riak TS time
|
6
|
+
series database.
|
7
|
+
|
8
|
+
New features:
|
9
|
+
|
10
|
+
* Riak TS support, for queries, reads, writes, and deletes. Key list support
|
11
|
+
is also provided.
|
12
|
+
* Network error logging, thanks to Sebastian Röbke.
|
13
|
+
|
14
|
+
Bug fixes:
|
15
|
+
|
16
|
+
* The `last_modified` field on `RContent` and `RObject` objects now has
|
17
|
+
microsecond precision, thanks to Sebastian Röbke.
|
18
|
+
|
3
19
|
## 2.2.2 Release - 2015-11-24
|
4
20
|
|
5
21
|
Version 2.2.2 is a bugfix release.
|
data/Rakefile
CHANGED
@@ -90,7 +90,7 @@ task :pb_defs => 'beefcake:pb_defs'
|
|
90
90
|
namespace :beefcake do
|
91
91
|
task :pb_defs => 'lib/riak/client/beefcake/messages.rb'
|
92
92
|
|
93
|
-
PROTO_FILES = %w{riak_kv riak_search riak_yokozuna riak_dt}
|
93
|
+
PROTO_FILES = %w{riak_kv riak_search riak_yokozuna riak_dt riak_ts}
|
94
94
|
PROTO_TMP = PROTO_FILES.map{|f| "tmp/#{f}.pb.rb"}
|
95
95
|
|
96
96
|
task :clean do
|
@@ -113,7 +113,8 @@ namespace :beefcake do
|
|
113
113
|
|
114
114
|
directory 'tmp/riak_pb' => 'tmp' do
|
115
115
|
cd 'tmp' do
|
116
|
-
|
116
|
+
# NB: change this once TS is published
|
117
|
+
sh "git clone -b end-to-end/timeseries https://github.com/basho/riak_pb.git"
|
117
118
|
end
|
118
119
|
end
|
119
120
|
end
|
@@ -68,6 +68,18 @@ module Riak
|
|
68
68
|
:DtUpdateReq => 82,
|
69
69
|
:DtUpdateResp => 83,
|
70
70
|
|
71
|
+
# riak time series
|
72
|
+
:TsQueryReq => 90,
|
73
|
+
:TsQueryResp => 91,
|
74
|
+
:TsPutReq => 92,
|
75
|
+
:TsPutResp => 93,
|
76
|
+
:TsDelReq => 94,
|
77
|
+
:TsDelResp => 95,
|
78
|
+
:TsGetReq => 96,
|
79
|
+
:TsGetResp => 97,
|
80
|
+
:TsListKeysReq => 98,
|
81
|
+
:TsListKeysResp => 99,
|
82
|
+
|
71
83
|
# internal
|
72
84
|
:AuthReq => 253,
|
73
85
|
:AuthResp => 254,
|
@@ -4,7 +4,7 @@ module Riak
|
|
4
4
|
class Client
|
5
5
|
# @private
|
6
6
|
class BeefcakeProtobuffsBackend
|
7
|
-
## Generated from riak.proto
|
7
|
+
## Generated from riak.proto
|
8
8
|
require "beefcake"
|
9
9
|
|
10
10
|
|
@@ -67,6 +67,14 @@ class RpbAuthReq
|
|
67
67
|
include Beefcake::Message
|
68
68
|
end
|
69
69
|
|
70
|
+
class RpbToggleEncodingReq
|
71
|
+
include Beefcake::Message
|
72
|
+
end
|
73
|
+
|
74
|
+
class RpbToggleEncodingResp
|
75
|
+
include Beefcake::Message
|
76
|
+
end
|
77
|
+
|
70
78
|
class RpbErrorResp
|
71
79
|
required :errmsg, :bytes, 1
|
72
80
|
required :errcode, :uint32, 2
|
@@ -156,7 +164,15 @@ class RpbAuthReq
|
|
156
164
|
required :user, :bytes, 1
|
157
165
|
required :password, :bytes, 2
|
158
166
|
end
|
159
|
-
|
167
|
+
|
168
|
+
class RpbToggleEncodingReq
|
169
|
+
required :use_native, :bool, 1
|
170
|
+
end
|
171
|
+
|
172
|
+
class RpbToggleEncodingResp
|
173
|
+
required :use_native, :bool, 1
|
174
|
+
end
|
175
|
+
## Generated from riak_kv.proto
|
160
176
|
require "beefcake"
|
161
177
|
|
162
178
|
|
@@ -225,6 +241,10 @@ class RpbIndexResp
|
|
225
241
|
include Beefcake::Message
|
226
242
|
end
|
227
243
|
|
244
|
+
class RpbIndexBodyResp
|
245
|
+
include Beefcake::Message
|
246
|
+
end
|
247
|
+
|
228
248
|
class RpbCSBucketReq
|
229
249
|
include Beefcake::Message
|
230
250
|
end
|
@@ -273,6 +293,18 @@ class RpbBucketKeyPreflistItem
|
|
273
293
|
include Beefcake::Message
|
274
294
|
end
|
275
295
|
|
296
|
+
class RpbCoverageReq
|
297
|
+
include Beefcake::Message
|
298
|
+
end
|
299
|
+
|
300
|
+
class RpbCoverageResp
|
301
|
+
include Beefcake::Message
|
302
|
+
end
|
303
|
+
|
304
|
+
class RpbCoverageEntry
|
305
|
+
include Beefcake::Message
|
306
|
+
end
|
307
|
+
|
276
308
|
class RpbGetClientIdResp
|
277
309
|
required :client_id, :bytes, 1
|
278
310
|
end
|
@@ -392,6 +424,8 @@ class RpbIndexReq
|
|
392
424
|
optional :type, :bytes, 12
|
393
425
|
optional :term_regex, :bytes, 13
|
394
426
|
optional :pagination_sort, :bool, 14
|
427
|
+
optional :cover_context, :bytes, 15
|
428
|
+
optional :return_body, :bool, 16
|
395
429
|
end
|
396
430
|
|
397
431
|
class RpbIndexResp
|
@@ -401,6 +435,12 @@ class RpbIndexResp
|
|
401
435
|
optional :done, :bool, 4
|
402
436
|
end
|
403
437
|
|
438
|
+
class RpbIndexBodyResp
|
439
|
+
repeated :objects, RpbIndexObject, 1
|
440
|
+
optional :continuation, :bytes, 2
|
441
|
+
optional :done, :bool, 3
|
442
|
+
end
|
443
|
+
|
404
444
|
class RpbCSBucketReq
|
405
445
|
required :bucket, :bytes, 1
|
406
446
|
required :start_key, :bytes, 2
|
@@ -411,6 +451,7 @@ class RpbCSBucketReq
|
|
411
451
|
optional :max_results, :uint32, 7
|
412
452
|
optional :timeout, :uint32, 8
|
413
453
|
optional :type, :bytes, 9
|
454
|
+
optional :cover_context, :bytes, 10
|
414
455
|
end
|
415
456
|
|
416
457
|
class RpbCSBucketResp
|
@@ -486,7 +527,26 @@ class RpbBucketKeyPreflistItem
|
|
486
527
|
required :node, :bytes, 2
|
487
528
|
required :primary, :bool, 3
|
488
529
|
end
|
489
|
-
|
530
|
+
|
531
|
+
class RpbCoverageReq
|
532
|
+
optional :type, :bytes, 1
|
533
|
+
required :bucket, :bytes, 2
|
534
|
+
optional :min_partitions, :uint32, 3
|
535
|
+
optional :replace_cover, :bytes, 4
|
536
|
+
repeated :unavailable_cover, :bytes, 5
|
537
|
+
end
|
538
|
+
|
539
|
+
class RpbCoverageResp
|
540
|
+
repeated :entries, RpbCoverageEntry, 1
|
541
|
+
end
|
542
|
+
|
543
|
+
class RpbCoverageEntry
|
544
|
+
required :ip, :bytes, 1
|
545
|
+
required :port, :uint32, 2
|
546
|
+
optional :keyspace_desc, :bytes, 3
|
547
|
+
required :cover_context, :bytes, 4
|
548
|
+
end
|
549
|
+
## Generated from riak_search.proto
|
490
550
|
require "beefcake"
|
491
551
|
|
492
552
|
|
@@ -524,7 +584,7 @@ class RpbSearchQueryResp
|
|
524
584
|
optional :max_score, :float, 2
|
525
585
|
optional :num_found, :uint32, 3
|
526
586
|
end
|
527
|
-
## Generated from riak_yokozuna.proto
|
587
|
+
## Generated from riak_yokozuna.proto
|
528
588
|
require "beefcake"
|
529
589
|
|
530
590
|
|
@@ -603,7 +663,7 @@ end
|
|
603
663
|
class RpbYokozunaSchemaGetResp
|
604
664
|
required :schema, RpbYokozunaSchema, 1
|
605
665
|
end
|
606
|
-
## Generated from riak_dt.proto
|
666
|
+
## Generated from riak_dt.proto
|
607
667
|
require "beefcake"
|
608
668
|
|
609
669
|
|
@@ -766,6 +826,146 @@ class DtUpdateResp
|
|
766
826
|
repeated :set_value, :bytes, 4
|
767
827
|
repeated :map_value, MapEntry, 5
|
768
828
|
end
|
829
|
+
## Generated from riak_ts.proto
|
830
|
+
require "beefcake"
|
831
|
+
|
832
|
+
|
833
|
+
module TsColumnType
|
834
|
+
VARCHAR = 0
|
835
|
+
SINT64 = 1
|
836
|
+
DOUBLE = 2
|
837
|
+
TIMESTAMP = 3
|
838
|
+
BOOLEAN = 4
|
839
|
+
end
|
840
|
+
|
841
|
+
class TsQueryReq
|
842
|
+
include Beefcake::Message
|
843
|
+
end
|
844
|
+
|
845
|
+
class TsQueryResp
|
846
|
+
include Beefcake::Message
|
847
|
+
end
|
848
|
+
|
849
|
+
class TsGetReq
|
850
|
+
include Beefcake::Message
|
851
|
+
end
|
852
|
+
|
853
|
+
class TsGetResp
|
854
|
+
include Beefcake::Message
|
855
|
+
end
|
856
|
+
|
857
|
+
class TsPutReq
|
858
|
+
include Beefcake::Message
|
859
|
+
end
|
860
|
+
|
861
|
+
class TsPutResp
|
862
|
+
include Beefcake::Message
|
863
|
+
end
|
864
|
+
|
865
|
+
class TsDelReq
|
866
|
+
include Beefcake::Message
|
867
|
+
end
|
868
|
+
|
869
|
+
class TsDelResp
|
870
|
+
include Beefcake::Message
|
871
|
+
end
|
872
|
+
|
873
|
+
class TsInterpolation
|
874
|
+
include Beefcake::Message
|
875
|
+
end
|
876
|
+
|
877
|
+
class TsColumnDescription
|
878
|
+
include Beefcake::Message
|
879
|
+
end
|
880
|
+
|
881
|
+
class TsRow
|
882
|
+
include Beefcake::Message
|
883
|
+
end
|
884
|
+
|
885
|
+
class TsCell
|
886
|
+
include Beefcake::Message
|
887
|
+
end
|
888
|
+
|
889
|
+
class TsListKeysReq
|
890
|
+
include Beefcake::Message
|
891
|
+
end
|
892
|
+
|
893
|
+
class TsListKeysResp
|
894
|
+
include Beefcake::Message
|
895
|
+
end
|
896
|
+
|
897
|
+
class TsQueryReq
|
898
|
+
optional :query, TsInterpolation, 1
|
899
|
+
optional :stream, :bool, 2, :default => false
|
900
|
+
end
|
901
|
+
|
902
|
+
class TsQueryResp
|
903
|
+
repeated :columns, TsColumnDescription, 1
|
904
|
+
repeated :rows, TsRow, 2
|
905
|
+
optional :done, :bool, 3, :default => true
|
906
|
+
end
|
907
|
+
|
908
|
+
class TsGetReq
|
909
|
+
required :table, :bytes, 1
|
910
|
+
repeated :key, TsCell, 2
|
911
|
+
optional :timeout, :uint32, 3
|
912
|
+
end
|
913
|
+
|
914
|
+
class TsGetResp
|
915
|
+
repeated :columns, TsColumnDescription, 1
|
916
|
+
repeated :rows, TsRow, 2
|
917
|
+
end
|
918
|
+
|
919
|
+
class TsPutReq
|
920
|
+
required :table, :bytes, 1
|
921
|
+
repeated :columns, TsColumnDescription, 2
|
922
|
+
repeated :rows, TsRow, 3
|
923
|
+
end
|
924
|
+
|
925
|
+
class TsPutResp
|
926
|
+
end
|
927
|
+
|
928
|
+
class TsDelReq
|
929
|
+
required :table, :bytes, 1
|
930
|
+
repeated :key, TsCell, 2
|
931
|
+
optional :vclock, :bytes, 3
|
932
|
+
optional :timeout, :uint32, 4
|
933
|
+
end
|
934
|
+
|
935
|
+
class TsDelResp
|
936
|
+
end
|
937
|
+
|
938
|
+
class TsInterpolation
|
939
|
+
required :base, :bytes, 1
|
940
|
+
repeated :interpolations, RpbPair, 2
|
941
|
+
end
|
942
|
+
|
943
|
+
class TsColumnDescription
|
944
|
+
required :name, :bytes, 1
|
945
|
+
required :type, TsColumnType, 2
|
946
|
+
end
|
947
|
+
|
948
|
+
class TsRow
|
949
|
+
repeated :cells, TsCell, 1
|
950
|
+
end
|
951
|
+
|
952
|
+
class TsCell
|
953
|
+
optional :varchar_value, :bytes, 1
|
954
|
+
optional :sint64_value, :sint64, 2
|
955
|
+
optional :timestamp_value, :sint64, 3
|
956
|
+
optional :boolean_value, :bool, 4
|
957
|
+
optional :double_value, :double, 5
|
958
|
+
end
|
959
|
+
|
960
|
+
class TsListKeysReq
|
961
|
+
required :table, :bytes, 1
|
962
|
+
optional :timeout, :uint32, 2
|
963
|
+
end
|
964
|
+
|
965
|
+
class TsListKeysResp
|
966
|
+
repeated :keys, TsRow, 1
|
967
|
+
optional :done, :bool, 2
|
968
|
+
end
|
769
969
|
|
770
970
|
end
|
771
971
|
end
|
@@ -49,8 +49,7 @@ module Riak
|
|
49
49
|
pbuf.indexes.each {|pair| decode_index(pair, rcontent.indexes) }
|
50
50
|
end
|
51
51
|
if pbuf.last_mod.present?
|
52
|
-
rcontent.last_modified = Time.at(pbuf.last_mod)
|
53
|
-
rcontent.last_modified += pbuf.last_mod_usecs / 1000000 if pbuf.last_mod_usecs.present?
|
52
|
+
rcontent.last_modified = Time.at(pbuf.last_mod, pbuf.last_mod_usecs || 0)
|
54
53
|
end
|
55
54
|
rcontent
|
56
55
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative './ts_cell_codec'
|
2
|
+
require_relative './operator'
|
3
|
+
|
4
|
+
class Riak::Client::BeefcakeProtobuffsBackend
|
5
|
+
def time_series_delete_operator
|
6
|
+
TimeSeriesDeleteOperator.new(self)
|
7
|
+
end
|
8
|
+
|
9
|
+
class TimeSeriesDeleteOperator < Operator
|
10
|
+
def delete(table_name, key_components, options = {})
|
11
|
+
codec = TsCellCodec.new
|
12
|
+
|
13
|
+
request_options = options.merge(table: table_name,
|
14
|
+
key: codec.cells_for(key_components))
|
15
|
+
|
16
|
+
request = TsDelReq.new request_options
|
17
|
+
|
18
|
+
backend.protocol do |p|
|
19
|
+
p.write :TsDelReq, request
|
20
|
+
p.expect :TsDelResp, TsDelResp, empty_body_acceptable: true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative './ts_cell_codec'
|
2
|
+
require_relative './operator'
|
3
|
+
|
4
|
+
class Riak::Client::BeefcakeProtobuffsBackend
|
5
|
+
def time_series_get_operator
|
6
|
+
TimeSeriesGetOperator.new(self)
|
7
|
+
end
|
8
|
+
|
9
|
+
class TimeSeriesGetOperator < Operator
|
10
|
+
def get(table_name, key_components, options = {})
|
11
|
+
codec = TsCellCodec.new
|
12
|
+
|
13
|
+
request_options = options.merge(table: table_name,
|
14
|
+
key: codec.cells_for(key_components))
|
15
|
+
|
16
|
+
request = TsGetReq.new request_options
|
17
|
+
|
18
|
+
result = begin
|
19
|
+
backend.protocol do |p|
|
20
|
+
p.write :TsGetReq, request
|
21
|
+
result = p.expect :TsGetResp, TsGetResp, empty_body_acceptable: true
|
22
|
+
end
|
23
|
+
rescue Riak::ProtobuffsErrorResponse => e
|
24
|
+
raise unless e.code == 10
|
25
|
+
return nil
|
26
|
+
end
|
27
|
+
|
28
|
+
return nil if result == :empty
|
29
|
+
|
30
|
+
Riak::TimeSeries::Collection.new(result.rows.map do |row|
|
31
|
+
Riak::TimeSeries::Row.new codec.scalars_for row.cells
|
32
|
+
end.to_a)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative './ts_cell_codec'
|
2
|
+
require_relative './operator'
|
3
|
+
|
4
|
+
class Riak::Client::BeefcakeProtobuffsBackend
|
5
|
+
def time_series_list_operator
|
6
|
+
TimeSeriesListOperator.new(self)
|
7
|
+
end
|
8
|
+
|
9
|
+
class TimeSeriesListOperator < Operator
|
10
|
+
def list(table_name, block, options = { })
|
11
|
+
request = TsListKeysReq.new options.merge(table: table_name)
|
12
|
+
|
13
|
+
return streaming_list_keys(request, &block) unless block.nil?
|
14
|
+
|
15
|
+
Riak::TimeSeries::Collection.new.tap do |key_buffer|
|
16
|
+
streaming_list_keys(request) do |key_row|
|
17
|
+
key_buffer << key_row
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def streaming_list_keys(request)
|
25
|
+
backend.protocol do |p|
|
26
|
+
p.write :TsListKeysReq, request
|
27
|
+
|
28
|
+
codec = TsCellCodec.new
|
29
|
+
|
30
|
+
while resp = p.expect(:TsListKeysResp, TsListKeysResp)
|
31
|
+
break if resp.done
|
32
|
+
resp.keys.each do |row|
|
33
|
+
key_fields = codec.scalars_for row.cells
|
34
|
+
yield key_fields
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative './ts_cell_codec'
|
2
|
+
require_relative './operator'
|
3
|
+
|
4
|
+
class Riak::Client::BeefcakeProtobuffsBackend
|
5
|
+
def time_series_put_operator
|
6
|
+
TimeSeriesPutOperator.new(self)
|
7
|
+
end
|
8
|
+
|
9
|
+
class TimeSeriesPutOperator < Operator
|
10
|
+
def put(table_name, measurements)
|
11
|
+
rows = rows_for measurements
|
12
|
+
|
13
|
+
request = TsPutReq.new table: table_name, rows: rows
|
14
|
+
|
15
|
+
backend.protocol do |p|
|
16
|
+
p.write :TsPutReq, request
|
17
|
+
p.expect :TsPutResp, TsPutResp, empty_body_acceptable: true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def rows_for(measurements)
|
23
|
+
codec = TsCellCodec.new
|
24
|
+
measurements.map do |measurement|
|
25
|
+
# expect a measurement to be mappable
|
26
|
+
TsRow.new(cells: measurement.map do |measure|
|
27
|
+
codec.cell_for measure
|
28
|
+
end)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative './ts_cell_codec'
|
2
|
+
require_relative './operator'
|
3
|
+
|
4
|
+
class Riak::Client::BeefcakeProtobuffsBackend
|
5
|
+
def time_series_query_operator
|
6
|
+
TimeSeriesQueryOperator.new(self)
|
7
|
+
end
|
8
|
+
|
9
|
+
class TimeSeriesQueryOperator < Operator
|
10
|
+
def query(base, interpolations = { })
|
11
|
+
interpolator = TsInterpolation.new base: base
|
12
|
+
interpolator.interpolations = pairs_for interpolations
|
13
|
+
|
14
|
+
request = TsQueryReq.new query: interpolator
|
15
|
+
|
16
|
+
result = backend.protocol do |p|
|
17
|
+
p.write :TsQueryReq, request
|
18
|
+
p.expect :TsQueryResp, TsQueryResp, empty_body_acceptable: true
|
19
|
+
end
|
20
|
+
|
21
|
+
return nil if :empty == result
|
22
|
+
|
23
|
+
codec = TsCellCodec.new
|
24
|
+
|
25
|
+
collection = Riak::TimeSeries::Collection.
|
26
|
+
new(result.rows.map do |row|
|
27
|
+
Riak::TimeSeries::Row.new codec.scalars_for row.cells
|
28
|
+
end)
|
29
|
+
|
30
|
+
collection.columns = result.columns
|
31
|
+
|
32
|
+
collection
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def pairs_for(interpolations)
|
37
|
+
interpolations.map do |key, value|
|
38
|
+
RpbPair.new key: key.to_s, value: value.to_s
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
|
3
|
+
class Riak::Client::BeefcakeProtobuffsBackend
|
4
|
+
class TsCellCodec
|
5
|
+
def cells_for(measures)
|
6
|
+
measures.map{ |m| cell_for m }
|
7
|
+
end
|
8
|
+
|
9
|
+
def scalars_for(cells)
|
10
|
+
cells.map{ |c| scalar_for c }
|
11
|
+
end
|
12
|
+
|
13
|
+
def cell_for(measure)
|
14
|
+
TsCell.new case measure
|
15
|
+
when String
|
16
|
+
{ varchar_value: measure }
|
17
|
+
when Fixnum
|
18
|
+
{ sint64_value: measure }
|
19
|
+
when Bignum
|
20
|
+
{ sint64_value: check_bignum_range(measure) }
|
21
|
+
when Float
|
22
|
+
{ double_value: measure }
|
23
|
+
when BigDecimal
|
24
|
+
{ double_value: measure.to_f }
|
25
|
+
when Rational
|
26
|
+
fail Riak::TimeSeriesError::SerializeRationalNumberError
|
27
|
+
when Complex
|
28
|
+
fail Riak::TimeSeriesError::SerializeComplexNumberError
|
29
|
+
when Time
|
30
|
+
seconds = measure.to_f
|
31
|
+
milliseconds = seconds * 1000
|
32
|
+
truncated_ms = milliseconds.to_i
|
33
|
+
{ timestamp_value: truncated_ms }
|
34
|
+
when TrueClass, FalseClass
|
35
|
+
{ boolean_value: measure }
|
36
|
+
when nil
|
37
|
+
{ }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def scalar_for(cell)
|
42
|
+
cell.varchar_value ||
|
43
|
+
cell.sint64_value ||
|
44
|
+
cell.double_value ||
|
45
|
+
timestamp(cell) ||
|
46
|
+
cell.boolean_value # boolean_value is last, so we can get either false, nil, or true
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def check_bignum_range(bignum)
|
51
|
+
if (bignum > -0x8000000000000000) && (bignum < 0x7FFFFFFFFFFFFFFF)
|
52
|
+
return bignum
|
53
|
+
end
|
54
|
+
|
55
|
+
fail Riak::TimeSeriesError::SerializeBigIntegerError, bignum
|
56
|
+
end
|
57
|
+
|
58
|
+
def timestamp(cell)
|
59
|
+
return false unless cell.timestamp_value.is_a? Integer
|
60
|
+
Time.at(cell.timestamp_value.to_f / 1000)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -16,6 +16,11 @@ module Riak
|
|
16
16
|
require 'riak/client/beefcake/bucket_properties_operator'
|
17
17
|
require 'riak/client/beefcake/crdt_operator'
|
18
18
|
require 'riak/client/beefcake/crdt_loader'
|
19
|
+
require 'riak/client/beefcake/time_series_delete_operator'
|
20
|
+
require 'riak/client/beefcake/time_series_get_operator'
|
21
|
+
require 'riak/client/beefcake/time_series_list_operator'
|
22
|
+
require 'riak/client/beefcake/time_series_put_operator'
|
23
|
+
require 'riak/client/beefcake/time_series_query_operator'
|
19
24
|
require 'riak/client/beefcake/protocol'
|
20
25
|
require 'riak/client/beefcake/socket'
|
21
26
|
true
|
data/lib/riak/client.rb
CHANGED
@@ -21,6 +21,7 @@ require 'riak/multiget'
|
|
21
21
|
require 'riak/secondary_index'
|
22
22
|
require 'riak/search'
|
23
23
|
require 'riak/stamp'
|
24
|
+
require 'riak/time_series'
|
24
25
|
require 'riak/list_buckets'
|
25
26
|
|
26
27
|
module Riak
|
@@ -356,6 +357,8 @@ module Riak
|
|
356
357
|
begin
|
357
358
|
yield backend
|
358
359
|
rescue *NETWORK_ERRORS => e
|
360
|
+
Riak.logger.warn("Riak client error: #{e.inspect} for #{backend.inspect}")
|
361
|
+
|
359
362
|
# Network error.
|
360
363
|
tries -= 1
|
361
364
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'riak/errors/base'
|
2
|
+
|
3
|
+
module Riak
|
4
|
+
class TimeSeriesError < Error
|
5
|
+
class SerializeComplexNumberError < TimeSeriesError
|
6
|
+
def initialize
|
7
|
+
super t('time_series.serialize_complex_number')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class SerializeRationalNumberError < TimeSeriesError
|
12
|
+
def initialize
|
13
|
+
super t('time_series.serialize_rational_number')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class SerializeBigIntegerError < TimeSeriesError
|
18
|
+
def initialize(bignum)
|
19
|
+
super t('time_series.serialize_big_integer', bignum: bignum)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/riak/locale/en.yml
CHANGED
@@ -97,6 +97,11 @@ en:
|
|
97
97
|
stored_function_invalid: "function must have :bucket and :key when a hash"
|
98
98
|
streaming_bucket_list_without_block: "Streaming bucket list was requested but no block was given."
|
99
99
|
string_type: "invalid_argument %{string} is not a String"
|
100
|
+
time_series:
|
101
|
+
list_keys: "Riak::TimeSeries::List is an expensive operation that should not be used in production.\n %{backtrace}"
|
102
|
+
serialize_big_integer: "%{bignum} is out of range for sint64 field"
|
103
|
+
serialize_complex_number: "Cannot serialize Complex numbers"
|
104
|
+
serialize_rational_number: "Cannot serialize Rational numbers without losing precision"
|
100
105
|
too_few_arguments: "too few arguments: %{params}"
|
101
106
|
walk_spec_invalid_unless_link: "WalkSpec is only valid for a function when the type is :link"
|
102
107
|
wrong_argument_count_walk_spec: "wrong number of arguments (one Hash or bucket,tag,keep required)"
|