sessionm-cassandra_object 4.0.1 → 4.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6052d6c720f923eec9b114106e5a49d970348bcf
4
- data.tar.gz: b3258446a414824776c5e4fd7cc6515448b6220a
3
+ metadata.gz: 3e1cdbe60a0e5d0445c81ca4a2cbbfe124392c1f
4
+ data.tar.gz: 8dbd7771413345f0477fdd98d8ae2198bdb6d26f
5
5
  SHA512:
6
- metadata.gz: 3a42956c3dcbd6ebf8ea93c6029a4b3dad8e3eebe59287ff0c77b6e06937a0f673b5375eb73c7c42a93bf5205582535c3ff481d1695e0ff403f1924b32106995
7
- data.tar.gz: 254dadc67d4d95237075a962cd6037bad649afd0c4541a82d5fb209388ad06d6aac5e2992b69e4857c926f5cf1ebaf4ea819ebc47ce55a298c78f9eabc23915e
6
+ metadata.gz: 47dc210f1595a73cbd8a900021facd42bfae16e81292d2b079f9ffb053e7f6dc72ad6864ccfe832110167f566c77540c417b4e75457e48347eabacac639a7c9a
7
+ data.tar.gz: 580fc7a117c73831b5b4cc6857a714e2cffdfb89187c741f0838afea11c701eec968b4f63f17b11985e6b52a4e73b9b70a201f8d74e4d4f13ad5d8bca861c4b6
data/.gitignore CHANGED
@@ -1,2 +1,10 @@
1
- Gemfile.lock
1
+ .bundle
2
+ tmp/
3
+ !.gitignore
4
+ *~
5
+ \#*\#
6
+ .\#*
7
+ cms/
8
+ .DS_Store
9
+ .*.swp
2
10
  *.gem
data/Gemfile CHANGED
@@ -1,6 +1,12 @@
1
1
  source 'http://gems.prod.sessionm.com'
2
2
 
3
- gem 'rails', :require => 'rails/all'
3
+ gem 'activesupport', :require => 'active_support/all'
4
+ gem 'activerecord', :require => 'active_record'
4
5
 
5
6
  gem 'simple_uuid', '0.2.2'
6
7
  gem 'cassandra-driver', :require => 'cassandra'
8
+
9
+ group :test, :spec do
10
+ gem 'rspec'
11
+ gem "mocha"
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,60 @@
1
+ GEM
2
+ remote: http://gems.prod.sessionm.com/
3
+ specs:
4
+ activemodel (4.2.1)
5
+ activesupport (= 4.2.1)
6
+ builder (~> 3.1)
7
+ activerecord (4.2.1)
8
+ activemodel (= 4.2.1)
9
+ activesupport (= 4.2.1)
10
+ arel (~> 6.0)
11
+ activesupport (4.2.1)
12
+ i18n (~> 0.7)
13
+ json (~> 1.7, >= 1.7.7)
14
+ minitest (~> 5.1)
15
+ thread_safe (~> 0.3, >= 0.3.4)
16
+ tzinfo (~> 1.1)
17
+ arel (6.0.0)
18
+ builder (3.2.2)
19
+ cassandra-driver (2.1.3)
20
+ ione (~> 1.2)
21
+ diff-lcs (1.2.5)
22
+ i18n (0.7.0)
23
+ ione (1.2.0)
24
+ json (1.8.2)
25
+ macaddr (1.6.1)
26
+ systemu (~> 2.5.0)
27
+ metaclass (0.0.4)
28
+ minitest (5.6.1)
29
+ mocha (1.1.0)
30
+ metaclass (~> 0.0.1)
31
+ rspec (3.2.0)
32
+ rspec-core (~> 3.2.0)
33
+ rspec-expectations (~> 3.2.0)
34
+ rspec-mocks (~> 3.2.0)
35
+ rspec-core (3.2.3)
36
+ rspec-support (~> 3.2.0)
37
+ rspec-expectations (3.2.1)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.2.0)
40
+ rspec-mocks (3.2.1)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.2.0)
43
+ rspec-support (3.2.2)
44
+ simple_uuid (0.2.2)
45
+ macaddr (= 1.6.1)
46
+ systemu (2.5.2)
47
+ thread_safe (0.3.5)
48
+ tzinfo (1.2.2)
49
+ thread_safe (~> 0.1)
50
+
51
+ PLATFORMS
52
+ ruby
53
+
54
+ DEPENDENCIES
55
+ activerecord
56
+ activesupport
57
+ cassandra-driver
58
+ mocha
59
+ rspec
60
+ simple_uuid (= 0.2.2)
data/config/cassandra.yml CHANGED
@@ -1,26 +1,9 @@
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
1
  test:
