eurydice 1.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,217 @@
1
+ # encoding: utf-8
2
+
3
+ module Eurydice
4
+ module Pelops
5
+ class ColumnFamily
6
+ include ExceptionHelpers
7
+ include ByteHelpers
8
+
9
+ attr_reader :name, :keyspace
10
+
11
+ def initialize(keyspace, name)
12
+ @keyspace, @name = keyspace, name
13
+ end
14
+
15
+ def definition(reload=true)
16
+ @definition = nil if reload
17
+ @definition ||= @keyspace.definition(true)[:column_families][@name]
18
+ end
19
+
20
+ def exists?
21
+ !!definition(true)
22
+ end
23
+
24
+ def create!(options={})
25
+ thrift_exception_handler do
26
+ @keyspace.column_family_manger.add_column_family(Cassandra::CfDef.from_h(options.merge(:keyspace => @keyspace.name, :name => @name)))
27
+ end
28
+ end
29
+
30
+ def drop!
31
+ thrift_exception_handler do
32
+ @keyspace.column_family_manger.drop_column_family(@name)
33
+ end
34
+ end
35
+
36
+ def truncate!
37
+ thrift_exception_handler do
38
+ @keyspace.column_family_manger.truncate_column_family(@name)
39
+ end
40
+ end
41
+
42
+ def delete(row_key, options={})
43
+ thrift_exception_handler do
44
+ deletor = @keyspace.create_row_deletor
45
+ deletor.delete_row(@name, row_key, get_cl(options))
46
+ end
47
+ end
48
+
49
+ def delete_column(row_key, column_key, options={})
50
+ thrift_exception_handler do
51
+ mutator = @keyspace.create_mutator
52
+ mutator.delete_column(@name, row_key, to_pelops_bytes(column_key))
53
+ mutator.execute(get_cl(options))
54
+ end
55
+ end
56
+
57
+ def delete_columns(row_key, column_keys, options={})
58
+ thrift_exception_handler do
59
+ mutator = @keyspace.create_mutator
60
+ mutator.delete_columns(@name, row_key, column_keys.map { |k| to_pelops_bytes(k) })
61
+ mutator.execute(get_cl(options))
62
+ end
63
+ end
64
+
65
+ def update(row_key, properties, options={})
66
+ thrift_exception_handler do
67
+ types = options[:validations] || {}
68
+ key_type = options[:comparator]
69
+ mutator = @keyspace.create_mutator
70
+ columns = properties.map do |k, v|
71
+ key = to_pelops_bytes(k, key_type)
72
+ value = to_pelops_bytes(v, types[k])
73
+ ttl = options.fetch(:ttl, mutator.class::NO_TTL)
74
+ mutator.new_column(key, value, ttl)
75
+ end
76
+ mutator.write_columns(@name, row_key, columns)
77
+ mutator.execute(get_cl(options))
78
+ end
79
+ end
80
+ alias_method :insert, :update
81
+
82
+ def key?(row_key, options={})
83
+ thrift_exception_handler do
84
+ selector = @keyspace.create_selector
85
+ predicate = Cassandra::SlicePredicate.new
86
+ count = selector.get_column_count(@name, row_key, get_cl(options))
87
+ count > 0
88
+ end
89
+ end
90
+ alias_method :row_exists?, :key?
91
+
92
+ def get(row_or_rows, options={})
93
+ case row_or_rows
94
+ when Array then get_multi(row_or_rows, options)
95
+ else get_single(row_or_rows, options)
96
+ end
97
+ end
98
+ alias_method :get_row, :get
99
+ alias_method :get_rows, :get
100
+
101
+ def get_column(row_key, column_key, options={})
102
+ thrift_exception_handler do
103
+ selector = @keyspace.create_selector
104
+ column = selector.get_column_from_row(@name, row_key, column_key, get_cl(options))
105
+ byte_array_to_s(column.get_value)
106
+ end
107
+ rescue NotFoundError => e
108
+ nil
109
+ end
110
+
111
+ def each_column(row_key, options={})
112
+ thrift_exception_handler do
113
+ reversed = options.fetch(:reversed, false)
114
+ batch_size = options.fetch(:batch_size, 100)
115
+ start_beyond = options.fetch(:start_beyond, nil)
116
+ start_beyond = to_pelops_bytes(start_beyond) if start_beyond
117
+ selector = @keyspace.create_selector
118
+ iterator = selector.iterate_columns_from_row(@name, to_pelops_bytes(row_key), start_beyond, reversed, batch_size, get_cl(options))
119
+ if block_given?
120
+ iterator.each do |column|
121
+ yield column_to_kv(column, options)
122
+ end
123
+ else
124
+ Enumerator.new do |y|
125
+ iterator.each do |column|
126
+ y << column_to_kv(column, options)
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ def get_indexed(column_key, operator, value, options={})
134
+ thrift_exception_handler do
135
+ selector = @keyspace.create_selector
136
+ op = Cassandra::INDEX_OPERATORS[operator]
137
+ max_rows = options.fetch(:max_row_count, 20)
138
+ types = options[:validations] || {}
139
+ key_type = options[:comparator]
140
+ raise ArgumentError, %(Unsupported index operator: "#{operator}") unless op
141
+ index_expression = selector.class.new_index_expression(to_pelops_bytes(column_key, key_type), op, to_pelops_bytes(value, types[column_key]))
142
+ index_clause = selector.class.new_index_clause(empty_pelops_bytes, max_rows, index_expression)
143
+ column_predicate = create_column_predicate(options)
144
+ rows = selector.get_indexed_columns(@name, index_clause, column_predicate, get_cl(options))
145
+ rows_to_h(rows, options)
146
+ end
147
+ end
148
+
149
+ private
150
+
151
+ def get_single(row_key, options={})
152
+ thrift_exception_handler do
153
+ selector = @keyspace.create_selector
154
+ column_predicate = create_column_predicate(options)
155
+ columns = selector.get_columns_from_row(@name, to_pelops_bytes(row_key), column_predicate, get_cl(options))
156
+ columns_to_h(columns, options)
157
+ end
158
+ end
159
+
160
+ def get_multi(row_keys, options={})
161
+ thrift_exception_handler do
162
+ selector = @keyspace.create_selector
163
+ column_predicate = create_column_predicate(options)
164
+ byte_row_keys = row_keys.map { |rk| to_pelops_bytes(rk) }
165
+ rows = selector.get_columns_from_rows(@name, byte_row_keys, column_predicate, get_cl(options))
166
+ rows_to_h(rows, options)
167
+ end
168
+ end
169
+
170
+ def create_column_predicate(options)
171
+ max_column_count = options.fetch(:max_column_count, java.lang.Integer::MAX_VALUE)
172
+ reversed = options.fetch(:reversed, false)
173
+ case options[:columns]
174
+ when Range
175
+ ::Pelops::Selector.new_columns_predicate(to_pelops_bytes(options[:columns].begin), to_pelops_bytes(options[:columns].end), reversed, max_column_count)
176
+ when Array
177
+ ::Pelops::Selector.new_columns_predicate(*options[:columns].map { |col| to_pelops_bytes(col) })
178
+ else
179
+ ::Pelops::Selector.new_columns_predicate_all(reversed, max_column_count)
180
+ end
181
+ end
182
+
183
+ def rows_to_h(rows, options)
184
+ rows.reduce({}) do |acc, (row_key, columns)|
185
+ columns_h = columns_to_h(columns, options)
186
+ acc[pelops_bytes_to_s(row_key)] = columns_h if columns_h && !columns_h.empty?
187
+ acc
188
+ end
189
+ end
190
+
191
+ def columns_to_h(columns, options)
192
+ if columns.empty?
193
+ nil
194
+ else
195
+ columns.reduce({}) do |acc, column|
196
+ key, value = column_to_kv(column, options)
197
+ acc[key] = value
198
+ acc
199
+ end
200
+ end
201
+ end
202
+
203
+ def column_to_kv(column, options)
204
+ types = options[:validations] || {}
205
+ key_type = options[:comparator]
206
+ key = byte_array_to_s(column.get_name, key_type)
207
+ value = byte_array_to_s(column.get_value, types[key])
208
+ return key, value
209
+ end
210
+
211
+ def get_cl(options)
212
+ cl = options.fetch(:consistency_level, options.fetch(:cl, :one))
213
+ Cassandra::CONSISTENCY_LEVELS[cl]
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,75 @@
1
+ # encoding: utf-8
2
+
3
+ module Eurydice
4
+ module Pelops
5
+ class Keyspace
6
+ include ExceptionHelpers
7
+
8
+ attr_reader :name
9
+
10
+ def initialize(name, cluster, pool_name, driver)
11
+ @name = name
12
+ @cluster = cluster
13
+ @pool_name = pool_name
14
+ @driver = driver
15
+ end
16
+
17
+ def definition(reload=false)
18
+ thrift_exception_handler do
19
+ @definition = nil if reload
20
+ @definition ||= keyspace_manager.get_keyspace_schema(@name).to_h
21
+ @definition
22
+ end
23
+ end
24
+
25
+ def exists?
26
+ keyspace_manager.keyspace_names.map { |ks_def| ks_def.name }.include?(@name)
27
+ end
28
+
29
+ def create!(options={})
30
+ thrift_exception_handler do
31
+ ks_def = Cassandra::KsDef.from_h({:strategy_class => 'org.apache.cassandra.locator.LocalStrategy'}.merge(options).merge(:name => @name))
32
+ keyspace_manager.add_keyspace(ks_def)
33
+ @driver.add_pool(@pool_name, @cluster, @name)
34
+ end
35
+ end
36
+
37
+ def drop!
38
+ keyspace_manager.drop_keyspace(@name)
39
+ rescue Exception => e
40
+ transform_thrift_exception(e)
41
+ end
42
+
43
+ def column_families(reload=false)
44
+ definition(reload)[:column_families].keys
45
+ end
46
+
47
+ def column_family(name, options={})
48
+ create = options.fetch(:create, true)
49
+ cf = ColumnFamily.new(self, name)
50
+ cf.create! if create && !cf.exists?
51
+ cf
52
+ end
53
+
54
+ def create_mutator
55
+ @driver.create_mutator(@pool_name)
56
+ end
57
+
58
+ def create_selector
59
+ @driver.create_selector(@pool_name)
60
+ end
61
+
62
+ def create_row_deletor
63
+ @driver.create_row_deletor(@pool_name)
64
+ end
65
+
66
+ def keyspace_manager
67
+ @keyspace_manager ||= @driver.create_keyspace_manager(@cluster)
68
+ end
69
+
70
+ def column_family_manger
71
+ @column_family_manger ||= @driver.create_column_family_manager(@cluster, @name)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,124 @@
1
+ # encoding: utf-8
2
+
3
+ require 'pelops-jars'
4
+ require 'eurydice'
5
+ require 'cassandra'
6
+
7
+
8
+ module Pelops
9
+ import 'org.scale7.cassandra.pelops.Cluster'
10
+ import 'org.scale7.cassandra.pelops.Pelops'
11
+ import 'org.scale7.cassandra.pelops.Selector'
12
+ import 'org.scale7.cassandra.pelops.Bytes'
13
+ import 'org.scale7.cassandra.pelops.exceptions.InvalidRequestException'
14
+ import 'org.scale7.cassandra.pelops.exceptions.NotFoundException'
15
+ import 'org.scale7.cassandra.pelops.exceptions.ApplicationException'
16
+ end
17
+
18
+ module Eurydice
19
+ def self.connect
20
+ Pelops.connect
21
+ end
22
+
23
+ def self.disconnect!
24
+ Pelops.disconnect!
25
+ end
26
+
27
+ module Pelops
28
+ def self.connect(options={})
29
+ host = options.fetch(:host, 'localhost')
30
+ port = options.fetch(:port, 9160)
31
+ pool_name = options.fetch(:pool_name, 'eurydice')
32
+ Cluster.new(::Pelops::Cluster.new(host, port))
33
+ end
34
+
35
+ def self.keyspace(keyspace_name, host='localhost', port=9160, pool_name='eurydice')
36
+ cluster = ::Pelops::Cluster.new(host, port)
37
+ ::Pelops::Pelops.add_pool(pool_name, cluster, keyspace_name)
38
+ Keyspace.new(keyspace_name, cluster, pool_name)
39
+ end
40
+
41
+ def self.disconnect!
42
+ ::Pelops::Pelops.shutdown
43
+ end
44
+
45
+ module ByteHelpers
46
+ extend self
47
+
48
+ def empty_pelops_bytes
49
+ ::Pelops::Bytes::EMPTY
50
+ end
51
+
52
+ def to_pelops_bytes(obj, type=nil)
53
+ case type
54
+ when :long
55
+ ::Pelops::Bytes.from_long(obj)
56
+ else
57
+ ::Pelops::Bytes.new(obj.to_s.to_java_bytes)
58
+ end
59
+ end
60
+
61
+ def to_nio_bytes(str)
62
+ to_pelops_bytes(str).bytes
63
+ end
64
+
65
+ def to_byte_array(str)
66
+ str.to_java_bytes
67
+ end
68
+
69
+ def pelops_bytes_to_s(pb)
70
+ String.from_java_bytes(pb.to_byte_array)
71
+ end
72
+
73
+ def nio_bytes_to_s(nb)
74
+ pelops_bytes_to_s(::Pelops::Bytes.new(nb))
75
+ end
76
+
77
+ def byte_array_to_s(ba, type=nil)
78
+ case type
79
+ when :long
80
+ ::Pelops::Bytes.new(ba).to_long
81
+ else
82
+ String.from_java_bytes(ba)
83
+ end
84
+ end
85
+ end
86
+
87
+ module ExceptionHelpers
88
+ def transform_thrift_exception(e)
89
+ if e.respond_to?(:cause)
90
+ case e.cause
91
+ when Cassandra::InvalidRequestException, ::Pelops::InvalidRequestException
92
+ message = e.cause.why
93
+ backtrace = e.backtrace
94
+ error_class = begin
95
+ case message
96
+ when /Keyspace already exists/
97
+ then KeyspaceExistsError
98
+ else InvalidRequestError
99
+ end
100
+ end
101
+ raise error_class, message, backtrace
102
+ when ::Pelops::NotFoundException
103
+ raise NotFoundError, e.cause.message, e.backtrace
104
+ when ::Pelops::ApplicationException
105
+ raise EurydiceError, e.cause.message, e.backtrace
106
+ when Thrift::TTransportException
107
+ raise TimeoutError, e.cause.message, e.backtrace
108
+ end
109
+ end
110
+ raise e
111
+ end
112
+
113
+ def thrift_exception_handler
114
+ yield
115
+ rescue Exception => e
116
+ transform_thrift_exception(e)
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ require_relative 'pelops/cluster'
123
+ require_relative 'pelops/keyspace'
124
+ require_relative 'pelops/column_family'
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ module Eurydice
5
+ VERSION = '1.0.0'
6
+ end
data/lib/eurydice.rb ADDED
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ require 'java'
4
+ require 'eurydice/pelops'
5
+
6
+ module Eurydice
7
+ class EurydiceError < StandardError; end
8
+ class InvalidRequestError < EurydiceError; end
9
+ class KeyspaceExistsError < InvalidRequestError; end
10
+ class NotFoundError < EurydiceError; end
11
+ class TimeoutError < EurydiceError; end
12
+ end
@@ -0,0 +1,39 @@
1
+ require_relative '../../spec_helper'
2
+
3
+
4
+ module Eurydice
5
+ module Pelops
6
+ describe Cluster do
7
+ it 'can connect' do
8
+ @cluster = Eurydice.connect
9
+ @cluster.should be_connected
10
+ end
11
+
12
+ describe '#keyspace' do
13
+ before do
14
+ @cluster = Eurydice.connect
15
+ @keyspace_name = "eurydice_test_space_#{rand(1000)}"
16
+ if @cluster.keyspaces.include?(@keyspace_name)
17
+ @cluster.keyspace(@keyspace_name).drop!
18
+ end
19
+ end
20
+
21
+ after do
22
+ @keyspace.drop! rescue nil
23
+ end
24
+
25
+ it 'creates a keyspace' do
26
+ @keyspace = @cluster.keyspace(@keyspace_name)
27
+ @keyspace.exists?.should be_true
28
+ end
29
+
30
+ it 'defers the creation of a keyspace with :create => false' do
31
+ @keyspace = @cluster.keyspace(@keyspace_name, :create => false)
32
+ @keyspace.exists?.should be_false
33
+ @keyspace.create!
34
+ @keyspace.exists?.should be_true
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end