gotime-cassandra_object 3.0.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.
- data/CHANGELOG +0 -3
- data/Gemfile +3 -2
- data/README.rdoc +1 -1
- data/gotime-cassandra_object.gemspec +5 -4
- data/lib/cassandra_object/base.rb +0 -1
- data/lib/cassandra_object/batches.rb +0 -4
- data/lib/cassandra_object/connection.rb +18 -3
- data/lib/cassandra_object/consistency.rb +3 -3
- data/lib/cassandra_object/finder_methods.rb +24 -27
- data/lib/cassandra_object/persistence.rb +11 -13
- data/lib/cassandra_object/railtie.rb +0 -4
- data/lib/cassandra_object/schema.rb +25 -24
- data/lib/cassandra_object/tasks/ks.rake +2 -61
- data/lib/gotime-cassandra_object.rb +2 -8
- data/test/support/connect.rb +5 -6
- data/test/support/issue.rb +2 -1
- data/test/unit/batches_test.rb +0 -10
- data/test/unit/connection_test.rb +16 -17
- data/test/unit/finder_methods_test.rb +1 -1
- data/test/unit/persistence_test.rb +9 -0
- metadata +21 -15
- data/lib/cassandra_object/generators/migration_generator.rb +0 -31
- data/lib/cassandra_object/generators/templates/migration.rb.erb +0 -9
- data/lib/cassandra_object/migrations.rb +0 -25
- data/lib/cassandra_object/migrations/migration.rb +0 -15
- data/lib/cassandra_object/schema/migration.rb +0 -104
- data/lib/cassandra_object/schema/migration_proxy.rb +0 -25
- data/lib/cassandra_object/schema/migrator.rb +0 -210
- data/lib/cassandra_object/tasks/column_family.rb +0 -54
- data/lib/cassandra_object/tasks/keyspace.rb +0 -44
- data/test/unit/tasks/column_family_test.rb +0 -29
data/CHANGELOG
CHANGED
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -7,7 +7,7 @@ Cassandra Object uses ActiveModel to mimic much of the behavior in ActiveRecord.
|
|
7
7
|
|
8
8
|
Add the following to your Gemfile:
|
9
9
|
|
10
|
-
gem 'cassandra', require: '0
|
10
|
+
gem 'cassandra', require: '1.0'
|
11
11
|
gem 'gotime-cassandra_object'
|
12
12
|
|
13
13
|
Change the version of Cassandra accordingly. Recent versions have not been backward compatible.
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'gotime-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
|
s.authors = ["Michael Koziarski", "gotime"]
|
@@ -17,9 +17,10 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
18
18
|
s.require_paths = ['lib']
|
19
19
|
|
20
|
-
s.add_runtime_dependency('activemodel',
|
21
|
-
s.add_runtime_dependency('
|
22
|
-
s.add_runtime_dependency('
|
20
|
+
s.add_runtime_dependency('activemodel', '>= 3.0')
|
21
|
+
s.add_runtime_dependency('cassandra', '>= 0.14.0')
|
22
|
+
s.add_runtime_dependency('cassandra-cql')
|
23
|
+
s.add_runtime_dependency('thrift_client', '~> 0.8.0')
|
23
24
|
|
24
25
|
s.add_development_dependency('bundler')
|
25
26
|
end
|
@@ -3,7 +3,7 @@ module CassandraObject
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
class_attribute :
|
6
|
+
class_attribute :connection_config
|
7
7
|
end
|
8
8
|
|
9
9
|
module ClassMethods
|
@@ -11,9 +11,24 @@ module CassandraObject
|
|
11
11
|
servers: "127.0.0.1:9160",
|
12
12
|
thrift: {}
|
13
13
|
}
|
14
|
+
|
14
15
|
def establish_connection(spec)
|
15
|
-
spec.reverse_merge
|
16
|
-
|
16
|
+
self.connection_config = spec.reverse_merge(DEFAULT_OPTIONS)
|
17
|
+
end
|
18
|
+
|
19
|
+
def connection
|
20
|
+
@@connection ||= Cassandra.new(connection_config[:keyspace], connection_config[:servers], connection_config[:thrift].symbolize_keys!)
|
21
|
+
end
|
22
|
+
|
23
|
+
def cql
|
24
|
+
@@cql ||= CassandraCQL::Database.new(connection_config[:servers], keyspace: connection_config[:keyspace])
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute_cql(cql_string, *bind_vars)
|
28
|
+
statement = CassandraCQL::Statement.sanitize(cql_string, bind_vars)
|
29
|
+
ActiveSupport::Notifications.instrument("cql.cassandra_object", cql: statement) do
|
30
|
+
cql.execute statement
|
31
|
+
end
|
17
32
|
end
|
18
33
|
end
|
19
34
|
end
|
@@ -14,9 +14,9 @@ module CassandraObject
|
|
14
14
|
|
15
15
|
module ClassMethods
|
16
16
|
THRIFT_LEVELS = {
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
17
|
+
one: Cassandra::Consistency::ONE,
|
18
|
+
quorum: Cassandra::Consistency::QUORUM,
|
19
|
+
all: Cassandra::Consistency::ALL
|
20
20
|
}
|
21
21
|
|
22
22
|
def thrift_read_consistency
|
@@ -17,32 +17,38 @@ module CassandraObject
|
|
17
17
|
nil
|
18
18
|
end
|
19
19
|
|
20
|
-
def all
|
21
|
-
|
22
|
-
results = ActiveSupport::Notifications.instrument("get_range.cassandra_object", column_family: column_family, key_count: limit) do
|
23
|
-
connection.get_range(column_family, key_count: limit, consistency: thrift_read_consistency, count: 500)
|
24
|
-
end
|
25
|
-
|
26
|
-
results.map do |k, v|
|
27
|
-
v.empty? ? nil : instantiate(k, v)
|
28
|
-
end.compact
|
20
|
+
def all
|
21
|
+
instantiate_from_cql "select * from #{column_family}"
|
29
22
|
end
|
30
23
|
|
31
24
|
def first(options = {})
|
32
|
-
|
25
|
+
instantiate_from_cql("select * from #{column_family} limit 1").first
|
33
26
|
end
|
34
27
|
|
35
|
-
|
36
|
-
|
28
|
+
private
|
29
|
+
|
30
|
+
def instantiate_from_cql(cql_string, *args)
|
31
|
+
results = []
|
32
|
+
execute_cql(cql_string, *args).fetch do |cql_row|
|
33
|
+
results << instantiate_cql_row(cql_row)
|
34
|
+
end
|
35
|
+
results.compact!
|
36
|
+
results
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
def instantiate_cql_row(cql_row)
|
40
|
+
attributes = cql_row.to_hash
|
41
|
+
key = attributes.delete('KEY')
|
42
|
+
if attributes.any?
|
43
|
+
instantiate(key, attributes)
|
44
|
+
end
|
45
|
+
end
|
40
46
|
|
41
47
|
def find_one(id)
|
42
48
|
if id.blank?
|
43
49
|
raise CassandraObject::RecordNotFound, "Couldn't find #{self.name} with key #{id.inspect}"
|
44
|
-
elsif
|
45
|
-
|
50
|
+
elsif record = instantiate_from_cql("select * from #{column_family} where KEY = ? limit 1", id).first
|
51
|
+
record
|
46
52
|
else
|
47
53
|
raise CassandraObject::RecordNotFound
|
48
54
|
end
|
@@ -50,21 +56,12 @@ module CassandraObject
|
|
50
56
|
|
51
57
|
def find_some(ids)
|
52
58
|
ids = ids.flatten
|
53
|
-
return
|
59
|
+
return [] if ids.empty?
|
54
60
|
|
55
61
|
ids = ids.compact.map(&:to_s).uniq
|
56
62
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
def multi_get(keys, options={})
|
61
|
-
attribute_results = ActiveSupport::Notifications.instrument("multi_get.cassandra_object", column_family: column_family, keys: keys) do
|
62
|
-
connection.multi_get(column_family, keys.map(&:to_s), consistency: thrift_read_consistency, count: 500)
|
63
|
-
end
|
64
|
-
|
65
|
-
Hash[attribute_results.map do |key, attributes|
|
66
|
-
[key, attributes.present? ? instantiate(key, attributes) : nil]
|
67
|
-
end]
|
63
|
+
statement = "select * from #{column_family} where KEY in (#{Array.new(ids.size, '?') * ','})"
|
64
|
+
instantiate_from_cql statement, *ids
|
68
65
|
end
|
69
66
|
end
|
70
67
|
end
|
@@ -4,15 +4,11 @@ module CassandraObject
|
|
4
4
|
|
5
5
|
module ClassMethods
|
6
6
|
def remove(id)
|
7
|
-
|
8
|
-
connection.remove(column_family, id, consistency: thrift_write_consistency)
|
9
|
-
end
|
7
|
+
execute_cql "DELETE FROM #{column_family} WHERE KEY = ?", id
|
10
8
|
end
|
11
9
|
|
12
10
|
def delete_all
|
13
|
-
|
14
|
-
connection.truncate!(column_family)
|
15
|
-
end
|
11
|
+
execute_cql "TRUNCATE #{column_family}"
|
16
12
|
end
|
17
13
|
|
18
14
|
def create(attributes = {})
|
@@ -22,12 +18,14 @@ module CassandraObject
|
|
22
18
|
end
|
23
19
|
|
24
20
|
def write(id, attributes)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
21
|
+
if (encoded = encode_attributes(attributes)).any?
|
22
|
+
insert_attributes = {'KEY' => id}.update encode_attributes(attributes)
|
23
|
+
statement = "INSERT INTO #{column_family} (#{insert_attributes.keys * ','}) VALUES (#{Array.new(insert_attributes.size, '?') * ','})"
|
24
|
+
execute_cql statement, *insert_attributes.values
|
25
|
+
end
|
26
|
+
|
27
|
+
if (nil_attributes = attributes.select { |key, value| value.nil? }).any?
|
28
|
+
execute_cql "DELETE #{nil_attributes.keys * ','} FROM #{column_family} WHERE KEY = ?", id
|
31
29
|
end
|
32
30
|
end
|
33
31
|
|
@@ -45,7 +43,7 @@ module CassandraObject
|
|
45
43
|
attributes.each do |column_name, value|
|
46
44
|
# The ruby thrift gem expects all strings to be encoded as ascii-8bit.
|
47
45
|
unless value.nil?
|
48
|
-
encoded[column_name.to_s] = attribute_definitions[column_name.to_sym].coder.encode(value)
|
46
|
+
encoded[column_name.to_s] = attribute_definitions[column_name.to_sym].coder.encode(value)
|
49
47
|
end
|
50
48
|
end
|
51
49
|
encoded
|
@@ -1,37 +1,38 @@
|
|
1
1
|
module CassandraObject
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
class Schema
|
3
|
+
class << self
|
4
|
+
def create_keyspace(keyspace)
|
5
|
+
system_execute "CREATE KEYSPACE #{keyspace} " +
|
6
|
+
"WITH strategy_class = SimpleStrategy " +
|
7
|
+
" AND strategy_options:replication_factor = 1"
|
8
|
+
end
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
super("Multiple migrations have the version number #{version}")
|
10
|
+
def drop_keyspace(keyspace)
|
11
|
+
system_execute "DROP KEYSPACE #{keyspace}"
|
11
12
|
end
|
12
|
-
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
def create_column_family(column_family)
|
15
|
+
execute "CREATE COLUMNFAMILY #{column_family} " +
|
16
|
+
"(KEY varchar PRIMARY KEY)"
|
17
17
|
end
|
18
|
-
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
super("No migration with version number #{version}")
|
19
|
+
def alter_column_family_with(with)
|
20
|
+
execute "ALTER TABLE users WITH #{with}"
|
23
21
|
end
|
24
|
-
end
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed)")
|
23
|
+
def add_index()
|
24
|
+
|
29
25
|
end
|
30
|
-
end
|
31
26
|
|
32
|
-
|
33
|
-
|
34
|
-
|
27
|
+
private
|
28
|
+
def execute(cql)
|
29
|
+
CassandraObject::Base.execute_cql cql
|
30
|
+
end
|
35
31
|
|
32
|
+
def system_execute(cql)
|
33
|
+
@system_cql ||= CassandraCQL::Database.new(CassandraObject::Base.connection_config[:servers], keyspace: 'system')
|
34
|
+
@system_cql.execute cql
|
35
|
+
end
|
36
|
+
end
|
36
37
|
end
|
37
38
|
end
|
@@ -1,77 +1,18 @@
|
|
1
1
|
namespace :ks do
|
2
2
|
desc 'Create the keyspace in cassandra_config/cassandra.yml for the current environment'
|
3
3
|
task create: :environment do
|
4
|
-
CassandraObject::
|
5
|
-
puts "Created keyspace: #{cassandra_config['keyspace']}"
|
4
|
+
CassandraObject::Schema.create_keyspace cassandra_config['keyspace']
|
6
5
|
end
|
7
6
|
|
8
|
-
desc 'Drop keyspace in cassandra_config/cassandra.yml for the current environment'
|
9
7
|
task drop: :environment do
|
10
|
-
CassandraObject::
|
11
|
-
puts "Dropped keyspace: #{cassandra_config['keyspace']}"
|
12
|
-
end
|
13
|
-
|
14
|
-
desc 'Migrate the keyspace (options: VERSION=x)'
|
15
|
-
task migrate: :environment do
|
16
|
-
version = ( ENV['VERSION'] ? ENV['VERSION'].to_i : nil )
|
17
|
-
CassandraObject::Schema::Migrator.migrate CassandraObject::Schema::Migrator.migrations_path, version
|
18
|
-
schema_dump
|
19
|
-
end
|
20
|
-
|
21
|
-
namespace :migrate do
|
22
|
-
task :reset => ["ks:drop", "ks:create", "ks:migrate"]
|
23
|
-
end
|
24
|
-
|
25
|
-
desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n)'
|
26
|
-
task rollback: :environment do
|
27
|
-
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
28
|
-
CassandraObject::Schema::Migrator.rollback CassandraObject::Schema::Migrator.migrations_path, step
|
29
|
-
schema_dump
|
30
|
-
end
|
31
|
-
|
32
|
-
desc 'Pushes the schema to the next version (specify steps w/ STEP=n)'
|
33
|
-
task forward: :environment do
|
34
|
-
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
35
|
-
CassandraObject::Schema::Migrator.forward CassandraObject::Schema::Migrator.migrations_path, step
|
36
|
-
schema_dump
|
37
|
-
end
|
38
|
-
|
39
|
-
namespace :schema do
|
40
|
-
desc 'Create ks/schema.json file that can be portably used against any Cassandra instance supported by CassandraObject'
|
41
|
-
task dump: :environment do
|
42
|
-
schema_dump
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
namespace :test do
|
48
|
-
desc 'Load the development schema in to the test keyspace'
|
49
|
-
task prepare: :environment do
|
50
|
-
schema_dump :development
|
51
|
-
schema_load :test
|
52
|
-
end
|
8
|
+
CassandraObject::Schema.drop_keyspace cassandra_config['keyspace']
|
53
9
|
end
|
54
10
|
|
55
11
|
private
|
56
|
-
def schema_dump(env = Rails.env)
|
57
|
-
# File.open "#{Rails.root}/ks/schema.rb", 'w' do |file|
|
58
|
-
# end
|
59
|
-
end
|
60
|
-
|
61
|
-
def schema_load(env = Rails.env)
|
62
|
-
end
|
63
|
-
|
64
12
|
def cassandra_config
|
65
13
|
@cassandra_config ||= begin
|
66
14
|
cassandra_configs = YAML.load_file(Rails.root.join("config", "cassandra.yml"))
|
67
15
|
cassandra_configs[Rails.env || 'development']
|
68
16
|
end
|
69
17
|
end
|
70
|
-
|
71
|
-
def get_keyspace
|
72
|
-
ks = CassandraObject::Tasks::Keyspace.new
|
73
|
-
ks.set cassandra_config['keyspace']
|
74
|
-
ks
|
75
|
-
end
|
76
18
|
end
|
77
|
-
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/all'
|
2
2
|
require 'active_model'
|
3
|
+
require 'cassandra-cql'
|
3
4
|
|
4
5
|
module CassandraObject
|
5
6
|
extend ActiveSupport::Autoload
|
@@ -15,15 +16,14 @@ module CassandraObject
|
|
15
16
|
autoload :Identity
|
16
17
|
autoload :Inspect
|
17
18
|
autoload :Serialization
|
18
|
-
autoload :Migrations
|
19
19
|
autoload :Collection
|
20
20
|
autoload :Mocking
|
21
21
|
autoload :Batches
|
22
22
|
autoload :FinderMethods
|
23
23
|
autoload :Savepoints
|
24
|
+
autoload :Schema
|
24
25
|
autoload :Timestamps
|
25
26
|
autoload :Type
|
26
|
-
autoload :Schema
|
27
27
|
|
28
28
|
module BelongsTo
|
29
29
|
extend ActiveSupport::Autoload
|
@@ -44,12 +44,6 @@ module CassandraObject
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
module Tasks
|
48
|
-
extend ActiveSupport::Autoload
|
49
|
-
autoload :Keyspace
|
50
|
-
autoload :ColumnFamily
|
51
|
-
end
|
52
|
-
|
53
47
|
module Types
|
54
48
|
extend ActiveSupport::Autoload
|
55
49
|
|
data/test/support/connect.rb
CHANGED
@@ -3,11 +3,10 @@ CassandraObject::Base.establish_connection(
|
|
3
3
|
servers: '127.0.0.1:9160'
|
4
4
|
)
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
begin
|
7
|
+
CassandraObject::Schema.drop_keyspace 'cassandra_object_test'
|
8
|
+
rescue Exception => e
|
9
9
|
end
|
10
10
|
|
11
|
-
CassandraObject::
|
12
|
-
|
13
|
-
end
|
11
|
+
CassandraObject::Schema.create_keyspace 'cassandra_object_test'
|
12
|
+
CassandraObject::Schema.create_column_family 'Issues'
|
data/test/support/issue.rb
CHANGED
data/test/unit/batches_test.rb
CHANGED
@@ -27,14 +27,4 @@ class CassandraObject::BatchesTest < CassandraObject::TestCase
|
|
27
27
|
assert issue_batches.any? { |issues| issues.size == 2 }
|
28
28
|
assert issue_batches.any? { |issues| issues.size == 1 }
|
29
29
|
end
|
30
|
-
|
31
|
-
test 'batch' do
|
32
|
-
Issue.batch do
|
33
|
-
Issue.create
|
34
|
-
Issue.create
|
35
|
-
assert_equal 0, Issue.count
|
36
|
-
end
|
37
|
-
|
38
|
-
assert_equal 2, Issue.count
|
39
|
-
end
|
40
30
|
end
|
@@ -5,24 +5,23 @@ class CassandraObject::ConnectionTest < CassandraObject::TestCase
|
|
5
5
|
end
|
6
6
|
|
7
7
|
test 'establish_connection' do
|
8
|
-
TestObject.establish_connection(
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
)
|
13
|
-
|
14
|
-
|
15
|
-
assert_equal
|
16
|
-
assert_equal
|
17
|
-
assert_equal 10, TestObject.connection.thrift_client_options[:timeout]
|
8
|
+
# TestObject.establish_connection(
|
9
|
+
# keyspace: 'place_directory_development',
|
10
|
+
# servers: '192.168.0.100:9160',
|
11
|
+
# thrift: {'timeout' => 10}
|
12
|
+
# )
|
13
|
+
#
|
14
|
+
# assert_equal 'place_directory_development', TestObject.connection.keyspace
|
15
|
+
# assert_equal ["192.168.0.100:9160"], TestObject.connection.servers
|
16
|
+
# assert_equal 10, TestObject.connection.thrift_client_options[:timeout]
|
18
17
|
end
|
19
18
|
|
20
19
|
test 'establish_connection defaults' do
|
21
|
-
TestObject.establish_connection(
|
22
|
-
|
23
|
-
)
|
24
|
-
|
25
|
-
assert_equal 'place_directory_development', TestObject.connection.keyspace
|
26
|
-
assert_equal ["127.0.0.1:9160"], TestObject.connection.servers
|
20
|
+
# TestObject.establish_connection(
|
21
|
+
# keyspace: 'place_directory_development'
|
22
|
+
# )
|
23
|
+
#
|
24
|
+
# assert_equal 'place_directory_development', TestObject.connection.keyspace
|
25
|
+
# assert_equal ["127.0.0.1:9160"], TestObject.connection.servers
|
27
26
|
end
|
28
|
-
end
|
27
|
+
end
|
@@ -94,6 +94,15 @@ class CassandraObject::PersistenceTest < CassandraObject::TestCase
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
+
test 'update nil attributes' do
|
98
|
+
issue = Issue.create(title: 'I rule', description: 'lololol')
|
99
|
+
|
100
|
+
issue.update_attributes title: nil
|
101
|
+
|
102
|
+
issue = Issue.find issue.id
|
103
|
+
assert_nil issue.title
|
104
|
+
end
|
105
|
+
|
97
106
|
test 'reload' do
|
98
107
|
persisted_issue = Issue.create
|
99
108
|
fresh_issue = Issue.find(persisted_issue.id)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gotime-cassandra_object
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-08-10 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activemodel
|
@@ -29,13 +29,13 @@ dependencies:
|
|
29
29
|
- !ruby/object:Gem::Version
|
30
30
|
version: '3.0'
|
31
31
|
- !ruby/object:Gem::Dependency
|
32
|
-
name:
|
32
|
+
name: cassandra
|
33
33
|
requirement: !ruby/object:Gem::Requirement
|
34
34
|
none: false
|
35
35
|
requirements:
|
36
36
|
- - ! '>='
|
37
37
|
- !ruby/object:Gem::Version
|
38
|
-
version: 0.
|
38
|
+
version: 0.14.0
|
39
39
|
type: :runtime
|
40
40
|
prerelease: false
|
41
41
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -43,7 +43,23 @@ dependencies:
|
|
43
43
|
requirements:
|
44
44
|
- - ! '>='
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 0.
|
46
|
+
version: 0.14.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: cassandra-cql
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
47
63
|
- !ruby/object:Gem::Dependency
|
48
64
|
name: thrift_client
|
49
65
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,24 +125,15 @@ files:
|
|
109
125
|
- lib/cassandra_object/consistency.rb
|
110
126
|
- lib/cassandra_object/errors.rb
|
111
127
|
- lib/cassandra_object/finder_methods.rb
|
112
|
-
- lib/cassandra_object/generators/migration_generator.rb
|
113
|
-
- lib/cassandra_object/generators/templates/migration.rb.erb
|
114
128
|
- lib/cassandra_object/identity.rb
|
115
129
|
- lib/cassandra_object/inspect.rb
|
116
130
|
- lib/cassandra_object/log_subscriber.rb
|
117
|
-
- lib/cassandra_object/migrations.rb
|
118
|
-
- lib/cassandra_object/migrations/migration.rb
|
119
131
|
- lib/cassandra_object/mocking.rb
|
120
132
|
- lib/cassandra_object/persistence.rb
|
121
133
|
- lib/cassandra_object/railtie.rb
|
122
134
|
- lib/cassandra_object/savepoints.rb
|
123
135
|
- lib/cassandra_object/schema.rb
|
124
|
-
- lib/cassandra_object/schema/migration.rb
|
125
|
-
- lib/cassandra_object/schema/migration_proxy.rb
|
126
|
-
- lib/cassandra_object/schema/migrator.rb
|
127
136
|
- lib/cassandra_object/serialization.rb
|
128
|
-
- lib/cassandra_object/tasks/column_family.rb
|
129
|
-
- lib/cassandra_object/tasks/keyspace.rb
|
130
137
|
- lib/cassandra_object/tasks/ks.rake
|
131
138
|
- lib/cassandra_object/timestamps.rb
|
132
139
|
- lib/cassandra_object/type.rb
|
@@ -164,7 +171,6 @@ files:
|
|
164
171
|
- test/unit/inspect_test.rb
|
165
172
|
- test/unit/persistence_test.rb
|
166
173
|
- test/unit/savepoints_test.rb
|
167
|
-
- test/unit/tasks/column_family_test.rb
|
168
174
|
- test/unit/timestamps_test.rb
|
169
175
|
- test/unit/types/array_type_test.rb
|
170
176
|
- test/unit/types/base_type_test.rb
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'rails/generators'
|
2
|
-
require 'rails/generators/named_base'
|
3
|
-
|
4
|
-
module CassandraObject
|
5
|
-
module Generators
|
6
|
-
class MigrationGenerator < Rails::Generators::NamedBase
|
7
|
-
|
8
|
-
source_root File.expand_path("../templates", __FILE__)
|
9
|
-
|
10
|
-
def self.banner
|
11
|
-
"rails g cassandra_object:migration NAME"
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.desc(description = nil)
|
15
|
-
<<EOF
|
16
|
-
Description:
|
17
|
-
Create an empty Cassandra migration file in 'ks/migrate'. Very similar to Rails database migrations.
|
18
|
-
|
19
|
-
Example:
|
20
|
-
`rails g cassandra_object:migration CreateFooColumnFamily`
|
21
|
-
EOF
|
22
|
-
end
|
23
|
-
|
24
|
-
def create
|
25
|
-
timestamp = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
26
|
-
template 'migration.rb.erb', "ks/migrate/#{timestamp}_#{file_name.underscore}.rb"
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module CassandraObject
|
2
|
-
module Migrations
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
extend ActiveSupport::Autoload
|
5
|
-
|
6
|
-
included do
|
7
|
-
class_attribute :migrations
|
8
|
-
self.migrations = []
|
9
|
-
end
|
10
|
-
|
11
|
-
autoload :Migration
|
12
|
-
|
13
|
-
class MigrationNotFoundError < StandardError
|
14
|
-
def initialize(record_version, migrations)
|
15
|
-
super("Cannot migrate a record from #{record_version.inspect}. Migrations exist for #{migrations.map(&:version)}")
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
module ClassMethods
|
20
|
-
def migrate(version, &blk)
|
21
|
-
migrations << Migration.new(version, blk)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,104 +0,0 @@
|
|
1
|
-
module CassandraObject
|
2
|
-
module Schema
|
3
|
-
class Migration
|
4
|
-
|
5
|
-
@@verbose = true
|
6
|
-
cattr_accessor :verbose
|
7
|
-
|
8
|
-
class << self
|
9
|
-
def connection
|
10
|
-
CassandraObject::Base.connection
|
11
|
-
end
|
12
|
-
|
13
|
-
def migrate(direction)
|
14
|
-
return unless respond_to?(direction)
|
15
|
-
|
16
|
-
case direction
|
17
|
-
when :up then announce "migrating"
|
18
|
-
when :down then announce "reverting"
|
19
|
-
end
|
20
|
-
|
21
|
-
result = nil
|
22
|
-
time = Benchmark.measure { result = send("#{direction}") }
|
23
|
-
|
24
|
-
case direction
|
25
|
-
when :up then announce "migrated (%.4fs)" % time.real; write
|
26
|
-
when :down then announce "reverted (%.4fs)" % time.real; write
|
27
|
-
end
|
28
|
-
|
29
|
-
result
|
30
|
-
end
|
31
|
-
|
32
|
-
# Creates a new column family with the given name. Column family configurations can be set within
|
33
|
-
# a block like this:
|
34
|
-
#
|
35
|
-
# create_column_family(:users) do |cf|
|
36
|
-
# cf.comment = 'Users column family'
|
37
|
-
# cf.comparator_type = 'TimeUUIDType'
|
38
|
-
# end
|
39
|
-
#
|
40
|
-
# A complete list of available configuration settings is here:
|
41
|
-
#
|
42
|
-
# http://github.com/fauna/cassandra/blob/master/vendor/0.7/gen-rb/cassandra_types.rb
|
43
|
-
#
|
44
|
-
# Scroll down to the CfDef definition.
|
45
|
-
def create_column_family(name, &block)
|
46
|
-
say_with_time("create_column_family #{name}") do
|
47
|
-
column_family_tasks.create(name, &block)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Drops the given column family
|
52
|
-
def drop_column_family(name)
|
53
|
-
say_with_time("drop_column_family #{name}") do
|
54
|
-
column_family_tasks.drop(name)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# Renames the column family from the old name to the new name
|
59
|
-
def rename_column_family(old_name, new_name)
|
60
|
-
say_with_time("rename_column_family #{name}") do
|
61
|
-
column_family_tasks.rename(old_name, new_name)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def write(text="")
|
66
|
-
puts(text) if verbose
|
67
|
-
end
|
68
|
-
|
69
|
-
def announce(message)
|
70
|
-
version = defined?(@version) ? @version : nil
|
71
|
-
|
72
|
-
text = "#{version} #{name}: #{message}"
|
73
|
-
length = [0, 75 - text.length].max
|
74
|
-
write "== %s %s" % [text, "=" * length]
|
75
|
-
end
|
76
|
-
|
77
|
-
def say(message, subitem=false)
|
78
|
-
write "#{subitem ? " ->" : "--"} #{message}"
|
79
|
-
end
|
80
|
-
|
81
|
-
def say_with_time(message)
|
82
|
-
say(message)
|
83
|
-
result = nil
|
84
|
-
time = Benchmark.measure { result = yield }
|
85
|
-
say "%.4fs" % time.real, :subitem
|
86
|
-
say("#{result} rows", :subitem) if result.is_a?(Integer)
|
87
|
-
result
|
88
|
-
end
|
89
|
-
|
90
|
-
def suppress_messages
|
91
|
-
save, self.verbose = verbose, false
|
92
|
-
yield
|
93
|
-
ensure
|
94
|
-
self.verbose = save
|
95
|
-
end
|
96
|
-
|
97
|
-
private
|
98
|
-
def column_family_tasks
|
99
|
-
Tasks::ColumnFamily.new(CassandraObject::Base.connection.keyspace)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module CassandraObject
|
2
|
-
module Schema
|
3
|
-
|
4
|
-
# MigrationProxy is used to defer loading of the actual migration classes
|
5
|
-
# until they are needed
|
6
|
-
class MigrationProxy
|
7
|
-
|
8
|
-
attr_accessor :name, :version, :filename
|
9
|
-
|
10
|
-
delegate :migrate, :announce, :write, :to=>:migration
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
def migration
|
15
|
-
@migration ||= load_migration
|
16
|
-
end
|
17
|
-
|
18
|
-
def load_migration
|
19
|
-
require(File.expand_path(filename))
|
20
|
-
name.constantize
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,210 +0,0 @@
|
|
1
|
-
module CassandraObject
|
2
|
-
module Schema
|
3
|
-
class Migrator
|
4
|
-
class << self
|
5
|
-
def migrate(migrations_path, target_version = nil)
|
6
|
-
case
|
7
|
-
when target_version.nil?
|
8
|
-
up(migrations_path, target_version)
|
9
|
-
when current_version == 0 && target_version == 0
|
10
|
-
when current_version > target_version
|
11
|
-
down(migrations_path, target_version)
|
12
|
-
else
|
13
|
-
up(migrations_path, target_version)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def rollback(migrations_path, steps = 1)
|
18
|
-
move(:down, migrations_path, steps)
|
19
|
-
end
|
20
|
-
|
21
|
-
def forward(migrations_path, steps = 1)
|
22
|
-
move(:up, migrations_path, steps)
|
23
|
-
end
|
24
|
-
|
25
|
-
def up(migrations_path, target_version = nil)
|
26
|
-
new(:up, migrations_path, target_version).migrate
|
27
|
-
end
|
28
|
-
|
29
|
-
def down(migrations_path, target_version = nil)
|
30
|
-
new(:down, migrations_path, target_version).migrate
|
31
|
-
end
|
32
|
-
|
33
|
-
def run(direction, migrations_path, target_version)
|
34
|
-
new(direction, migrations_path, target_version).run
|
35
|
-
end
|
36
|
-
|
37
|
-
def migrations_path
|
38
|
-
'ks/migrate'
|
39
|
-
end
|
40
|
-
|
41
|
-
def schema_migrations_column_family
|
42
|
-
:schema_migrations
|
43
|
-
end
|
44
|
-
|
45
|
-
def column_family_tasks
|
46
|
-
cas = CassandraObject::Base.connection
|
47
|
-
Tasks::ColumnFamily.new(cas.keyspace)
|
48
|
-
end
|
49
|
-
|
50
|
-
def get_all_versions
|
51
|
-
cas = CassandraObject::Base.connection
|
52
|
-
cas.get(schema_migrations_column_family, 'all').map {|(name, _value)| name.to_i}.sort
|
53
|
-
end
|
54
|
-
|
55
|
-
def current_version
|
56
|
-
sm_cf = schema_migrations_column_family
|
57
|
-
if column_family_tasks.exists?(sm_cf)
|
58
|
-
get_all_versions.max || 0
|
59
|
-
else
|
60
|
-
0
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def move(direction, migrations_path, steps)
|
67
|
-
migrator = self.new(direction, migrations_path)
|
68
|
-
start_index = migrator.migrations.index(migrator.current_migration)
|
69
|
-
|
70
|
-
if start_index
|
71
|
-
finish = migrator.migrations[start_index + steps]
|
72
|
-
version = finish ? finish.version : 0
|
73
|
-
send(direction, migrations_path, version)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def initialize(direction, migrations_path, target_version = nil)
|
79
|
-
sm_cf = self.class.schema_migrations_column_family
|
80
|
-
|
81
|
-
unless column_family_tasks.exists?(sm_cf)
|
82
|
-
column_family_tasks.create(sm_cf) do |cf|
|
83
|
-
cf.comparator_type = 'LongType'
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
@direction, @migrations_path, @target_version = direction, migrations_path, target_version
|
88
|
-
end
|
89
|
-
|
90
|
-
def current_version
|
91
|
-
migrated.last || 0
|
92
|
-
end
|
93
|
-
|
94
|
-
def current_migration
|
95
|
-
migrations.detect { |m| m.version == current_version }
|
96
|
-
end
|
97
|
-
|
98
|
-
def run
|
99
|
-
target = migrations.detect { |m| m.version == @target_version }
|
100
|
-
raise UnknownMigrationVersionError.new(@target_version) if target.nil?
|
101
|
-
unless (up? && migrated.include?(target.version.to_i)) || (down? && !migrated.include?(target.version.to_i))
|
102
|
-
target.migrate(@direction)
|
103
|
-
record_version_state_after_migrating(target)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def migrate
|
108
|
-
current = migrations.detect { |m| m.version == current_version }
|
109
|
-
target = migrations.detect { |m| m.version == @target_version }
|
110
|
-
|
111
|
-
if target.nil? && !@target_version.nil? && @target_version > 0
|
112
|
-
raise UnknownMigrationVersionError.new(@target_version)
|
113
|
-
end
|
114
|
-
|
115
|
-
start = up? ? 0 : (migrations.index(current) || 0)
|
116
|
-
finish = migrations.index(target) || migrations.size - 1
|
117
|
-
runnable = migrations[start..finish]
|
118
|
-
|
119
|
-
# skip the last migration if we're headed down, but not ALL the way down
|
120
|
-
runnable.pop if down? && !target.nil?
|
121
|
-
|
122
|
-
runnable.each do |migration|
|
123
|
-
#puts "Migrating to #{migration.name} (#{migration.version})"
|
124
|
-
|
125
|
-
# On our way up, we skip migrating the ones we've already migrated
|
126
|
-
next if up? && migrated.include?(migration.version.to_i)
|
127
|
-
|
128
|
-
# On our way down, we skip reverting the ones we've never migrated
|
129
|
-
if down? && !migrated.include?(migration.version.to_i)
|
130
|
-
migration.announce 'never migrated, skipping'; migration.write
|
131
|
-
next
|
132
|
-
end
|
133
|
-
|
134
|
-
migration.migrate(@direction)
|
135
|
-
record_version_state_after_migrating(migration)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def migrations
|
140
|
-
@migrations ||= begin
|
141
|
-
files = Dir["#{@migrations_path}/[0-9]*_*.rb"]
|
142
|
-
|
143
|
-
migrations = files.inject([]) do |klasses, file|
|
144
|
-
version, name = file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first
|
145
|
-
|
146
|
-
raise IllegalMigrationNameError.new(file) unless version
|
147
|
-
version = version.to_i
|
148
|
-
|
149
|
-
if klasses.detect { |m| m.version == version }
|
150
|
-
raise DuplicateMigrationVersionError.new(version)
|
151
|
-
end
|
152
|
-
|
153
|
-
if klasses.detect { |m| m.name == name.camelize }
|
154
|
-
raise DuplicateMigrationNameError.new(name.camelize)
|
155
|
-
end
|
156
|
-
|
157
|
-
migration = MigrationProxy.new
|
158
|
-
migration.name = name.camelize
|
159
|
-
migration.version = version
|
160
|
-
migration.filename = file
|
161
|
-
klasses << migration
|
162
|
-
end
|
163
|
-
|
164
|
-
migrations = migrations.sort_by { |m| m.version }
|
165
|
-
down? ? migrations.reverse : migrations
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def pending_migrations
|
170
|
-
already_migrated = migrated
|
171
|
-
migrations.reject { |m| already_migrated.include?(m.version.to_i) }
|
172
|
-
end
|
173
|
-
|
174
|
-
def migrated
|
175
|
-
@migrated_versions ||= self.class.get_all_versions
|
176
|
-
end
|
177
|
-
|
178
|
-
private
|
179
|
-
|
180
|
-
def column_family_tasks
|
181
|
-
Tasks::ColumnFamily.new(connection.keyspace)
|
182
|
-
end
|
183
|
-
|
184
|
-
def connection
|
185
|
-
CassandraObject::Base.connection
|
186
|
-
end
|
187
|
-
|
188
|
-
def record_version_state_after_migrating(migration)
|
189
|
-
sm_cf = self.class.schema_migrations_column_family
|
190
|
-
|
191
|
-
@migrated_versions ||= []
|
192
|
-
if down?
|
193
|
-
@migrated_versions.delete(migration.version)
|
194
|
-
connection.remove sm_cf, 'all', migration.version
|
195
|
-
else
|
196
|
-
@migrated_versions.push(migration.version).sort!
|
197
|
-
connection.insert sm_cf, 'all', { migration.version => migration.name }
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def up?
|
202
|
-
@direction == :up
|
203
|
-
end
|
204
|
-
|
205
|
-
def down?
|
206
|
-
@direction == :down
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
module CassandraObject
|
2
|
-
module Tasks
|
3
|
-
class ColumnFamily
|
4
|
-
COLUMN_TYPES = {
|
5
|
-
standard: 'Standard',
|
6
|
-
super: 'Super'
|
7
|
-
}
|
8
|
-
|
9
|
-
def initialize(keyspace)
|
10
|
-
@keyspace = keyspace
|
11
|
-
end
|
12
|
-
|
13
|
-
def exists?(name)
|
14
|
-
connection.schema.cf_defs.find { |cf_def| cf_def.name == name.to_s }
|
15
|
-
end
|
16
|
-
|
17
|
-
def create(name)
|
18
|
-
cf = Cassandra::ColumnFamily.new
|
19
|
-
cf.name = name.to_s
|
20
|
-
cf.keyspace = @keyspace.to_s
|
21
|
-
cf.comparator_type = 'UTF8Type'
|
22
|
-
cf.column_type = 'Standard'
|
23
|
-
|
24
|
-
yield(cf) if block_given?
|
25
|
-
|
26
|
-
post_process_column_family(cf)
|
27
|
-
connection.add_column_family(cf)
|
28
|
-
end
|
29
|
-
|
30
|
-
def drop(name)
|
31
|
-
connection.drop_column_family(name.to_s)
|
32
|
-
end
|
33
|
-
|
34
|
-
def rename(old_name, new_name)
|
35
|
-
connection.rename_column_family(old_name.to_s, new_name.to_s)
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
def connection
|
40
|
-
CassandraObject::Base.connection
|
41
|
-
end
|
42
|
-
|
43
|
-
def post_process_column_family(cf)
|
44
|
-
col_type = cf.column_type
|
45
|
-
if col_type && COLUMN_TYPES.has_key?(col_type)
|
46
|
-
cf.column_type = COLUMN_TYPES[col_type]
|
47
|
-
end
|
48
|
-
|
49
|
-
cf
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module CassandraObject
|
2
|
-
module Tasks
|
3
|
-
class Keyspace
|
4
|
-
def exists?(name)
|
5
|
-
connection.keyspaces.include? name.to_s
|
6
|
-
end
|
7
|
-
|
8
|
-
def create(name, options = {})
|
9
|
-
keyspace = Cassandra::Keyspace.new
|
10
|
-
keyspace.name = name.to_s
|
11
|
-
keyspace.replication_factor = options[:replication_factor] || 1
|
12
|
-
keyspace.strategy_class = options[:strategy_class] || 'org.apache.cassandra.locator.SimpleStrategy'
|
13
|
-
keyspace.cf_defs = options[:cf_defs] || []
|
14
|
-
|
15
|
-
connection.add_keyspace keyspace
|
16
|
-
end
|
17
|
-
|
18
|
-
def drop(name)
|
19
|
-
connection.drop_keyspace name.to_s
|
20
|
-
end
|
21
|
-
|
22
|
-
def set(name)
|
23
|
-
connection.keyspace = name.to_s
|
24
|
-
end
|
25
|
-
|
26
|
-
def get
|
27
|
-
connection.keyspace
|
28
|
-
end
|
29
|
-
|
30
|
-
def clear
|
31
|
-
return puts 'Cannot clear system keyspace' if connection.keyspace == 'system'
|
32
|
-
|
33
|
-
connection.clear_keyspace!
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
def connection
|
38
|
-
@connection ||= begin
|
39
|
-
Cassandra.new('system', CassandraObject::Base.connection.servers)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class CassandraObject::Tasks::ColumnFamilyTest < CassandraObject::TestCase
|
4
|
-
setup do
|
5
|
-
column_family_task.drop('Gadgets') if column_family_task.exists?('Gadgets')
|
6
|
-
column_family_task.drop('Widgets') if column_family_task.exists?('Widgets')
|
7
|
-
end
|
8
|
-
|
9
|
-
test 'create' do
|
10
|
-
assert !column_family_task.exists?('Widgets')
|
11
|
-
column_family_task.create 'Widgets'
|
12
|
-
assert column_family_task.exists?('Widgets')
|
13
|
-
end
|
14
|
-
|
15
|
-
# test 'rename' do
|
16
|
-
# column_family_task.create 'Widgets'
|
17
|
-
# column_family_task.rename 'Widgets', 'Gadgets'
|
18
|
-
#
|
19
|
-
# sleep 2
|
20
|
-
#
|
21
|
-
# assert !column_family_task.exists?('Widgets')
|
22
|
-
# assert column_family_task.exists?('Gadgets')
|
23
|
-
# end
|
24
|
-
|
25
|
-
private
|
26
|
-
def column_family_task
|
27
|
-
@column_family_task ||= CassandraObject::Tasks::ColumnFamily.new(CassandraObject::Base.connection.keyspace)
|
28
|
-
end
|
29
|
-
end
|