19
- servers: ['127.0.0.1:9160']
20
- keyspace: greyhound_test
2
+ servers: ['127.0.0.1']
3
+ keyspace: cassandra_object_test
21
4
  replication:
22
5
  strategy: org.apache.cassandra.locator.SimpleStrategy
23
- factor: 1
6
+ replication_factor: 1
24
7
  consistency:
25
8
  read_default: quorum
26
9
  write_default: quorum
@@ -31,6 +14,3 @@ test:
31
14
  connect_timeout: 0.5
32
15
  timeout: 3
33
16
  retries: 2
34
- exception_class_overrides:
35
- - CassandraThrift::InvalidRequestException
36
- - CassandraThrift::NotFoundException
@@ -1,4 +1,5 @@
1
- require 'rails/all'
1
+ require 'active_support/all'
2
+ require 'active_record'
2
3
 
3
4
  module CassandraObject
4
5
  extend ActiveSupport::Autoload
@@ -12,7 +12,11 @@ module CassandraObject
12
12
  end
13
13
 
14
14
  def client
15
- @client ||= Client.new(cluster.connect(config[:keyspace]))
15
+ @client ||= self.new_client
16
+ end
17
+
18
+ def new_client
19
+ Client.new(cluster.connect(config[:keyspace]), cluster)
16
20
  end
17
21
 
18
22
  def close
@@ -26,21 +30,22 @@ module CassandraObject
26
30
  :port => config[:port] || 9042,
27
31
  :connect_timeout => config[:thrift][:connect_timeout] || 10,
28
32
  :timeout => config[:thrift][:timeout] || 10,
29
- :logger => Rails.logger || Logger.new(STDOUT),
33
+ :logger => config[:logger] || (defined?(Rails) && Rails.logger) || Logger.new(STDOUT),
30
34
  :consistency => (config[:consistency] || {})[:write_default].try(:to_sym) || :one,
31
35
  }
32
36
  end
33
37
 
34
38
  # The client class acts like the old cassandra gem
35
39
  class Client
36
- attr_reader :session
40
+ attr_reader :session, :cluster
37
41
 
38
42
  KEY_FIELD = 'key'
39
43
  NAME_FIELD = 'column1'
40
44
  VALUE_FIELD = 'value'
41
45
 
42
- def initialize(session)
46
+ def initialize(session, cluster)
43
47
  @session = session
48
+ @cluster = cluster
44
49
  end
45
50
 
46
51
  def close
@@ -106,6 +111,40 @@ module CassandraObject
106
111
  async ? self.execute_async(query, execute_options(opts)) : self.execute(query, execute_options(opts))
107
112
  end
108
113
 
114
+ def remove(column_family, key, *args)
115
+ opts = args.pop if args.last.is_a?(Hash)
116
+ async = opts.try(:[], :async)
117
+ key = "textAsBlob('#{key}')"
118
+
119
+ query =
120
+ if args.first.nil? || args.first.is_a?(Hash)
121
+ "DELETE FROM \"#{column_family}\" WHERE #{KEY_FIELD} = #{key};"
122
+ else
123
+ "DELETE \"#{column_family}\" WHERE #{KEY_FIELD} = #{key} AND #{NAME_FIELD} = '#{args.first}';"
124
+ end
125
+
126
+ async ? self.execute_async(query, execute_options(opts)) : self.execute(query, execute_options(opts))
127
+ end
128
+
129
+ def get_range(column_family, opts={}, &blk)
130
+ key_count = opts[:key_count] || 100
131
+ query = "SELECT #{KEY_FIELD} FROM \"#{column_family}\" LIMIT #{key_count}"
132
+ keys = self.execute(query, execute_options(opts)).map { |result| result[KEY_FIELD] }
133
+ keys.size > 0 ? multi_get(column_family, keys) : {}
134
+ end
135
+
136
+ def multi_get(column_family, keys, *args)
137
+ opts = args.pop if args.last.is_a?(Hash)
138
+ keys = keys.map { |key| "textAsBlob('#{key}')" }.join(',')
139
+ results = {}
140
+ query = "SELECT * FROM \"#{column_family}\" WHERE #{KEY_FIELD} IN(#{keys})"
141
+ self.execute(query, execute_options(opts)).each do |row|
142
+ results[row[KEY_FIELD]] ||= {}
143
+ results[row[KEY_FIELD]][row[NAME_FIELD]] = row[VALUE_FIELD]
144
+ end
145
+ results
146
+ end
147
+
109
148
  def execute_options(opts)
110
149
  opts.try(:slice,
111
150
  :consistency,
@@ -115,6 +154,10 @@ module CassandraObject
115
154
  :serial_consistency
116
155
  ) || {}
