gotime-cassandra_object 2.1.2 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gotime-cassandra_object (2.1.1)
4
+ gotime-cassandra_object (2.1.2)
5
5
  cassandra (~> 0.11.3)
6
6
  rails (~> 3.0)
7
7
 
data/README.markdown CHANGED
@@ -1,79 +1,8 @@
1
1
  # Cassandra Object
2
2
 
3
- Cassandra Object provides a nice API for working with [Cassandra](http://incubator.apache.org/cassandra/). CassandraObjects are mostly duck-type compatible with ActiveRecord objects so most of your controller code should work ok. Note that they're *mostly* compatible, Cassandra has no support for dynamic queries, or sorting. So the following kinds of operations aren't supported and *never will be*.
3
+ Cassandra Object provides a API for working with [Cassandra](http://incubator.apache.org/cassandra/).
4
4
 
5
- * `:order`
6
- * `:conditions`
7
- * `:joins`
8
- * `:group`
9
-
10
- There isn't much in the way of documentation yet, but a few examples.
5
+ Example:
11
6
 
12
7
  class Customer < CassandraObject::Base
13
- attribute :first_name, :type => :string
14
- attribute :last_name, :type => :string
15
- attribute :date_of_birth, :type => :date
16
- attribute :signed_up_at, :type => :time_with_zone
17
-
18
- validate :should_be_cool
19
-
20
- key :uuid
21
-
22
- index :date_of_birth
23
-
24
- association :invoices, :unique=>false, :inverse_of=>:customer
25
-
26
- private
27
-
28
- def should_be_cool
29
- unless ["Michael", "Anika", "Evan", "James"].include?(first_name)
30
- errors.add(:first_name, "must be that of a cool person")
31
- end
32
- end
33
- end
34
-
35
- class Invoice < CassandraObject::Base
36
- attribute :number, :type=>:integer
37
- attribute :total, :type=>:float
38
- attribute :gst_number, :type=>:string
39
-
40
- # indexes can have a single entry also.
41
- index :number, :unique=>true
42
-
43
- # bi-directional associations with read-repair support.
44
- association :customer, :unique=>true, :inverse_of=>:invoices
45
-
46
- # Read migration support
47
- migrate 1 do |attrs|
48
- attrs["total"] ||= rand(2000) / 100.0
49
- end
50
-
51
- migrate 2 do |attrs|
52
- attrs["gst_number"] = "66-666-666"
53
- end
54
-
55
- key :natural, :attributes => :number
56
8
  end
57
-
58
- @invoice = Invoice.get("12345")
59
- @invoice.customer.invoices.all.include?(@invoice) # true
60
-
61
- # FAQ
62
-
63
- ## How do I make this work?
64
-
65
- Here are some basic directions:
66
-
67
- 1. `git clone git://github.com/NZKoz/cassandra_object.git`
68
- 2. Run the bundler `gem bundle`
69
- 3. Make sure the tests pass `rake test`
70
-
71
- This gem has backwards compatibility with active support version 2.3.x, this is to enable people to use it with rails 2.3 applications. This backwards compatibility may not continue after the 1.0 release.
72
-
73
- ## Should I use this in production?
74
-
75
- Only if you're looking to help out with the development, there are a bunch of rough edges right now.
76
-
77
- ## Why do you use a superclass and not a module.
78
-
79
- Because.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'gotime-cassandra_object'
5
- s.version = '2.1.2'
5
+ s.version = '2.2.0'
6
6
  s.description = 'Cassandra ActiveModel'
7
7
  s.summary = 'Cassandra ActiveModel'
8
8
 
@@ -6,6 +6,7 @@ module CassandraObject
6
6
  autoload :Base
7
7
  autoload :Connection
8
8
  autoload :Attributes
9
+ autoload :PrimaryKey
9
10
  autoload :Dirty
10
11
  autoload :Consistency
11
12
  autoload :Persistence
@@ -3,6 +3,7 @@ require 'set'
3
3
 
4
4
  require 'cassandra_object/log_subscriber'
5
5
  require 'cassandra_object/types'
6
+ require 'cassandra_object/errors'
6
7
 
7
8
  module CassandraObject
8
9
  class Base
@@ -28,10 +29,11 @@ module CassandraObject
28
29
  extend ActiveSupport::DescendantsTracker
29
30
 
30
31
  include Connection
31
- include Callbacks
32
+ include PrimaryKey
32
33
  include Identity
33
34
  include Attributes
34
35
  include Persistence
36
+ include Callbacks
35
37
  include Indexes
36
38
  include Dirty
37
39
  include Validation
@@ -6,5 +6,22 @@ module CassandraObject
6
6
  extend ActiveModel::Callbacks
7
7
  define_model_callbacks :save, :create, :destroy, :update
8
8
  end
9
+
10
+ def destroy #:nodoc:
11
+ _run_destroy_callbacks { super }
12
+ end
13
+
14
+ private
15
+ def create_or_update #:nodoc:
16
+ _run_save_callbacks { super }
17
+ end
18
+
19
+ def create #:nodoc:
20
+ _run_create_callbacks { super }
21
+ end
22
+
23
+ def update(*) #:nodoc:
24
+ _run_update_callbacks { super }
25
+ end
9
26
  end
10
27
  end
@@ -0,0 +1,10 @@
1
+ module CassandraObject
2
+ class CasssandraObjectError < StandardError
3
+ end
4
+
5
+ class RecordNotSaved < CasssandraObjectError
6
+ end
7
+
8
+ class RecordNotFound < CasssandraObjectError
9
+ end
10
+ end
@@ -2,6 +2,14 @@ module CassandraObject
2
2
  module FinderMethods
3
3
  extend ActiveSupport::Concern
4
4
  module ClassMethods
5
+ def find(key)
6
+ if parse_key(key) && attributes = connection.get(column_family, key)
7
+ instantiate(key, attributes)
8
+ else
9
+ raise CassandraObject::RecordNotFound
10
+ end
11
+ end
12
+
5
13
  def all(options = {})
6
14
  options = {:consistency => self.read_consistency, :limit => 100}.merge(options)
7
15
  count = options[:limit]
@@ -25,6 +25,8 @@ module CassandraObject
25
25
  # Parse should create a new key object from the 'to_param' format
26
26
  def parse(string)
27
27
  UUID.new(string)
28
+ rescue
29
+ nil
28
30
  end
29
31
 
30
32
  # create should create a new key object from the cassandra format.
@@ -89,62 +89,78 @@ module CassandraObject
89
89
  def column_family_configuration
90
90
  [{:Name => column_family, :CompareWith => "UTF8Type"}]
91
91
  end
92
+ end
92
93
 
94
+ def new_record?
95
+ @new_record
93
96
  end
94
97
 
95
- def save(options={})
96
- _run_save_callbacks do
97
- create_or_update
98
- end
98
+ def destroyed?
99
+ @destroyed
99
100
  end
100
-
101
- def create_or_update
102
- result = persisted? ? update : create
103
- result != false
101
+
102
+ def persisted?
103
+ !(new_record? || destroyed?)
104
104
  end
105
-
106
- def create
107
- _run_create_callbacks do
108
- @key ||= self.class.next_key(self)
109
- _write
110
- @new_record = false
111
- @key
105
+
106
+ def save(*)
107
+ begin
108
+ create_or_update
109
+ rescue CassandraObject::RecordInvalid
110
+ false
112
111
  end
113
112
  end
114
-
115
- def update
116
- _run_update_callbacks do
117
- _write
118
- end
113
+
114
+ def save!
115
+ create_or_update || raise(RecordNotSaved)
119
116
  end
120
-
121
- def _write
122
- changed_attributes = changed.inject({}) { |h, n| h[n] = read_attribute(n); h }
123
- self.class.write(key, changed_attributes, schema_version)
117
+
118
+ def destroy
119
+ self.class.remove(key)
120
+ @destroyed = true
121
+ freeze
124
122
  end
125
123
 
126
- def new_record?
127
- @new_record
124
+ def update_attribute(name, value)
125
+ name = name.to_s
126
+ send("#{name}=", value)
127
+ save(:validate => false)
128
128
  end
129
129
 
130
- def destroyed?
131
- @destroyed
130
+ def update_attributes(attributes)
131
+ self.attributes = attributes
132
+ save
132
133
  end
133
134
 
134
- def persisted?
135
- !(new_record? || destroyed?)
135
+ def update_attributes!(attributes)
136
+ self.attributes = attributes
137
+ save!
136
138
  end
137
139
 
138
- def destroy
139
- _run_destroy_callbacks do
140
- self.class.remove(key)
141
- @destroyed = true
142
- freeze
143
- end
140
+ def reload
141
+ @attributes.update(self.class.find(self.id).instance_variable_get('@attributes'))
144
142
  end
143
+
144
+ private
145
+ def create_or_update
146
+ result = new_record? ? create : update
147
+ result != false
148
+ end
149
+
150
+ def create
151
+ @key ||= self.class.next_key(self)
152
+ write
153
+ @new_record = false
154
+ @key
155
+ end
145
156
 
146
- def reload
147
- self.class.get(self.key)
148
- end
157
+ def update
158
+ write
159
+ end
160
+
161
+ def write
162
+ changed_attributes = changed.inject({}) { |h, n| h[n] = read_attribute(n); h }
163
+ self.class.write(key, changed_attributes, schema_version)
164
+ end
149
165
  end
150
166
  end
@@ -0,0 +1,12 @@
1
+ module CassandraObject
2
+ module PrimaryKey
3
+ def id
4
+ key.to_s
5
+ end
6
+
7
+ def id=(key)
8
+ self.key = self.class.parse_key(key)
9
+ id
10
+ end
11
+ end
12
+ end
@@ -25,7 +25,7 @@ module CassandraObject
25
25
  new(attributes).tap &:save!
26
26
  end
27
27
  end
28
-
28
+
29
29
  def valid?
30
30
  run_callbacks :validation do
31
31
  super
@@ -1,11 +1,17 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class CassandraObject::FinderMethodsTest < CassandraObject::TestCase
4
- test 'first' do
5
- first_issue = Issue.create
6
- second_issue = Issue.create
4
+ test 'find' do
5
+ persisted_issue = Issue.create
6
+ found_issue = Issue.find(persisted_issue.id)
7
7
 
8
- assert [first_issue, second_issue].include?(Issue.first)
8
+ assert_equal persisted_issue, found_issue
9
+ end
10
+
11
+ test 'find missing record' do
12
+ assert_raise CassandraObject::RecordNotFound do
13
+ Issue.find('what')
14
+ end
9
15
  end
10
16
 
11
17
  test 'all' do
@@ -15,6 +21,13 @@ class CassandraObject::FinderMethodsTest < CassandraObject::TestCase
15
21
  assert_equal [first_issue, second_issue].to_set, Issue.all.to_set
16
22
  end
17
23
 
24
+ test 'first' do
25
+ first_issue = Issue.create
26
+ second_issue = Issue.create
27
+
28
+ assert [first_issue, second_issue].include?(Issue.first)
29
+ end
30
+
18
31
  test 'find_with_ids' do
19
32
  first_issue = Issue.create
20
33
  second_issue = Issue.create
@@ -1,6 +1,16 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class CassandraObject::IdentityTest < CassandraObject::TestCase
4
+ test 'parse_key' do
5
+ # p "Issue.parse_key('bb4cbbbc-b7c7-11e0-9ca2-732604ff41fe') = #{Issue.parse_key('bb4cbbbc-b7c7-11e0-9ca2-732604ff41fe').class}"
6
+ assert_kind_of(
7
+ CassandraObject::Identity::UUIDKeyFactory::UUID,
8
+ Issue.parse_key('bb4cbbbc-b7c7-11e0-9ca2-732604ff41fe')
9
+ )
10
+
11
+ assert_nil Issue.parse_key('fail')
12
+ end
13
+
4
14
  test 'equality of new records' do
5
15
  assert_not_equal Issue.new, Issue.new
6
16
  end
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class CassandraObject::PersistenceTest < CassandraObject::TestCase
4
- test 'persisted' do
4
+ test 'persistance inquiries' do
5
5
  issue = Issue.new
6
6
  assert issue.new_record?
7
7
  assert !issue.persisted?
@@ -9,9 +9,76 @@ class CassandraObject::PersistenceTest < CassandraObject::TestCase
9
9
  issue.save
10
10
  assert issue.persisted?
11
11
  assert !issue.new_record?
12
+ end
13
+
14
+ test 'save' do
15
+ issue = Issue.new
16
+ issue.save
17
+
18
+ assert_equal issue, Issue.find(issue.id)
19
+ end
12
20
 
21
+ test 'save!' do
22
+ begin
23
+ Issue.validates(:description, presence: true)
24
+
25
+ issue = Issue.new(description: 'bad')
26
+ issue.save!
27
+
28
+ issue = Issue.new
29
+ assert_raise(CassandraObject::RecordInvalid) { issue.save! }
30
+ ensure
31
+ Issue.reset_callbacks(:validate)
32
+ end
33
+ end
34
+
35
+ test 'destroy' do
36
+ issue = Issue.create
13
37
  issue.destroy
38
+
14
39
  assert issue.destroyed?
15
40
  assert !issue.persisted?
41
+ assert !issue.new_record?
42
+ end
43
+
44
+ test 'update_attribute' do
45
+ issue = Issue.create
46
+ issue.update_attribute(:description, 'lol')
47
+
48
+ assert !issue.changed?
49
+ assert_equal 'lol', issue.description
50
+ end
51
+
52
+ test 'update_attributes' do
53
+ issue = Issue.create
54
+ issue.update_attributes(description: 'lol')
55
+
56
+ assert !issue.changed?
57
+ assert_equal 'lol', issue.description
58
+ end
59
+
60
+ test 'update_attributes!' do
61
+ begin
62
+ Issue.validates(:description, presence: true)
63
+
64
+ issue = Issue.new(description: 'bad')
65
+ issue.save!
66
+
67
+ assert_raise CassandraObject::RecordInvalid do
68
+ issue.update_attributes! description: ''
69
+ end
70
+ ensure
71
+ Issue.reset_callbacks(:validate)
72
+ end
73
+ end
74
+
75
+ test 'reload' do
76
+ persisted_issue = Issue.create
77
+ fresh_issue = Issue.find(persisted_issue.id)
78
+ fresh_issue.update_attribute(:description, 'say what')
79
+
80
+ assert_nil persisted_issue.description
81
+ persisted_issue.reload
82
+ assert_equal 'say what', persisted_issue.description
16
83
  end
17
84
  end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ class CassandraObject::PrimaryKeyTest < CassandraObject::TestCase
4
+ test 'id' do
5
+ issue = Issue.create
6
+
7
+ assert_equal issue.key.to_s, issue.id
8
+ end
9
+ end
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: 2.1.2
4
+ version: 2.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -14,7 +14,7 @@ date: 2011-07-26 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
17
- requirement: &2153248160 !ruby/object:Gem::Requirement
17
+ requirement: &2152763200 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: '3.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2153248160
25
+ version_requirements: *2152763200
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: cassandra
28
- requirement: &2153247700 !ruby/object:Gem::Requirement
28
+ requirement: &2152762740 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ~>
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: 0.11.3
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *2153247700
36
+ version_requirements: *2152762740
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: bundler
39
- requirement: &2153247240 !ruby/object:Gem::Requirement
39
+ requirement: &2152762280 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ~>
@@ -44,7 +44,7 @@ dependencies:
44
44
  version: 1.0.0
45
45
  type: :development
46
46
  prerelease: false
47
- version_requirements: *2153247240
47
+ version_requirements: *2152762280
48
48
  description: Cassandra ActiveModel
49
49
  email: gems@gotime.com
50
50
  executables: []
@@ -60,7 +60,6 @@ files:
60
60
  - MIT-LICENSE
61
61
  - README.markdown
62
62
  - Rakefile
63
- - TODO
64
63
  - gotime-cassandra_object.gemspec
65
64
  - lib/cassandra_object.rb
66
65
  - lib/cassandra_object/associations.rb
@@ -75,6 +74,7 @@ files:
75
74
  - lib/cassandra_object/consistency.rb
76
75
  - lib/cassandra_object/cursor.rb
77
76
  - lib/cassandra_object/dirty.rb
77
+ - lib/cassandra_object/errors.rb
78
78
  - lib/cassandra_object/finder_methods.rb
79
79
  - lib/cassandra_object/generators/migration_generator.rb
80
80
  - lib/cassandra_object/generators/templates/migration.rb.erb
@@ -91,6 +91,7 @@ files:
91
91
  - lib/cassandra_object/migrations/migration.rb
92
92
  - lib/cassandra_object/mocking.rb
93
93
  - lib/cassandra_object/persistence.rb
94
+ - lib/cassandra_object/primary_key.rb
94
95
  - lib/cassandra_object/railtie.rb
95
96
  - lib/cassandra_object/schema.rb
96
97
  - lib/cassandra_object/schema/migration.rb
@@ -143,6 +144,7 @@ files:
143
144
  - test/finder_methods_test.rb
144
145
  - test/identity_test.rb
145
146
  - test/persistence_test.rb
147
+ - test/primary_key_test.rb
146
148
  - test/test_helper.rb
147
149
  - test/timestamps_test.rb
148
150
  - test/types/array_type_test.rb
@@ -186,6 +188,7 @@ test_files:
186
188
  - test/finder_methods_test.rb
187
189
  - test/identity_test.rb
188
190
  - test/persistence_test.rb
191
+ - test/primary_key_test.rb
189
192
  - test/test_helper.rb
190
193
  - test/timestamps_test.rb
191
194
  - test/types/array_type_test.rb
data/TODO DELETED
@@ -1,2 +0,0 @@
1
- * Support for alternate column names in associations and indexes
2
- * Support for compound keys for associations e.g. "#{customer_id}:#{invoice_date}"