sessionm-cassandra_object 2.7.5 → 4.0.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/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +5 -3
- data/config/boot.rb +9 -0
- data/config/cassandra.yml +36 -0
- data/config/environment.rb +17 -0
- data/lib/cassandra_object.rb +1 -0
- data/lib/cassandra_object/adapters.rb +7 -0
- data/lib/cassandra_object/adapters/cassandra_driver.rb +121 -0
- data/lib/cassandra_object/associations.rb +8 -5
- data/lib/cassandra_object/attributes.rb +12 -12
- data/lib/cassandra_object/base.rb +1 -1
- data/lib/cassandra_object/connection.rb +29 -156
- data/lib/cassandra_object/consistency.rb +5 -5
- data/lib/cassandra_object/finder_methods.rb +14 -17
- data/lib/cassandra_object/migrations.rb +7 -5
- data/lib/cassandra_object/mocking.rb +1 -6
- data/lib/cassandra_object/nested_attributes.rb +2 -1
- data/lib/cassandra_object/schema/migrator.rb +1 -1
- data/lib/cassandra_object/tasks/column_family.rb +1 -0
- data/lib/cassandra_object/tasks/ks.rake +1 -3
- data/script/console.rb +16 -0
- data/sessionm-cassandra_object.gemspec +2 -2
- data/test/consistency_test.rb +2 -2
- data/test/persistence_test.rb +2 -2
- metadata +12 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8c030402fac23c1c5582c18fb390760fafad77b
|
4
|
+
data.tar.gz: 153e5739c2ca48e426e244c9644386729c90d663
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 34bc064fa9b47e01e82deedd7c76ae77b981671bcb3f7e7cc13046e76d3a0732363851ca82fe77e73c37dcd5c03df20c63397e62f8c55be4338abccf8ec2cb80
|
7
|
+
data.tar.gz: 05abb454e907e44fa7defc4b98a1077449c5a38d6e032f1b49a141df72431c568af2a0371590fa79ae9b44897ff5911a5716add7442ea8e74fc38a5323dde593
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
cassandra_object
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.2.0
|
data/Gemfile
CHANGED
data/config/boot.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
development: &id001
|
2
|
+
servers: ['127.0.0.1:9160']
|
3
|
+
keyspace: greyhound_development
|
4
|
+
replication:
|
5
|
+
strategy: org.apache.cassandra.locator.SimpleStrategy
|
6
|
+
factor: 1
|
7
|
+
consistency:
|
8
|
+
read_default: quorum
|
9
|
+
write_default: quorum
|
10
|
+
column_family_defaults:
|
11
|
+
compaction_strategy: org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy
|
12
|
+
row_cache_provider: org.apache.cassandra.cache.ConcurrentLinkedHashCacheProvider
|
13
|
+
thrift:
|
14
|
+
connect_timeout: 0.5
|
15
|
+
timeout: 3
|
16
|
+
retries: 2
|
17
|
+
production: *id001
|
18
|
+
test:
|
19
|
+
servers: ['127.0.0.1:9160']
|
20
|
+
keyspace: greyhound_test
|
21
|
+
replication:
|
22
|
+
strategy: org.apache.cassandra.locator.SimpleStrategy
|
23
|
+
factor: 1
|
24
|
+
consistency:
|
25
|
+
read_default: quorum
|
26
|
+
write_default: quorum
|
27
|
+
column_family_defaults:
|
28
|
+
compaction_strategy: org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy
|
29
|
+
row_cache_provider: org.apache.cassandra.cache.ConcurrentLinkedHashCacheProvider
|
30
|
+
thrift:
|
31
|
+
connect_timeout: 0.5
|
32
|
+
timeout: 3
|
33
|
+
retries: 2
|
34
|
+
exception_class_overrides:
|
35
|
+
- CassandraThrift::InvalidRequestException
|
36
|
+
- CassandraThrift::NotFoundException
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path('../boot', __FILE__)
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
ENV['RAILS_ENV'] ||= 'development'
|
5
|
+
|
6
|
+
Bundler.require :default, ENV['RAILS_ENV']
|
7
|
+
|
8
|
+
BASE_DIR = Pathname.new(File.expand_path('../..', __FILE__))
|
9
|
+
|
10
|
+
CASSANDRA_YAML = "#{BASE_DIR}/config/cassandra.yml"
|
11
|
+
|
12
|
+
DEFAULT_LOG_FILE = "#{BASE_DIR}/log/#{ENV['RAILS_ENV']}.log"
|
13
|
+
|
14
|
+
$LOAD_PATH << File.expand_path('../../lib', __FILE__)
|
15
|
+
require 'cassandra_object'
|
16
|
+
|
17
|
+
CassandraObject::Base.config = YAML.load_file(CASSANDRA_YAML)[ENV['RAILS_ENV']]
|
data/lib/cassandra_object.rb
CHANGED
@@ -0,0 +1,121 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
module Adapters
|
3
|
+
class CassandraDriver
|
4
|
+
attr_reader :config
|
5
|
+
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def cluster
|
11
|
+
@cluster ||= Cassandra.cluster cluster_config
|
12
|
+
end
|
13
|
+
|
14
|
+
def client
|
15
|
+
@client ||= Client.new(cluster.connect(config[:keyspace]))
|
16
|
+
end
|
17
|
+
|
18
|
+
def close
|
19
|
+
@client.try(:close)
|
20
|
+
@client = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def cluster_config
|
24
|
+
{
|
25
|
+
:hosts => config[:servers].map { |server| server.sub /:\d+/, '' },
|
26
|
+
:port => config[:port] || 9042,
|
27
|
+
:connect_timeout => config[:thrift][:connect_timeout] || 10,
|
28
|
+
:timeout => config[:thrift][:timeout] || 10,
|
29
|
+
:logger => Rails.logger || Logger.new(STDOUT),
|
30
|
+
:consistency => (config[:consistency] || {})[:write_default].try(:to_sym) || :one,
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
# The client class acts like the old cassandra gem
|
35
|
+
class Client
|
36
|
+
attr_reader :session
|
37
|
+
|
38
|
+
KEY_FIELD = 'key'
|
39
|
+
NAME_FIELD = 'column1'
|
40
|
+
VALUE_FIELD = 'value'
|
41
|
+
|
42
|
+
def initialize(session)
|
43
|
+
@session = session
|
44
|
+
end
|
45
|
+
|
46
|
+
def close
|
47
|
+
session.close
|
48
|
+
end
|
49
|
+
|
50
|
+
def execute(*args)
|
51
|
+
session.execute *args
|
52
|
+
end
|
53
|
+
|
54
|
+
def execute_async(*args)
|
55
|
+
session.execute_async *args
|
56
|
+
end
|
57
|
+
|
58
|
+
def insert(column_family, key, values, opts=nil)
|
59
|
+
ttl = opts.try(:[], :ttl)
|
60
|
+
async = opts.try(:[], :async)
|
61
|
+
|
62
|
+
insert_into_options = ttl ? " USING TTL #{ttl}" : ''
|
63
|
+
key = "textAsBlob('#{key}')"
|
64
|
+
|
65
|
+
query = "BEGIN BATCH\n"
|
66
|
+
query << values.map do |name, value|
|
67
|
+
" INSERT INTO \"#{column_family}\" (#{KEY_FIELD}, #{NAME_FIELD}, #{VALUE_FIELD}) VALUES (#{key}, '#{name}', '#{value}')#{insert_into_options}"
|
68
|
+
end.join("\n")
|
69
|
+
query << "\nAPPLY BATCH;"
|
70
|
+
|
71
|
+
async ? self.execute_async(query, execute_options(opts)) : self.execute(query, execute_options(opts))
|
72
|
+
end
|
73
|
+
|
74
|
+
def get(column_family, key, *columns_options)
|
75
|
+
opts = columns_options.pop if columns_options.last.is_a?(Hash)
|
76
|
+
async = opts.try(:[], :async)
|
77
|
+
|
78
|
+
columns = columns_options.flatten.compact
|
79
|
+
|
80
|
+
key = "textAsBlob('#{key}')"
|
81
|
+
|
82
|
+
query =
|
83
|
+
if columns.size == 1
|
84
|
+
"SELECT #{VALUE_FIELD} FROM \"#{column_family}\" WHERE #{KEY_FIELD} = #{key} AND #{NAME_FIELD} = '#{columns.first}'"
|
85
|
+
else
|
86
|
+
"SELECT #{NAME_FIELD}, #{VALUE_FIELD} FROM \"#{column_family}\" WHERE #{KEY_FIELD} = #{key}"
|
87
|
+
end
|
88
|
+
|
89
|
+
result = async ? self.execute_async(query, execute_options(opts)) : self.execute(query, execute_options(opts))
|
90
|
+
return result if async
|
91
|
+
|
92
|
+
if columns.size == 1
|
93
|
+
result.size > 0 ? result.first[VALUE_FIELD] : nil
|
94
|
+
else
|
95
|
+
data = result.inject({}) { |hsh, row| hsh[row[NAME_FIELD]] = row[VALUE_FIELD]; hsh }
|
96
|
+
columns.size > 0 ? data.slice(*columns.map(&:to_s)) : data
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def add(column_family, key, by, field, opts=nil)
|
101
|
+
async = opts.try(:[], :async)
|
102
|
+
key = "textAsBlob('#{key}')"
|
103
|
+
|
104
|
+
query = "UPDATE \"#{column_family}\" SET #{VALUE_FIELD} = #{VALUE_FIELD} + #{by} WHERE #{KEY_FIELD} = #{key} AND #{NAME_FIELD} = '#{field}';"
|
105
|
+
|
106
|
+
async ? self.execute_async(query, execute_options(opts)) : self.execute(query, execute_options(opts))
|
107
|
+
end
|
108
|
+
|
109
|
+
def execute_options(opts)
|
110
|
+
opts.try(:slice,
|
111
|
+
:consistency,
|
112
|
+
:page_size,
|
113
|
+
:trace,
|
114
|
+
:timeout,
|
115
|
+
:serial_consistency
|
116
|
+
) || {}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -12,7 +12,8 @@ module CassandraObject
|
|
12
12
|
autoload :OneToOne
|
13
13
|
|
14
14
|
included do
|
15
|
-
|
15
|
+
class_attribute :associations
|
16
|
+
self.associations = {}
|
16
17
|
end
|
17
18
|
|
18
19
|
module ClassMethods
|
@@ -29,10 +30,11 @@ module CassandraObject
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def association(association_name, options= {})
|
33
|
+
self.association = self.association.dup
|
32
34
|
if options[:unique]
|
33
|
-
|
35
|
+
self.associations[association_name] = OneToOne.new(association_name, self, options)
|
34
36
|
else
|
35
|
-
|
37
|
+
self.associations[association_name] = OneToMany.new(association_name, self, options)
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
@@ -43,8 +45,9 @@ module CassandraObject
|
|
43
45
|
connection.remove(relationships_column_family, key.to_s, consistency: thrift_write_consistency)
|
44
46
|
end
|
45
47
|
end
|
46
|
-
rescue Cassandra::
|
47
|
-
|
48
|
+
rescue Cassandra::Error => e
|
49
|
+
# pretty sure this is not the correct message for cassandra-driver gem, will need to investigate the actual message
|
50
|
+
raise e unless e.message =~ /invalid column family/i
|
48
51
|
end
|
49
52
|
super
|
50
53
|
end
|
@@ -75,19 +75,19 @@ module CassandraObject
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
def method_missing(method_id, *args, &block)
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
78
|
+
# def method_missing(method_id, *args, &block)
|
79
|
+
# if !self.class.attribute_methods_generated?
|
80
|
+
# self.class.define_attribute_methods
|
81
|
+
# send(method_id, *args, &block)
|
82
|
+
# else
|
83
|
+
# super
|
84
|
+
# end
|
85
|
+
# end
|
86
86
|
|
87
|
-
def respond_to?(*args)
|
88
|
-
|
89
|
-
|
90
|
-
end
|
87
|
+
# def respond_to?(*args)
|
88
|
+
# self.class.define_attribute_methods unless self.class.attribute_methods_generated?
|
89
|
+
# super
|
90
|
+
# end
|
91
91
|
|
92
92
|
protected
|
93
93
|
def attribute_method?(name)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_record/connection_adapters/connection_specification'
|
2
2
|
|
3
3
|
module CassandraObject
|
4
4
|
module Connection
|
@@ -7,164 +7,20 @@ module CassandraObject
|
|
7
7
|
included do
|
8
8
|
class_attribute :connection_spec
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def self.new_connection(async, servers)
|
14
|
-
spec = connection_spec.dup
|
15
|
-
|
16
|
-
if async
|
17
|
-
require 'thrift_client/event_machine'
|
18
|
-
spec[:thrift] = spec[:thrift].dup.merge(:transport => Thrift::EventMachineTransport,
|
19
|
-
:transport_wrapper => nil)
|
20
|
-
end
|
21
|
-
|
22
|
-
Cassandra.new(spec[:keyspace], servers || spec[:servers], spec[:thrift]).tap do |conn|
|
23
|
-
conn.disable_node_auto_discovery! if spec[:disable_node_auto_discovery]
|
24
|
-
if spec[:cache_schema]
|
25
|
-
if @@schema
|
26
|
-
conn.instance_variable_set '@schema', @@schema
|
27
|
-
else
|
28
|
-
begin
|
29
|
-
@@schema = conn.schema
|
30
|
-
rescue CassandraThrift::InvalidRequestException => e
|
31
|
-
# initially the schema doesn't exists
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.new_async_connection(servers=nil)
|
39
|
-
new_connection true, servers
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.new_sync_connection(servers=nil)
|
43
|
-
new_connection false, servers
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.new_async_connection_pool(servers=nil)
|
47
|
-
adapter_method = Proc.new do
|
48
|
-
self.new_async_connection servers
|
49
|
-
end
|
50
|
-
spec = ActiveRecord::Base::ConnectionSpecification.new self.connection_spec, adapter_method
|
51
|
-
WithConnection::ConnectionPool.new "async cassandra", spec
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.new_sync_connection_pool(servers=nil)
|
55
|
-
adapter_method = Proc.new do
|
56
|
-
self.new_sync_connection servers
|
57
|
-
end
|
58
|
-
spec = ActiveRecord::Base::ConnectionSpecification.new self.connection_spec, adapter_method
|
59
|
-
WithConnection::ConnectionPool.new "sync cassandra", spec
|
60
|
-
end
|
61
|
-
|
62
|
-
@@ring = nil
|
63
|
-
def self.ring
|
64
|
-
@@ring ||= self.new_sync_connection.ring
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.servers_and_ranges(datacenter)
|
68
|
-
datacenter = datacenter.to_s
|
69
|
-
ring.map do |t|
|
70
|
-
{
|
71
|
-
:start_token => t.start_token.to_i,
|
72
|
-
:end_token => t.end_token.to_i == 0 ? 0xffffffffffffffffffffffffffffffff : (t.end_token.to_i - 1),
|
73
|
-
:servers => t.endpoint_details.select { |d| d.datacenter == datacenter }.map { |d| "#{d.host}:9160" }
|
74
|
-
}
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
NEGATIVE_TEST = 0x80000000000000000000000000000000
|
79
|
-
FLIP_BITS_MASK = 0xffffffffffffffffffffffffffffffff
|
80
|
-
def self.ranged_connection_pool_key_algo
|
81
|
-
Proc.new do |key|
|
82
|
-
key = Digest::MD5.hexdigest(key.to_s).to_i(16)
|
83
|
-
|
84
|
-
# https://github.com/datastax/java-driver/blob/2.0/driver-core/src/main/java/com/datastax/driver/core/Token.java:259
|
85
|
-
# test to see if the unsigned integer is a negative singed value
|
86
|
-
if (key & NEGATIVE_TEST) != 0
|
87
|
-
# need to flip all the bits
|
88
|
-
# abs
|
89
|
-
(key ^ FLIP_BITS_MASK) + 1
|
90
|
-
else
|
91
|
-
key
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def self.new_ranged_connection_pool(async)
|
97
|
-
if self.connection_spec[:datacenter]
|
98
|
-
require 'with_connection/ranged_connection_pool'
|
99
|
-
|
100
|
-
default_pool = async ? new_async_connection_pool : new_sync_connection_pool
|
101
|
-
|
102
|
-
ranges_and_pools = self.servers_and_ranges(self.connection_spec[:datacenter]).map do |info|
|
103
|
-
pool = async ? new_async_connection_pool(info[:servers]) : new_sync_connection_pool(info[:servers])
|
104
|
-
[WithConnection::RangedConnectionPool::BasicRange.new(info[:start_token], info[:end_token]), pool]
|
105
|
-
end
|
106
|
-
|
107
|
-
ranges_and_pools.size <= 1 ? default_pool : WithConnection::RangedConnectionPool.new(ranges_and_pools, default_pool, self.ranged_connection_pool_key_algo)
|
108
|
-
else
|
109
|
-
async ? new_async_connection_pool : new_sync_connection_pool
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
@@sync_connection_pool = nil
|
114
|
-
def self.sync_connection_pool
|
115
|
-
@@sync_connection_pool ||= new_ranged_connection_pool(false)
|
116
|
-
end
|
117
|
-
|
118
|
-
@@async_connection_pool = nil
|
119
|
-
def self.async_connection_pool
|
120
|
-
@@async_connection_pool ||= new_ranged_connection_pool(true)
|
121
|
-
end
|
122
|
-
|
123
|
-
if defined?(EM)
|
124
|
-
def self.connection_pool
|
125
|
-
EM.reactor_running? ? self.async_connection_pool : self.sync_connection_pool
|
126
|
-
end
|
127
|
-
else
|
128
|
-
def self.connection_pool
|
129
|
-
self.sync_connection_pool
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def connection_pool
|
134
|
-
self.class.connection_pool
|
135
|
-
end
|
136
|
-
|
137
|
-
def self.connection
|
138
|
-
self.connection_pool.connection
|
139
|
-
end
|
140
|
-
def self.connection?; !!connection; end
|
141
|
-
|
142
|
-
def self.with_connection(key=nil, read_write=nil, &block)
|
143
|
-
self.connection_pool.with_connection(key, read_write, &block)
|
144
|
-
end
|
145
|
-
|
146
|
-
def with_connection(key=nil, read_write=nil, &block)
|
147
|
-
self.class.with_connection(key, read_write, &block)
|
148
|
-
end
|
149
|
-
|
150
|
-
def self.disconnect!
|
151
|
-
self.async_connection_pool.disconnect! if @@async_connection_pool
|
152
|
-
self.sync_connection_pool.disconnect! if @@sync_connection_pool
|
153
|
-
@@sync_connection_pool = nil
|
154
|
-
@@async_connection_pool = nil
|
155
|
-
end
|
10
|
+
def connection
|
11
|
+
self.class.connection
|
12
|
+
end
|
156
13
|
|
157
|
-
|
158
|
-
|
159
|
-
|
14
|
+
def connection?
|
15
|
+
self.class.connection?
|
16
|
+
end
|
160
17
|
|
161
|
-
|
162
|
-
|
163
|
-
|
18
|
+
def disconnect!
|
19
|
+
self.class.disconnect!
|
20
|
+
end
|
164
21
|
|
165
|
-
|
166
|
-
|
167
|
-
end
|
22
|
+
def with_connection(*args)
|
23
|
+
yield
|
168
24
|
end
|
169
25
|
end
|
170
26
|
|
@@ -185,6 +41,23 @@ module CassandraObject
|
|
185
41
|
|
186
42
|
self.connection_spec = spec
|
187
43
|
end
|
44
|
+
|
45
|
+
def connection
|
46
|
+
@connection ||= CassandraObject::Adapters::CassandraDriver.new(self.connection_spec).client
|
47
|
+
end
|
48
|
+
|
49
|
+
def connection?
|
50
|
+
!! @connection
|
51
|
+
end
|
52
|
+
|
53
|
+
def disconnect!
|
54
|
+
@connection.try(:close)
|
55
|
+
@connection = nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def with_connection(*args)
|
59
|
+
yield
|
60
|
+
end
|
188
61
|
end
|
189
62
|
end
|
190
63
|
end
|
@@ -9,11 +9,11 @@ module CassandraObject
|
|
9
9
|
|
10
10
|
module ClassMethods
|
11
11
|
THRIFT_LEVELS = {
|
12
|
-
:one =>
|
13
|
-
:quorum =>
|
14
|
-
:local_quorum =>
|
15
|
-
:each_quorum =>
|
16
|
-
:all =>
|
12
|
+
:one => :one,
|
13
|
+
:quorum => :quorum,
|
14
|
+
:local_quorum => :local_quorum,
|
15
|
+
:each_quorum => :each_quorum,
|
16
|
+
:all => :all
|
17
17
|
}
|
18
18
|
|
19
19
|
DEFAULT_OPTIONS = {
|
@@ -2,22 +2,6 @@ module CassandraObject
|
|
2
2
|
module FinderMethods
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
module ClassMethods
|
5
|
-
def column_parent
|
6
|
-
@column_parent ||= CassandraThrift::ColumnParent.new(:column_family => column_family)
|
7
|
-
end
|
8
|
-
|
9
|
-
def slice_range_count
|
10
|
-
@slice_range_count ||= 100
|
11
|
-
end
|
12
|
-
|
13
|
-
def slice_range_count=(v)
|
14
|
-
@slice_range_count = v
|
15
|
-
end
|
16
|
-
|
17
|
-
def slice_predicate
|
18
|
-
@slice_predicate ||= CassandraThrift::SlicePredicate.new(:slice_range => CassandraThrift::SliceRange.new(:count => slice_range_count, :reversed => false, :start => '', :finish => ''))
|
19
|
-
end
|
20
|
-
|
21
5
|
def find(key, opts={})
|
22
6
|
# kludge to play nice ActiveRecord association
|
23
7
|
opts.assert_valid_keys(:conditions, :consistency)
|
@@ -29,7 +13,7 @@ module CassandraObject
|
|
29
13
|
begin
|
30
14
|
CassandraObject::Base.with_connection(key, :read) do
|
31
15
|
ActiveSupport::Notifications.instrument("get.cassandra_object", column_family: column_family, key: key) do
|
32
|
-
connection.get
|
16
|
+
connection.get column_family, key, opts.slice(:consistency)
|
33
17
|
end
|
34
18
|
end
|
35
19
|
end
|
@@ -102,6 +86,19 @@ module CassandraObject
|
|
102
86
|
multi_get_by_expression(expression, options).values
|
103
87
|
end
|
104
88
|
|
89
|
+
# Selecting a slice of a super column
|
90
|
+
def get_slice(key, start, finish, opts={})
|
91
|
+
CassandraObject::Base.with_connection(key, :read) do
|
92
|
+
connection.get_slice(column_family,
|
93
|
+
key,
|
94
|
+
start,
|
95
|
+
finish,
|
96
|
+
opts[:count] || 100,
|
97
|
+
opts[:reversed] || false,
|
98
|
+
opts[:consistency] || thrift_read_consistency)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
105
102
|
private
|
106
103
|
def _columns_to_hash(columns)
|
107
104
|
{}.tap do |hsh|
|
@@ -4,8 +4,9 @@ module CassandraObject
|
|
4
4
|
extend ActiveSupport::Autoload
|
5
5
|
|
6
6
|
included do
|
7
|
-
|
8
|
-
|
7
|
+
class_attribute :migrations
|
8
|
+
self.migrations = []
|
9
|
+
class_attribute :current_schema_version
|
9
10
|
self.current_schema_version = 0
|
10
11
|
end
|
11
12
|
|
@@ -29,7 +30,8 @@ module CassandraObject
|
|
29
30
|
|
30
31
|
module ClassMethods
|
31
32
|
def migrate(version, &blk)
|
32
|
-
|
33
|
+
self.migrations = self.migrations.dup
|
34
|
+
self.migrations << Migration.new(version, blk)
|
33
35
|
|
34
36
|
if version > self.current_schema_version
|
35
37
|
self.current_schema_version = version
|
@@ -60,8 +62,8 @@ module CassandraObject
|
|
60
62
|
end
|
61
63
|
|
62
64
|
super(key, attributes).tap do |record|
|
63
|
-
|
64
|
-
record.attribute_will_change!
|
65
|
+
attributes.each do |name, _|
|
66
|
+
record.attribute_will_change!(name) unless original_attributes.has_key?(name)
|
65
67
|
end
|
66
68
|
end
|
67
69
|
end
|
@@ -1,14 +1,9 @@
|
|
1
|
-
require 'cassandra/mock'
|
2
1
|
module CassandraObject
|
3
2
|
module Mocking
|
4
3
|
extend ActiveSupport::Concern
|
5
4
|
module ClassMethods
|
6
5
|
def use_mock!(really=true)
|
7
|
-
|
8
|
-
self.connection_class = Cassandra::Mock
|
9
|
-
else
|
10
|
-
self.connection_class = Cassandra
|
11
|
-
end
|
6
|
+
self.connection_class = Cassandra
|
12
7
|
end
|
13
8
|
end
|
14
9
|
end
|
@@ -11,7 +11,7 @@ module CassandraObject
|
|
11
11
|
extend ActiveSupport::Concern
|
12
12
|
|
13
13
|
included do
|
14
|
-
|
14
|
+
class_attribute :nested_attributes_options
|
15
15
|
self.nested_attributes_options = {}
|
16
16
|
end
|
17
17
|
|
@@ -28,6 +28,7 @@ module CassandraObject
|
|
28
28
|
if reflection = reflect_on_association(association_name)
|
29
29
|
reflection.options[:autosave] = true
|
30
30
|
add_autosave_association_callbacks(reflection)
|
31
|
+
self.nested_attributes_options = self.nested_attributes_options.dup
|
31
32
|
nested_attributes_options[association_name.to_sym] = options
|
32
33
|
type = (reflection.collection? ? :collection : :one_to_one)
|
33
34
|
|
@@ -50,7 +50,7 @@ module CassandraObject
|
|
50
50
|
|
51
51
|
def self.get_all_versions
|
52
52
|
cas = CassandraObject::Base.connection
|
53
|
-
cas.
|
53
|
+
cas.get(schema_migrations_column_family, 'all').map {|(name, _value)| name.to_i}.sort
|
54
54
|
end
|
55
55
|
|
56
56
|
def self.current_version
|
@@ -1,8 +1,6 @@
|
|
1
1
|
namespace :ks do
|
2
2
|
task :configure => :environment do
|
3
|
-
@configs = YAML
|
4
|
-
# use default thrift settings
|
5
|
-
@configs.each { |_, section| section.delete 'thrift' }
|
3
|
+
@configs = YAML.load_file(Rails.root.join("config", "cassandra.yml"))
|
6
4
|
@config = @configs[Rails.env || 'development']
|
7
5
|
end
|
8
6
|
|
data/script/console.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path('../../config/environment', __FILE__)
|
4
|
+
require "irb"
|
5
|
+
|
6
|
+
if __FILE__ == $0
|
7
|
+
IRB.start(__FILE__)
|
8
|
+
else
|
9
|
+
# check -e option
|
10
|
+
if /^-e$/ =~ $0
|
11
|
+
IRB.start(__FILE__)
|
12
|
+
else
|
13
|
+
IRB.setup(__FILE__)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'sessionm-cassandra_object'
|
5
|
-
s.version = '
|
5
|
+
s.version = '4.0.0'
|
6
6
|
s.description = 'Cassandra ActiveModel'
|
7
7
|
s.summary = 'Cassandra ActiveModel'
|
8
8
|
|
9
9
|
s.authors = ["Michael Koziarski", "gotime", "sessionm"]
|
10
|
-
s.email = '
|
10
|
+
s.email = 'doug@sessionm.com'
|
11
11
|
s.homepage = 'http://github.com/sessionm/cassandra_object'
|
12
12
|
|
13
13
|
s.extra_rdoc_files = ["README.markdown"]
|
data/test/consistency_test.rb
CHANGED
@@ -6,11 +6,11 @@ class CassandraObject::ConsistencyTest < CassandraObject::TestCase
|
|
6
6
|
|
7
7
|
test 'thrift_write_consistency' do
|
8
8
|
TestModel.write_consistency = :all
|
9
|
-
assert_equal
|
9
|
+
assert_equal :all, TestModel.thrift_write_consistency
|
10
10
|
end
|
11
11
|
|
12
12
|
test 'thrift_read_consistency' do
|
13
13
|
TestModel.read_consistency = :all
|
14
|
-
assert_equal
|
14
|
+
assert_equal :all, TestModel.thrift_read_consistency
|
15
15
|
end
|
16
16
|
end
|
data/test/persistence_test.rb
CHANGED
@@ -62,11 +62,11 @@ class CassandraObject::PersistenceTest < CassandraObject::TestCase
|
|
62
62
|
CassandraObject::Consistency::ClassMethods.class_variable_set(:@@default_read_consistency, :quorum)
|
63
63
|
Counter.write_consistency = nil
|
64
64
|
|
65
|
-
Counter.connection.expects(:add).with(Counter.column_family, 'key', 2, 'column', :consistency =>
|
65
|
+
Counter.connection.expects(:add).with(Counter.column_family, 'key', 2, 'column', :consistency => :quorum)
|
66
66
|
Counter.add('key', 2, 'column')
|
67
67
|
|
68
68
|
Counter.write_consistency = :local_quorum
|
69
|
-
Counter.connection.expects(:add).with(Counter.column_family, 'key', 2, 'column', :consistency =>
|
69
|
+
Counter.connection.expects(:add).with(Counter.column_family, 'key', 2, 'column', :consistency => :local_quorum)
|
70
70
|
Counter.add('key', 2, 'column')
|
71
71
|
ensure
|
72
72
|
CassandraObject::Consistency::ClassMethods.class_variable_set(:@@default_read_consistency, old_class_write_cl)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sessionm-cassandra_object
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Koziarski
|
@@ -10,23 +10,30 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2015-05-06 00:00:00.000000000 Z
|
14
14
|
dependencies: []
|
15
15
|
description: Cassandra ActiveModel
|
16
|
-
email:
|
16
|
+
email: doug@sessionm.com
|
17
17
|
executables: []
|
18
18
|
extensions: []
|
19
19
|
extra_rdoc_files:
|
20
20
|
- README.markdown
|
21
21
|
files:
|
22
22
|
- ".gitignore"
|
23
|
+
- ".ruby-gemset"
|
24
|
+
- ".ruby-version"
|
23
25
|
- CHANGELOG
|
24
26
|
- Gemfile
|
25
27
|
- LICENSE
|
26
28
|
- MIT-LICENSE
|
27
29
|
- README.markdown
|
28
30
|
- Rakefile
|
31
|
+
- config/boot.rb
|
32
|
+
- config/cassandra.yml
|
33
|
+
- config/environment.rb
|
29
34
|
- lib/cassandra_object.rb
|
35
|
+
- lib/cassandra_object/adapters.rb
|
36
|
+
- lib/cassandra_object/adapters/cassandra_driver.rb
|
30
37
|
- lib/cassandra_object/associations.rb
|
31
38
|
- lib/cassandra_object/associations/one_to_many.rb
|
32
39
|
- lib/cassandra_object/associations/one_to_one.rb
|
@@ -83,6 +90,7 @@ files:
|
|
83
90
|
- lib/cassandra_object/types/time_with_zone_type.rb
|
84
91
|
- lib/cassandra_object/types/utf8_string_type.rb
|
85
92
|
- lib/cassandra_object/validations.rb
|
93
|
+
- script/console.rb
|
86
94
|
- sessionm-cassandra_object.gemspec
|
87
95
|
- test/README
|
88
96
|
- test/active_model_test.rb
|
@@ -128,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
136
|
version: '0'
|
129
137
|
requirements: []
|
130
138
|
rubyforge_project:
|
131
|
-
rubygems_version: 2.4.
|
139
|
+
rubygems_version: 2.4.6
|
132
140
|
signing_key:
|
133
141
|
specification_version: 4
|
134
142
|
summary: Cassandra ActiveModel
|