117
156
  end
157
+
158
+ def has_table?(name)
159
+ self.cluster.keyspace(session.keyspace).has_table? name
160
+ end
118
161
  end
119
162
  end
120
163
  end
@@ -52,16 +52,19 @@ module CassandraObject
52
52
  end
53
53
 
54
54
  def remove(key)
55
- begin
56
- CassandraObject::Base.with_connection(key, :write) do
57
- ActiveSupport::Notifications.instrument("remove.cassandra_object", column_family: relationships_column_family, key: key) do
58
- connection.remove(relationships_column_family, key.to_s, consistency: thrift_write_consistency)
55
+ if connection.has_table?(relationships_column_family)
56
+ begin
57
+ CassandraObject::Base.with_connection(key, :write) do
58
+ ActiveSupport::Notifications.instrument("remove.cassandra_object", column_family: relationships_column_family, key: key) do
59
+ connection.remove(relationships_column_family, key.to_s, consistency: thrift_write_consistency)
60
+ end
59
61
  end
62
+ rescue Cassandra::Errors::InvalidError => e
63
+ # pretty sure this is not the correct message for cassandra-driver gem, will need to investigate the actual message
64
+ raise e unless e.message =~ /unconfigured columnfamily/i
60
65
  end
61
- rescue Cassandra::Error => e
62
- # pretty sure this is not the correct message for cassandra-driver gem, will need to investigate the actual message
63
- raise e unless e.message =~ /invalid column family/i
64
66
  end
67
+
65
68
  super
66
69
  end
67
70
  end
@@ -8,4 +8,4 @@ module CassandraObject
8
8
  require 'cassandra_object/generators/migration_generator'
9
9
  end
10
10
  end
11
- end
11
+ end if defined?(Rails)
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'sessionm-cassandra_object'
5
- s.version = '4.0.1'
5
+ s.version = '4.0.2'
6
6
  s.description = 'Cassandra ActiveModel'
7
7
  s.summary = 'Cassandra ActiveModel'
