eurydice 1.0.0-java

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.
@@ -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