cassandra_object_rails 0.0.1

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.
Files changed (97) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +3 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG +5 -0
  5. data/Gemfile +8 -0
  6. data/LICENSE +13 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.rdoc +97 -0
  9. data/Rakefile +12 -0
  10. data/cassandra_object_rails.gemspec +26 -0
  11. data/lib/cassandra_object/attribute_methods.rb +87 -0
  12. data/lib/cassandra_object/attribute_methods/definition.rb +19 -0
  13. data/lib/cassandra_object/attribute_methods/dirty.rb +44 -0
  14. data/lib/cassandra_object/attribute_methods/primary_key.rb +25 -0
  15. data/lib/cassandra_object/attribute_methods/typecasting.rb +59 -0
  16. data/lib/cassandra_object/base.rb +69 -0
  17. data/lib/cassandra_object/belongs_to.rb +63 -0
  18. data/lib/cassandra_object/belongs_to/association.rb +48 -0
  19. data/lib/cassandra_object/belongs_to/builder.rb +40 -0
  20. data/lib/cassandra_object/belongs_to/reflection.rb +30 -0
  21. data/lib/cassandra_object/callbacks.rb +29 -0
  22. data/lib/cassandra_object/config.rb +15 -0
  23. data/lib/cassandra_object/connection.rb +36 -0
  24. data/lib/cassandra_object/consistency.rb +18 -0
  25. data/lib/cassandra_object/core.rb +59 -0
  26. data/lib/cassandra_object/errors.rb +6 -0
  27. data/lib/cassandra_object/identity.rb +24 -0
  28. data/lib/cassandra_object/inspect.rb +25 -0
  29. data/lib/cassandra_object/log_subscriber.rb +29 -0
  30. data/lib/cassandra_object/persistence.rb +169 -0
  31. data/lib/cassandra_object/rails_initializer.rb +19 -0
  32. data/lib/cassandra_object/railtie.rb +11 -0
  33. data/lib/cassandra_object/savepoints.rb +79 -0
  34. data/lib/cassandra_object/schema.rb +78 -0
  35. data/lib/cassandra_object/schema/tasks.rb +48 -0
  36. data/lib/cassandra_object/scope.rb +48 -0
  37. data/lib/cassandra_object/scope/batches.rb +32 -0
  38. data/lib/cassandra_object/scope/finder_methods.rb +47 -0
  39. data/lib/cassandra_object/scope/query_methods.rb +111 -0
  40. data/lib/cassandra_object/scoping.rb +19 -0
  41. data/lib/cassandra_object/serialization.rb +6 -0
  42. data/lib/cassandra_object/tasks/cassandra.rake +53 -0
  43. data/lib/cassandra_object/timestamps.rb +19 -0
  44. data/lib/cassandra_object/type.rb +16 -0
  45. data/lib/cassandra_object/types.rb +8 -0
  46. data/lib/cassandra_object/types/array_type.rb +76 -0
  47. data/lib/cassandra_object/types/base_type.rb +26 -0
  48. data/lib/cassandra_object/types/boolean_type.rb +20 -0
  49. data/lib/cassandra_object/types/date_type.rb +17 -0
  50. data/lib/cassandra_object/types/float_type.rb +16 -0
  51. data/lib/cassandra_object/types/integer_type.rb +16 -0
  52. data/lib/cassandra_object/types/json_type.rb +52 -0
  53. data/lib/cassandra_object/types/string_type.rb +15 -0
  54. data/lib/cassandra_object/types/time_type.rb +16 -0
  55. data/lib/cassandra_object/validations.rb +44 -0
  56. data/lib/cassandra_object_rails.rb +64 -0
  57. data/test/support/connect.rb +17 -0
  58. data/test/support/issue.rb +5 -0
  59. data/test/support/teardown.rb +24 -0
  60. data/test/test_helper.rb +34 -0
  61. data/test/unit/active_model_test.rb +18 -0
  62. data/test/unit/attribute_methods/definition_test.rb +13 -0
  63. data/test/unit/attribute_methods/dirty_test.rb +71 -0
  64. data/test/unit/attribute_methods/primary_key_test.rb +26 -0
  65. data/test/unit/attribute_methods/typecasting_test.rb +112 -0
  66. data/test/unit/attribute_methods_test.rb +39 -0
  67. data/test/unit/base_test.rb +20 -0
  68. data/test/unit/belongs_to/reflection_test.rb +12 -0
  69. data/test/unit/belongs_to_test.rb +62 -0
  70. data/test/unit/callbacks_test.rb +46 -0
  71. data/test/unit/config_test.rb +23 -0
  72. data/test/unit/connection_test.rb +10 -0
  73. data/test/unit/consistency_test.rb +13 -0
  74. data/test/unit/core_test.rb +55 -0
  75. data/test/unit/identity_test.rb +26 -0
  76. data/test/unit/inspect_test.rb +26 -0
  77. data/test/unit/log_subscriber_test.rb +22 -0
  78. data/test/unit/persistence_test.rb +187 -0
  79. data/test/unit/savepoints_test.rb +35 -0
  80. data/test/unit/schema/tasks_test.rb +29 -0
  81. data/test/unit/schema_test.rb +47 -0
  82. data/test/unit/scope/batches_test.rb +30 -0
  83. data/test/unit/scope/finder_methods_test.rb +51 -0
  84. data/test/unit/scope/query_methods_test.rb +26 -0
  85. data/test/unit/scoping_test.rb +7 -0
  86. data/test/unit/timestamps_test.rb +27 -0
  87. data/test/unit/types/array_type_test.rb +71 -0
  88. data/test/unit/types/base_type_test.rb +24 -0
  89. data/test/unit/types/boolean_type_test.rb +24 -0
  90. data/test/unit/types/date_type_test.rb +11 -0
  91. data/test/unit/types/float_type_test.rb +17 -0
  92. data/test/unit/types/integer_type_test.rb +19 -0
  93. data/test/unit/types/json_type_test.rb +77 -0
  94. data/test/unit/types/string_type_test.rb +32 -0
  95. data/test/unit/types/time_type_test.rb +14 -0
  96. data/test/unit/validations_test.rb +27 -0
  97. metadata +208 -0
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZjY5MDAwZDcwYmFlYmYxYjhjYWZlY2Y2YjNhZWM2MmI0YjQzN2Y2Yw==
5
+ data.tar.gz: !binary |-
6
+ MDRkMDJiYmE2OTg2ODhjZDlmYWYxMzk2ZjM4MmI2YjQ0YzA3ZTk4Yw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ YzA5YjVmZTI3MzUzYmJiNTI2YjAyMjM5OWRlNzc2NGE5M2M4MzRlN2NiMzli
10
+ NGE0MjA1OTAwMDNhOTY1NzZhMzEzMTA1OWJjZWNkMTgzMDI4NDE5YmZhYjY2
11
+ OGE3OTRjY2I3NmMxOWFlY2JhY2E4NmM5Yzk4ZDk3OWM2NGNmZDg=
12
+ data.tar.gz: !binary |-
13
+ NDE0YjU3ZTQ3NjY0MjU2MDkxZWM1M2JiMDI0ZjRjZjc0MDE4MDJiMTJlZDQ5
14
+ NDNlZGQ4NGUxY2NhNDdkNDk2ZWQ0OTExNmJmOWY3ZDU5ODY4M2Y5MjJlODcz
15
+ Njk2MDBjMmNmNzczNWUyYWEwYzI2YjlhOTUzODMyZWNkNGQ5ZTY=
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ *.gem
3
+ *.log
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ services:
3
+ - cassandra
4
+ rvm:
5
+ - 1.9.2
6
+ - 1.9.3
7
+ env: CQLSH=/usr/local/cassandra/bin/cqlsh
@@ -0,0 +1,5 @@
1
+ September 22th 2013 - cassandra_object_rails v0.0.1
2
+
3
+ cassandra_object_rails gem released. This gem is an improvement of
4
+ gotime-cassandra_object that offers a better rails integration and much more
5
+ resources.
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+ gemspec
3
+
4
+ gem 'rake'
5
+ gem 'mocha'
6
+ # group :development, :test do
7
+ # gem 'pry'
8
+ # end
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.
@@ -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.
@@ -0,0 +1,97 @@
1
+ == Cassandra Object Rails
2
+
3
+ Cassandra Object uses ActiveModel to mimic much of the behavior in ActiveRecord.
4
+
5
+ === Installation
6
+
7
+ Add the following to your Gemfile:
8
+
9
+ gem 'cassandra_object_rails'
10
+
11
+ === Defining Models
12
+
13
+ class Widget < CassandraObject::Base
14
+ string :name
15
+ string :description
16
+ integer :price
17
+ array :colors, unique: true
18
+
19
+ validates :name, presence: :true
20
+
21
+ before_create do
22
+ self.description = "#{name} is the best product ever"
23
+ end
24
+ end
25
+
26
+ === Connecting to the Server
27
+
28
+ CassandraObject::Base.config = {
29
+ keyspace: 'my_app_development',
30
+ servers: '127.0.0.1:9160',
31
+ thrift: {
32
+ timeout: 20,
33
+ retries: 2
34
+ }
35
+ }
36
+
37
+ === Connecting your rails application with Cassandra
38
+
39
+ in your config/cassandra.yml
40
+
41
+ development:
42
+ keyspace: 'my_app_development'
43
+ servers: '127.0.0.1:9160'
44
+
45
+ test:
46
+ keyspace: 'my_app_development'
47
+ servers: '127.0.0.1:9160'
48
+
49
+ production:
50
+ keyspace: 'my_app_development'
51
+ servers: '127.0.0.1:9160'
52
+
53
+
54
+ === Creating and updating records
55
+
56
+ Cassandra Object has equivalent methods as ActiveRecord:
57
+
58
+ widget = Widget.new
59
+ widget.valid?
60
+ widget = Widget.create(name: 'Acme', price: 100)
61
+ widget.update_attribute(:price, 1200)
62
+ widget.update_attributes(price: 1200, name: 'Acme Corporation')
63
+ widget.attributes = {price: 300}
64
+ widget.price_was
65
+ widget.save
66
+ widget.save!
67
+
68
+ === Finding records
69
+
70
+ widget = Widget.find(uuid)
71
+ widget = Widget.first
72
+ widgets = Widget.all
73
+ Widget.find_each do |widget|
74
+ ...
75
+ end
76
+
77
+ === Query
78
+
79
+ Some lightweight scoping features are available:
80
+
81
+ Widget.where('color' => 'red')
82
+ Widget.select(['name', 'color'])
83
+ Widget.limit(10)
84
+
85
+ === Keyspace
86
+
87
+ Creating cassandra keyspace defined on cassandra.yml
88
+
89
+ rake cassandra:create
90
+
91
+ Droping cassandra keyspace
92
+
93
+ rake cassandra:drop
94
+
95
+ === Adding column family
96
+
97
+ CassandraObject::Schema.create_column_family 'Widgets'
@@ -0,0 +1,12 @@
1
+ require 'bundler/setup'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ task default: :test
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << 'lib'
9
+ t.libs << 'test'
10
+ t.pattern = 'test/unit/**/*_test.rb'
11
+ t.verbose = true
12
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'cassandra_object_rails'
5
+ s.version = '0.0.1'
6
+ s.description = 'Cassandra ActiveModel'
7
+ s.summary = 'Cassandra ActiveModel'
8
+ s.authors = ["Lucas Allan Amorim"]
9
+ s.email = 'lucas.allan@gmail.com'
10
+ s.homepage = 'http://github.com/lucasallan/cassandra_object'
11
+
12
+ s.required_ruby_version = '>= 1.9.2'
13
+ s.required_rubygems_version = '>= 1.3.5'
14
+
15
+ s.extra_rdoc_files = ["README.rdoc"]
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test}/*`.split("\n")
18
+ s.require_paths = ['lib']
19
+
20
+ s.add_runtime_dependency('activemodel', '>= 3.0')
21
+ s.add_runtime_dependency('cassandra-cql')
22
+ s.add_runtime_dependency('thrift_client', '~> 0.9.2')
23
+ s.add_runtime_dependency('thin')
24
+
25
+ s.add_development_dependency('bundler')
26
+ end
@@ -0,0 +1,87 @@
1
+ module CassandraObject
2
+ module AttributeMethods
3
+ extend ActiveSupport::Concern
4
+ include ActiveModel::AttributeMethods
5
+
6
+ included do
7
+ if ActiveModel::VERSION::STRING < '3.2'
8
+ attribute_method_suffix("", "=")
9
+ else
10
+ attribute_method_suffix("=")
11
+ end
12
+
13
+ # (Alias for the protected read_attribute method).
14
+ def [](attr_name)
15
+ read_attribute(attr_name)
16
+ end
17
+
18
+ # Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
19
+ # (Alias for the protected write_attribute method).
20
+ def []=(attr_name, value)
21
+ write_attribute(attr_name, value)
22
+ end
23
+ end
24
+
25
+ module ClassMethods
26
+ def define_attribute_methods
27
+ return if attribute_methods_generated?
28
+ super(attribute_definitions.keys)
29
+ @attribute_methods_generated = true
30
+ end
31
+
32
+ def attribute_methods_generated?
33
+ @attribute_methods_generated ||= false
34
+ end
35
+ end
36
+
37
+ def write_attribute(name, value)
38
+ @attributes[name.to_s] = self.class.typecast_attribute(self, name, value)
39
+ end
40
+
41
+ def read_attribute(name)
42
+ @attributes[name.to_s]
43
+ end
44
+
45
+ def attribute_exists?(name)
46
+ @attributes.key?(name.to_s)
47
+ end
48
+
49
+ def attributes
50
+ Hash[@attributes.map { |name, _| [name, read_attribute(name)] }]
51
+ end
52
+
53
+ def attributes=(attributes)
54
+ attributes.each do |(name, value)|
55
+ send("#{name}=", value)
56
+ end
57
+ end
58
+
59
+ def method_missing(method_id, *args, &block)
60
+ if !self.class.attribute_methods_generated?
61
+ self.class.define_attribute_methods
62
+ send(method_id, *args, &block)
63
+ else
64
+ super
65
+ end
66
+ end
67
+
68
+ def respond_to?(*args)
69
+ self.class.define_attribute_methods unless self.class.attribute_methods_generated?
70
+ super
71
+ end
72
+
73
+ protected
74
+ def attribute_method?(name)
75
+ !!attribute_definitions[name.to_sym]
76
+ end
77
+
78
+ private
79
+ def attribute(name)
80
+ read_attribute(name)
81
+ end
82
+
83
+ def attribute=(name, value)
84
+ write_attribute(name, value)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,19 @@
1
+ module CassandraObject
2
+ module AttributeMethods
3
+ class Definition
4
+ attr_reader :name, :coder
5
+ def initialize(name, coder, options)
6
+ @name = name.to_s
7
+ @coder = coder.new(options)
8
+ end
9
+
10
+ def instantiate(record, value)
11
+ value = value.nil? ? coder.default : value
12
+ return if value.nil?
13
+
14
+ value = value.kind_of?(String) ? coder.decode(value) : value
15
+ coder.wrap(record, name, value)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,44 @@
1
+ module CassandraObject
2
+ module AttributeMethods
3
+ module Dirty
4
+ extend ActiveSupport::Concern
5
+ include ActiveModel::Dirty
6
+
7
+ # Attempts to +save+ the record and clears changed attributes if successful.
8
+ def save(*) #:nodoc:
9
+ if status = super
10
+ @previously_changed = changes
11
+ @changed_attributes.clear
12
+ end
13
+ status
14
+ end
15
+
16
+ # Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
17
+ def save!(*) #:nodoc:
18
+ super.tap do
19
+ @previously_changed = changes
20
+ @changed_attributes.clear
21
+ end
22
+ end
23
+
24
+ # <tt>reload</tt> the record and clears changed attributes.
25
+ def reload
26
+ super.tap do
27
+ @previously_changed.try :clear
28
+ @changed_attributes.try :clear
29
+ end
30
+ end
31
+
32
+ def write_attribute(name, value)
33
+ name = name.to_s
34
+ old = read_attribute(name)
35
+
36
+ super
37
+
38
+ unless attribute_changed?(name) || old == read_attribute(name)
39
+ changed_attributes[name] = old
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,25 @@
1
+ module CassandraObject
2
+ module AttributeMethods
3
+ module PrimaryKey
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def primary_key
8
+ 'id'
9
+ end
10
+ end
11
+
12
+ def id
13
+ @id ||= self.class._generate_key(self)
14
+ end
15
+
16
+ def id=(id)
17
+ @id = id
18
+ end
19
+
20
+ def attributes
21
+ super.update(self.class.primary_key => id)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,59 @@
1
+ module CassandraObject
2
+ module AttributeMethods
3
+ module Typecasting
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class_attribute :attribute_definitions
8
+ self.attribute_definitions = {}
9
+
10
+ %w(array boolean date float integer json string time).each do |type|
11
+ instance_eval <<-EOV, __FILE__, __LINE__ + 1
12
+ def #{type}(*args)
13
+ options = args.extract_options!
14
+ args.each do |name|
15
+ attribute(name, options.merge(:type => :#{type}))
16
+ end
17
+ end
18
+ EOV
19
+ end
20
+ end
21
+
22
+ module ClassMethods
23
+ def inherited(child)
24
+ super
25
+ child.attribute_definitions = attribute_definitions.dup
26
+ end
27
+
28
+ #
29
+ # attribute :name, type: :string
30
+ # attribute :ammo, type: Ammo, coder: AmmoCodec
31
+ #
32
+ def attribute(name, options)
33
+ type = options[:type]
34
+ coder = options[:coder]
35
+
36
+ if type.is_a?(Symbol)
37
+ coder = CassandraObject::Type.get_coder(type) || (raise "Unknown type #{type}")
38
+ elsif coder.nil?
39
+ raise "Must supply a :coder for #{name}"
40
+ end
41
+
42
+ attribute_definitions[name.to_sym] = AttributeMethods::Definition.new(name, coder, options)
43
+ end
44
+
45
+ def typecast_attribute(record, name, value)
46
+ if attribute_definition = attribute_definitions[name.to_sym]
47
+ attribute_definition.instantiate(record, value)
48
+ else
49
+ raise NoMethodError, "Unknown attribute #{name.inspect}"
50
+ end
51
+ end
52
+
53
+ def coder_for(attribute)
54
+ attribute_definitions[attribute.to_sym].coder
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end