8
8
 
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe CassandraObject::Base do
4
+ it "should be able to a create/fetch/destroy an issue" do
5
+ issue = Issue.create! :description => 'web site not working', :worth => 1.5
6
+ expect(issue.persisted?).to be true
7
+ issue = Issue.find issue.id
8
+ expect(issue.worth.to_f).to be 1.5
9
+ issue.destroy
10
+ expect(Issue.find_by_id(issue.id)).to be nil
11
+ end
12
+
13
+ it "should be able to get the first issue" do
14
+ issue = Issue.create! :description => 'web site not working', :worth => 1.5
15
+ expect(Issue.first.id).to eq issue.id
16
+ end
17
+
18
+ it "should be able to get all issues" do
19
+ issue1 = Issue.create! :description => 'web site not working', :worth => 1.5
20
+ issue2 = Issue.create! :description => 'button is disabled', :worth => 0.2
21
+ expect(Issue.all.map(&:id).sort).to eq [issue1.id, issue2.id].sort
22
+ end
23
+
24
+ it "should be able to find issues by id" do
25
+ issue1 = Issue.create! :description => 'web site not working', :worth => 1.5
26
+ issue2 = Issue.create! :description => 'button is disabled', :worth => 0.2
27
+ issue3 = Issue.create! :description => 'button is disabled', :worth => 0.2
28
+ expect(Issue.find_with_ids(issue1.id, issue2.id).map(&:id).sort).to eq [issue1.id, issue2.id].sort
29
+ end
30
+ end
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+
3
+ ENV["RAILS_ENV"] = 'test'
4
+
5
+ require File.expand_path('../../config/environment', __FILE__)
6
+
7
+ Bundler.require :default, :test
8
+
9
+ Dir[BASE_DIR.join("spec/support/**/*.rb")].each { |f| require f }
10
+
11
+ KEYSPACE = 'cassandra_object_test'
12
+
13
+ CassandraObject::Adapters::CassandraDriver.new(CassandraObject::Base.connection_spec).cluster.tap do |cluster|
14
+ cluster.connect.tap do |session|
15
+ session.execute("DROP KEYSPACE #{KEYSPACE}") if cluster.has_keyspace?(KEYSPACE)
16
+ replication = Cassandra::Keyspace::Replication.new('org.apache.cassandra.locator.SimpleStrategy', 'replication_factor' => 1)
17
+ keyspace = Cassandra::Keyspace.new(KEYSPACE, false, replication, [], [])
18
+ session.execute keyspace.to_cql
19
+ session.close
20
+ end
21
+
22
+ cluster.connect(KEYSPACE).tap do |session|
23
+ session.execute <<-CQL
24
+ CREATE TABLE "Issues" (
25
+ key blob,
26
+ column1 text,
27
+ value text,
28
+ PRIMARY KEY (key, column1)
29
+ )
30
+ CQL
31
+
32
+ session.execute <<-CQL
33
+ CREATE TABLE "Counters" (
34
+ key blob,
35
+ column1 text,
36
+ value counter,
37
+ PRIMARY KEY (key, column1)
38
+ )
39
+ CQL
40
+ session.close
41
+ end
42
+
43
+ cluster.close
44
+ end
45
+
46
+ RSpec.configure do |config|
47
+
48
+ config.before(:each) do
49
+ Cassandra::Session.delete_all_populated_column_families
50
+ end
51
+
52
+ config.after(:all) do
53
+ # we need to call this at the end of each set of tests because if the last test in an rspec file inserts data
54
+ # into Cassandra it will not be cleaned up at the beginning of the next test in the next rspec file. This was
55
+ # first spotted in ref #361. The test run in autotest called before_create on UserTransaction and added that
56
+ # class to @@populated_column_families, but when you run an individual file after autotest @@populated_column_families
57
+ # is empty, so Cassandra doesn't get cleaned up properly...
58
+ Cassandra::Session.delete_all_populated_column_families
59
+ end
60
+ end
@@ -0,0 +1,30 @@
1
+ require 'cassandra'
2
+
3
+ module Cassandra
4
+ class Session
5
+ @@populated_column_families = Set.new
6
+ @@test_client = CassandraObject::Adapters::CassandraDriver.new(CassandraObject::Base.connection_spec).client
7
+
8
+ def self.truncate_populated_column_family(column_family)
9
+ @@test_client.execute "TRUNCATE \"#{column_family}\""
10
+ end
11
+
12
+ def self.delete_all_populated_column_families
13
+ unless @@populated_column_families.empty?
14
+ @@populated_column_families.each { |column_family| self.truncate_populated_column_family(column_family) }
15
+ @@populated_column_families.clear
16
+ end
17
+ end
18
+
19
+ [:execute_async].each do |method|
20
+ define_method("#{method}_with_populated_tracking") do |*args|
21
+ send("#{method}_without_populated_tracking", *args).tap do
22
+ if args.first =~ /(insert into|update) "(.+?)"/i
23
+ @@populated_column_families.add $2
24
+ end
25
+ end
26
+ end
27
+ alias_method_chain method, :populated_tracking
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ class Counter < CassandraObject::Base
2
+ self.write_consistency = :all
3
+ end
@@ -0,0 +1,11 @@
1
+ class Issue < CassandraObject::Base
2
+ key :uuid
3
+ attribute :description, :type => :string
4
+ attribute :worth, :type => :decimal, :precision => 100
5
+ attribute :name, :type => :string
6
+ before_validation :set_defaults, :on => :create
7
+
8
+ def set_defaults
9
+ self.name ||= 'default name'
10
+ end
11
+ end
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.0.1
4
+ version: 4.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Koziarski
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-05-06 00:00:00.000000000 Z
13
+ date: 2015-05-11 00:00:00.000000000 Z
14
14
  dependencies: []
15
15
  description: Cassandra ActiveModel
16
16
  email: doug@sessionm.com
@@ -24,6 +24,7 @@ files:
24
24
  - ".ruby-version"
25
25
  - CHANGELOG
26
26
  - Gemfile
27
+ - Gemfile.lock
27
28
  - LICENSE
28
29
  - MIT-LICENSE
29
30
  - README.markdown
@@ -92,6 +93,11 @@ files:
92
93
  - lib/cassandra_object/validations.rb
93
94
  - script/console.rb
94
95
  - sessionm-cassandra_object.gemspec
96
+ - spec/cassandra_object/base_spec.rb
97
+ - spec/spec_helper.rb
98
+ - spec/support/cassandra.rb
99
+ - spec/support/models/counter.rb
100
+ - spec/support/models/issue.rb
95
101
  - test/README
96
102
  - test/active_model_test.rb
97
103
  - test/attributes_test.rb
@@ -141,6 +147,11 @@ signing_key:
141
147
  specification_version: 4
142
148
  summary: Cassandra ActiveModel
143
149
  test_files:
150
+ - spec/cassandra_object/base_spec.rb
151
+ - spec/spec_helper.rb
152
+ - spec/support/cassandra.rb
153
+ - spec/support/models/counter.rb
154
+ - spec/support/models/issue.rb
144
155
  - test/README
145
156
  - test/active_model_test.rb
146
157
  - test/attributes_test.rb