sessionm-cassandra_object 2.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/.gitignore +2 -0
  2. data/CHANGELOG +3 -0
  3. data/Gemfile +2 -0
  4. data/LICENSE +13 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.markdown +12 -0
  7. data/Rakefile +15 -0
  8. data/lib/cassandra_object/associations/one_to_many.rb +146 -0
  9. data/lib/cassandra_object/associations/one_to_one.rb +85 -0
  10. data/lib/cassandra_object/associations.rb +50 -0
  11. data/lib/cassandra_object/attributes.rb +97 -0
  12. data/lib/cassandra_object/base.rb +97 -0
  13. data/lib/cassandra_object/batches.rb +31 -0
  14. data/lib/cassandra_object/callbacks.rb +27 -0
  15. data/lib/cassandra_object/collection.rb +8 -0
  16. data/lib/cassandra_object/connection.rb +29 -0
  17. data/lib/cassandra_object/consistency.rb +31 -0
  18. data/lib/cassandra_object/cursor.rb +90 -0
  19. data/lib/cassandra_object/dirty.rb +32 -0
  20. data/lib/cassandra_object/errors.rb +10 -0
  21. data/lib/cassandra_object/finder_methods.rb +72 -0
  22. data/lib/cassandra_object/generators/migration_generator.rb +31 -0
  23. data/lib/cassandra_object/generators/templates/migration.rb.erb +11 -0
  24. data/lib/cassandra_object/identity/abstract_key_factory.rb +36 -0
  25. data/lib/cassandra_object/identity/custom_key_factory.rb +50 -0
  26. data/lib/cassandra_object/identity/hashed_natural_key_factory.rb +10 -0
  27. data/lib/cassandra_object/identity/key.rb +20 -0
  28. data/lib/cassandra_object/identity/natural_key_factory.rb +51 -0
  29. data/lib/cassandra_object/identity/uuid_key_factory.rb +39 -0
  30. data/lib/cassandra_object/identity.rb +52 -0
  31. data/lib/cassandra_object/log_subscriber.rb +37 -0
  32. data/lib/cassandra_object/migrations/migration.rb +15 -0
  33. data/lib/cassandra_object/migrations.rb +66 -0
  34. data/lib/cassandra_object/mocking.rb +15 -0
  35. data/lib/cassandra_object/persistence.rb +138 -0
  36. data/lib/cassandra_object/railtie.rb +11 -0
  37. data/lib/cassandra_object/schema/migration.rb +106 -0
  38. data/lib/cassandra_object/schema/migration_proxy.rb +25 -0
  39. data/lib/cassandra_object/schema/migrator.rb +213 -0
  40. data/lib/cassandra_object/schema.rb +37 -0
  41. data/lib/cassandra_object/serialization.rb +6 -0
  42. data/lib/cassandra_object/tasks/column_family.rb +90 -0
  43. data/lib/cassandra_object/tasks/keyspace.rb +89 -0
  44. data/lib/cassandra_object/tasks/ks.rake +121 -0
  45. data/lib/cassandra_object/timestamps.rb +19 -0
  46. data/lib/cassandra_object/type.rb +19 -0
  47. data/lib/cassandra_object/types/array_type.rb +16 -0
  48. data/lib/cassandra_object/types/boolean_type.rb +23 -0
  49. data/lib/cassandra_object/types/date_type.rb +20 -0
  50. data/lib/cassandra_object/types/float_type.rb +19 -0
  51. data/lib/cassandra_object/types/hash_type.rb +16 -0
  52. data/lib/cassandra_object/types/integer_type.rb +19 -0
  53. data/lib/cassandra_object/types/set_type.rb +22 -0
  54. data/lib/cassandra_object/types/string_type.rb +16 -0
  55. data/lib/cassandra_object/types/time_type.rb +27 -0
  56. data/lib/cassandra_object/types/time_with_zone_type.rb +18 -0
  57. data/lib/cassandra_object/types/utf8_string_type.rb +18 -0
  58. data/lib/cassandra_object/types.rb +11 -0
  59. data/lib/cassandra_object/validations.rb +46 -0
  60. data/lib/cassandra_object.rb +49 -0
  61. data/sessionm-cassandra_object.gemspec +26 -0
  62. data/test/active_model_test.rb +9 -0
  63. data/test/base_test.rb +28 -0
  64. data/test/batches_test.rb +30 -0
  65. data/test/connection_test.rb +28 -0
  66. data/test/consistency_test.rb +20 -0
  67. data/test/finder_methods_test.rb +49 -0
  68. data/test/identity_test.rb +30 -0
  69. data/test/persistence_test.rb +84 -0
  70. data/test/test_helper.rb +31 -0
  71. data/test/timestamps_test.rb +27 -0
  72. data/test/types/array_type_test.rb +15 -0
  73. data/test/types/boolean_type_test.rb +23 -0
  74. data/test/types/date_type_test.rb +4 -0
  75. data/test/types/float_type_test.rb +4 -0
  76. data/test/types/hash_type_test.rb +4 -0
  77. data/test/types/integer_type_test.rb +18 -0
  78. data/test/types/set_type_test.rb +17 -0
  79. data/test/types/string_type_test.rb +4 -0
  80. data/test/types/time_type_test.rb +4 -0
  81. data/test/types/utf8_string_type_test.rb +4 -0
  82. data/test/validations_test.rb +15 -0
  83. metadata +183 -0
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ *.gem
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ v 0.5.0.pre
2
+ - First release
3
+ - Rough around the corners, especially outside the core attributes/persistence stuff
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2009 Koziarski Software Ltd
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 [Michael Koziarski]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,12 @@
1
+ # Cassandra Object
2
+
3
+ Cassandra Object provides a API for working with [Cassandra](http://incubator.apache.org/cassandra/) in Rails projects.
4
+
5
+ Installation:
6
+
7
+ gem 'gotime-cassandra_object', require: 'cassandra_object'
8
+
9
+ Example:
10
+
11
+ class Customer < CassandraObject::Base
12
+ end
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+
6
+ # require File.expand_path('../lib/cassandra_object', __FILE__)
7
+
8
+ task default: :test
9
+
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << 'lib'
12
+ t.libs << 'test'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
@@ -0,0 +1,146 @@
1
+ module CassandraObject
2
+ module Associations
3
+ class OneToMany
4
+ def initialize(association_name, owner_class, options)
5
+ @association_name = association_name.to_s
6
+ @owner_class = owner_class
7
+ @target_class_name = options[:class_name] || association_name.to_s.singularize.camelize
8
+ @options = options
9
+
10
+ define_methods!
11
+ end
12
+
13
+ def find(owner, options = {})
14
+ reversed = options.has_key?(:reversed) ? options[:reversed] : reversed?
15
+ cursor = CassandraObject::Cursor.new(target_class, column_family, owner.key.to_s, @association_name, :start_after => options[:start_after], :reversed => reversed)
16
+ cursor.find(options[:limit] || 100)
17
+ end
18
+
19
+ def add(owner, record, set_inverse = true)
20
+ key = owner.key
21
+ attributes = {@association_name=>{new_key=>record.key.to_s}}
22
+ ActiveSupport::Notifications.instrument("insert.cassandra_object", :column_family => column_family, :key => key, :attributes => attributes) do
23
+ connection.insert(column_family, key.to_s, attributes, :consistency => @owner_class.thrift_write_consistency)
24
+ end
25
+ if has_inverse? && set_inverse
26
+ inverse.set_inverse(record, owner)
27
+ end
28
+ end
29
+
30
+ def new_key
31
+ SimpleUUID::UUID.new
32
+ end
33
+
34
+ def column_family
35
+ @owner_class.relationships_column_family
36
+ end
37
+
38
+ def connection
39
+ @owner_class.connection
40
+ end
41
+
42
+ def target_class
43
+ @target_class ||= @target_class_name.constantize
44
+ end
45
+
46
+ def new_proxy(owner)
47
+ OneToManyAssociationProxy.new(self, owner)
48
+ end
49
+
50
+ def has_inverse?
51
+ @options[:inverse_of]
52
+ end
53
+
54
+ def inverse
55
+ has_inverse? && target_class.associations[@options[:inverse_of]]
56
+ end
57
+
58
+ def set_inverse(owner, record)
59
+ add(owner, record, false)
60
+ end
61
+
62
+ def reversed?
63
+ @options[:reversed] == true
64
+ end
65
+
66
+ def define_methods!
67
+ @owner_class.class_eval <<-eos
68
+ def #{@association_name}
69
+ @_#{@association_name} ||= self.class.associations[:#{@association_name}].new_proxy(self)
70
+ end
71
+ eos
72
+ end
73
+ end
74
+
75
+ class OneToManyAssociationProxy
76
+ def initialize(association, owner)
77
+ @association = association
78
+ @owner = owner
79
+ end
80
+
81
+ include Enumerable
82
+ def each
83
+ target.each do |i|
84
+ yield i
85
+ end
86
+ end
87
+
88
+ def [](index)
89
+ to_a[index]
90
+ end
91
+
92
+ def <<(record)
93
+ @association.add(@owner, record)
94
+ if loaded?
95
+ @target << record
96
+ end
97
+ end
98
+
99
+ # Get the targets of this association proxy
100
+ #
101
+ # @param [Hash] options the options with which to modify this query
102
+ # @option options [String] :start_after the key after which to start returning results
103
+ # @option options [Boolean] :reversed (false or association default) return the results in reverse order
104
+ # @option options [Integer] :limit the max number of results to return
105
+ # @return [Array<CassandraObject::Base>] an array of objects of type self#target_class
106
+ #
107
+ def all(options = {})
108
+ @association.find(@owner, options)
109
+ end
110
+
111
+ # Create a record of the associated type with
112
+ # the supplied attributes and add it to this
113
+ # association
114
+ #
115
+ # @param [Hash] attributes the attributes with which to create the object
116
+ # @return [CassandraObject::Base] the newly created object
117
+ #
118
+ def create(attributes)
119
+ @association.target_class.create(attributes).tap do |record|
120
+ if record.valid?
121
+ self << record
122
+ end
123
+ end
124
+ end
125
+
126
+ def create!(attributes)
127
+ @association.target_class.create!(attributes).tap do |record|
128
+ self << record
129
+ end
130
+ end
131
+
132
+ def target
133
+ @target ||= begin
134
+ @loaded = true
135
+ @association.find(@owner)
136
+ end
137
+ end
138
+
139
+ alias to_a target
140
+
141
+ def loaded?
142
+ defined?(@loaded) && @loaded
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,85 @@
1
+ module CassandraObject
2
+ module Associations
3
+ class OneToOne
4
+ def initialize(association_name, owner_class, options)
5
+ @association_name = association_name.to_s
6
+ @owner_class = owner_class
7
+ @target_class_name = options[:class_name] || association_name.to_s.camelize
8
+ @options = options
9
+
10
+ define_methods!
11
+ end
12
+
13
+ def define_methods!
14
+ @owner_class.class_eval <<-eos
15
+ def #{@association_name}
16
+ @_#{@association_name} ||= self.class.associations[:#{@association_name}].find(self)
17
+ end
18
+
19
+ def #{@association_name}=(record)
20
+ @_#{@association_name} = record
21
+ self.class.associations[:#{@association_name}].set(self, record)
22
+ end
23
+ eos
24
+ end
25
+
26
+ def clear(owner)
27
+ ActiveSupport::Notifications.instrument("remove.cassandra_object", :column_family => column_family, :key => owner.key, :columns => @association_name) do
28
+ connection.remove(column_family, owner.key.to_s, @association_name)
29
+ end
30
+ end
31
+
32
+ def find(owner)
33
+ if key = connection.get(column_family, owner.key.to_s, @association_name.to_s, :count=>1).values.first
34
+ target_class.get(key)
35
+ else
36
+ nil
37
+ end
38
+ end
39
+
40
+ def set(owner, record, set_inverse = true)
41
+ clear(owner)
42
+ key = owner.key
43
+ attributes = {@association_name=>{new_key=>record.key.to_s}}
44
+ ActiveSupport::Notifications.instrument("insert.cassandra_object", :column_family => column_family, :key => key, :attributes => attributes) do
45
+ connection.insert(column_family, key.to_s, attributes, :consistency => @owner_class.thrift_write_consistency)
46
+ end
47
+ if has_inverse? && set_inverse
48
+ inverse.set_inverse(record, owner)
49
+ end
50
+ end
51
+
52
+ def new_key
53
+ SimpleUUID::UUID.new
54
+ end
55
+
56
+ def set_inverse(owner, record)
57
+ set(owner, record, false)
58
+ end
59
+
60
+ def has_inverse?
61
+ @options[:inverse_of]
62
+ end
63
+
64
+ def inverse
65
+ has_inverse? && target_class.associations[@options[:inverse_of]]
66
+ end
67
+
68
+ def column_family
69
+ @owner_class.relationships_column_family
70
+ end
71
+
72
+ def connection
73
+ @owner_class.connection
74
+ end
75
+
76
+ def target_class
77
+ @target_class ||= @target_class_name.constantize
78
+ end
79
+
80
+ def new_proxy(owner)
81
+ # OneToManyAssociationProxy.new(self, owner)
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,50 @@
1
+ module CassandraObject
2
+ module Associations
3
+ extend ActiveSupport::Concern
4
+ extend ActiveSupport::Autoload
5
+
6
+ # TODO: is this the convention?
7
+ include ActiveRecord::Reflection
8
+ include ActiveRecord::Associations
9
+
10
+ autoload :OneToMany
11
+ autoload :OneToOne
12
+
13
+ included do
14
+ class_inheritable_hash :associations
15
+ end
16
+
17
+ module ClassMethods
18
+ def relationships_column_family=(column_family)
19
+ @relationships_column_family = column_family
20
+ end
21
+
22
+ def relationships_column_family
23
+ @relationships_column_family || "#{name}Relationships"
24
+ end
25
+
26
+ def column_family_configuration
27
+ super << {:Name=>relationships_column_family, :CompareWith=>"UTF8Type", :CompareSubcolumnsWith=>"TimeUUIDType", :ColumnType=>"Super"}
28
+ end
29
+
30
+ def association(association_name, options= {})
31
+ if options[:unique]
32
+ write_inheritable_hash(:associations, {association_name => OneToOne.new(association_name, self, options)})
33
+ else
34
+ write_inheritable_hash(:associations, {association_name => OneToMany.new(association_name, self, options)})
35
+ end
36
+ end
37
+
38
+ def remove(key)
39
+ begin
40
+ ActiveSupport::Notifications.instrument("remove.cassandra_object", column_family: relationships_column_family, key: key) do
41
+ connection.remove(relationships_column_family, key.to_s, consistency: thrift_write_consistency)
42
+ end
43
+ rescue Cassandra::AccessError => e
44
+ raise e unless e.message =~ /Invalid column family/
45
+ end
46
+ super
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,97 @@
1
+ module CassandraObject
2
+ class Attribute
3
+ attr_reader :name, :converter, :expected_type
4
+ def initialize(name, converter, expected_type)
5
+ @name = name.to_s
6
+ @converter = converter
7
+ @expected_type = expected_type
8
+ end
9
+
10
+ def check_value!(value)
11
+ return value if value.nil?
12
+ value.kind_of?(expected_type) ? value : converter.decode(value)
13
+ end
14
+ end
15
+
16
+ module Attributes
17
+ extend ActiveSupport::Concern
18
+ include ActiveModel::AttributeMethods
19
+
20
+ module ClassMethods
21
+ def attribute(name, options)
22
+ if model_attributes.empty?
23
+ self.model_attributes = {}.with_indifferent_access
24
+ end
25
+
26
+ if type_mapping = CassandraObject::Type.get_mapping(options[:type])
27
+ converter = type_mapping.converter
28
+ expected_type = type_mapping.expected_type
29
+ elsif options[:converter]
30
+ converter = options[:converter]
31
+ expected_type = options[:type]
32
+ else
33
+ raise "Unknown type #{options[:type]}"
34
+ end
35
+
36
+ model_attributes[name] = Attribute.new(name, converter, expected_type)
37
+ end
38
+
39
+ def define_attribute_methods
40
+ super(model_attributes.keys)
41
+ end
42
+ end
43
+
44
+ included do
45
+ class_attribute :model_attributes
46
+ self.model_attributes = {}.with_indifferent_access
47
+
48
+ attribute_method_suffix("", "=")
49
+ end
50
+
51
+ def write_attribute(name, value)
52
+ if ma = self.class.model_attributes[name]
53
+ @attributes[name.to_s] = ma.check_value!(value)
54
+ else
55
+ raise NoMethodError, "Unknown attribute #{name.inspect}"
56
+ end
57
+ end
58
+
59
+ def read_attribute(name)
60
+ @attributes[name.to_s]
61
+ end
62
+
63
+ def attributes=(attributes)
64
+ attributes.each do |(name, value)|
65
+ send("#{name}=", value)
66
+ end
67
+ end
68
+
69
+ def method_missing(method_id, *args, &block)
70
+ if !self.class.attribute_methods_generated?
71
+ self.class.define_attribute_methods
72
+ send(method_id, *args, &block)
73
+ else
74
+ super
75
+ end
76
+ end
77
+
78
+ def respond_to?(*args)
79
+ self.class.define_attribute_methods unless self.class.attribute_methods_generated?
80
+ super
81
+ end
82
+
83
+ protected
84
+ def attribute_method?(name)
85
+ !!model_attributes[name.to_sym]
86
+ end
87
+
88
+ private
89
+ def attribute(name)
90
+ read_attribute(name)
91
+ end
92
+
93
+ def attribute=(name, value)
94
+ write_attribute(name, value)
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,97 @@
1
+ require 'set'
2
+
3
+ require 'cassandra_object/log_subscriber'
4
+ require 'cassandra_object/types'
5
+ require 'cassandra_object/errors'
6
+
7
+ module CassandraObject
8
+ class Base
9
+ class << self
10
+ def column_family=(column_family)
11
+ @column_family = column_family
12
+ end
13
+
14
+ def column_family
15
+ @column_family || name.pluralize
16
+ end
17
+
18
+ def base_class
19
+ klass = self
20
+ while klass.superclass != Base
21
+ klass = klass.superclass
22
+ end
23
+ klass
24
+ end
25
+
26
+ delegate :compute_type, :to => 'ActiveRecord::Base'
27
+ end
28
+
29
+ extend ActiveModel::Naming
30
+ include ActiveModel::Conversion
31
+ extend ActiveSupport::DescendantsTracker
32
+
33
+ include Connection
34
+ include Consistency
35
+ include Identity
36
+ include Attributes
37
+ include Persistence
38
+ include Callbacks
39
+ include Dirty
40
+ include Validations
41
+ include Associations
42
+ include Batches
43
+ include FinderMethods
44
+ include Timestamps
45
+
46
+ attr_accessor :key
47
+
48
+ include Serialization
49
+ include Migrations
50
+ include Mocking
51
+
52
+ def initialize(attributes={})
53
+ @key = attributes.delete(:key)
54
+ @new_record = true
55
+ @destroyed = false
56
+ @attributes = {}.with_indifferent_access
57
+ self.attributes = attributes
58
+ @schema_version = self.class.current_schema_version
59
+ end
60
+
61
+ def attributes
62
+ @attributes.merge(:id => id)
63
+ end
64
+
65
+ def to_param
66
+ id.to_s if persisted?
67
+ end
68
+
69
+ def hash
70
+ id.hash
71
+ end
72
+
73
+ def ==(comparison_object)
74
+ comparison_object.equal?(self) ||
75
+ (comparison_object.instance_of?(self.class) &&
76
+ comparison_object.key == key &&
77
+ !comparison_object.new_record?)
78
+ end
79
+
80
+ def eql?(comparison_object)
81
+ self == (comparison_object)
82
+ end
83
+
84
+ # Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
85
+ # "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
86
+ # (Alias for the protected read_attribute method).
87
+ def [](attr_name)
88
+ read_attribute(attr_name)
89
+ end
90
+
91
+ # Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
92
+ # (Alias for the protected write_attribute method).
93
+ def []=(attr_name, value)
94
+ write_attribute(attr_name, value)
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,31 @@
1
+ module CassandraObject
2
+ module Batches
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def find_each
7
+ connection.each(column_family) do |k, v|
8
+ yield instantiate(k, v)
9
+ end
10
+ end
11
+
12
+ def find_in_batches(options = {})
13
+ batch_size = options.delete(:batch_size) || 1000
14
+
15
+ batch = []
16
+
17
+ find_each do |record|
18
+ batch << record
19
+ if batch.size == batch_size
20
+ yield(batch)
21
+ batch = []
22
+ end
23
+ end
24
+
25
+ if batch.size > 0
26
+ yield batch
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ module CassandraObject
2
+ module Callbacks
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ extend ActiveModel::Callbacks
7
+ define_model_callbacks :save, :create, :destroy, :update
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
26
+ end
27
+ end
@@ -0,0 +1,8 @@
1
+ module CassandraObject
2
+ class Collection < Array
3
+ attr_accessor :last_column_name
4
+ def inspect
5
+ "<CassandraObject::Collection##{object_id} contents: #{super} last_column_name: #{last_column_name.inspect}>"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,29 @@
1
+ module CassandraObject
2
+ module Connection
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class_attribute :connection_spec
7
+ end
8
+
9
+ module ClassMethods
10
+ DEFAULT_OPTIONS = {
11
+ servers: "127.0.0.1:9160",
12
+ thrift: {}
13
+ }
14
+ def establish_connection(spec)
15
+ spec.reverse_merge!(DEFAULT_OPTIONS)
16
+ @connection = Cassandra.new(spec[:keyspace], spec[:servers], spec[:thrift].symbolize_keys!)
17
+ end
18
+
19
+ def connection=(val)
20
+ @connection = val
21
+ end
22
+
23
+ def connection
24
+ establish_connection(connection_spec) if @connection.nil?
25
+ @connection
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ module CassandraObject
2
+ module Consistency
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ cattr_accessor :consistency_levels
7
+ self.consistency_levels = [:one, :quorum, :all]
8
+
9
+ class_attribute :write_consistency
10
+ class_attribute :read_consistency
11
+ self.write_consistency = :quorum
12
+ self.read_consistency = :quorum
13
+ end
14
+
15
+ module ClassMethods
16
+ THRIFT_LEVELS = {
17
+ :one => Cassandra::Consistency::ONE,
18
+ :quorum => Cassandra::Consistency::QUORUM,
19
+ :all => Cassandra::Consistency::ALL
20
+ }
21
+
22
+ def thrift_read_consistency
23
+ THRIFT_LEVELS[read_consistency] || (raise "Invalid consistency level #{read_consistency}")
24
+ end
25
+
26
+ def thrift_write_consistency
27
+ THRIFT_LEVELS[write_consistency] || (raise "Invalid consistency level #{write_consistency}")
28
+ end
29
+ end
30
+ end
31
+ end