datastax_rails 1.0.5

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 (148) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +62 -0
  3. data/Rakefile +34 -0
  4. data/config/schema.xml +266 -0
  5. data/config/schema.xml.erb +70 -0
  6. data/config/solrconfig.xml +1564 -0
  7. data/config/stopwords.txt +58 -0
  8. data/lib/datastax_rails/associations/association.rb +224 -0
  9. data/lib/datastax_rails/associations/association_scope.rb +25 -0
  10. data/lib/datastax_rails/associations/belongs_to_association.rb +64 -0
  11. data/lib/datastax_rails/associations/builder/association.rb +56 -0
  12. data/lib/datastax_rails/associations/builder/belongs_to.rb +30 -0
  13. data/lib/datastax_rails/associations/builder/collection_association.rb +48 -0
  14. data/lib/datastax_rails/associations/builder/has_and_belongs_to_many.rb +36 -0
  15. data/lib/datastax_rails/associations/builder/has_many.rb +54 -0
  16. data/lib/datastax_rails/associations/builder/has_one.rb +52 -0
  17. data/lib/datastax_rails/associations/builder/singular_association.rb +56 -0
  18. data/lib/datastax_rails/associations/collection_association.rb +274 -0
  19. data/lib/datastax_rails/associations/collection_proxy.rb +118 -0
  20. data/lib/datastax_rails/associations/has_and_belongs_to_many_association.rb +44 -0
  21. data/lib/datastax_rails/associations/has_many_association.rb +58 -0
  22. data/lib/datastax_rails/associations/has_one_association.rb +68 -0
  23. data/lib/datastax_rails/associations/singular_association.rb +58 -0
  24. data/lib/datastax_rails/associations.rb +86 -0
  25. data/lib/datastax_rails/attribute_methods/definition.rb +20 -0
  26. data/lib/datastax_rails/attribute_methods/dirty.rb +43 -0
  27. data/lib/datastax_rails/attribute_methods/typecasting.rb +50 -0
  28. data/lib/datastax_rails/attribute_methods.rb +104 -0
  29. data/lib/datastax_rails/base.rb +587 -0
  30. data/lib/datastax_rails/batches.rb +35 -0
  31. data/lib/datastax_rails/callbacks.rb +37 -0
  32. data/lib/datastax_rails/collection.rb +9 -0
  33. data/lib/datastax_rails/connection.rb +21 -0
  34. data/lib/datastax_rails/consistency.rb +33 -0
  35. data/lib/datastax_rails/cql/base.rb +15 -0
  36. data/lib/datastax_rails/cql/column_family.rb +38 -0
  37. data/lib/datastax_rails/cql/consistency.rb +13 -0
  38. data/lib/datastax_rails/cql/create_column_family.rb +63 -0
  39. data/lib/datastax_rails/cql/create_keyspace.rb +30 -0
  40. data/lib/datastax_rails/cql/delete.rb +41 -0
  41. data/lib/datastax_rails/cql/drop_column_family.rb +13 -0
  42. data/lib/datastax_rails/cql/drop_keyspace.rb +13 -0
  43. data/lib/datastax_rails/cql/insert.rb +53 -0
  44. data/lib/datastax_rails/cql/select.rb +51 -0
  45. data/lib/datastax_rails/cql/truncate.rb +13 -0
  46. data/lib/datastax_rails/cql/update.rb +68 -0
  47. data/lib/datastax_rails/cql/use_keyspace.rb +13 -0
  48. data/lib/datastax_rails/cql.rb +25 -0
  49. data/lib/datastax_rails/cursor.rb +90 -0
  50. data/lib/datastax_rails/errors.rb +16 -0
  51. data/lib/datastax_rails/identity/abstract_key_factory.rb +26 -0
  52. data/lib/datastax_rails/identity/custom_key_factory.rb +36 -0
  53. data/lib/datastax_rails/identity/hashed_natural_key_factory.rb +10 -0
  54. data/lib/datastax_rails/identity/natural_key_factory.rb +37 -0
  55. data/lib/datastax_rails/identity/uuid_key_factory.rb +23 -0
  56. data/lib/datastax_rails/identity.rb +53 -0
  57. data/lib/datastax_rails/log_subscriber.rb +37 -0
  58. data/lib/datastax_rails/migrations/migration.rb +15 -0
  59. data/lib/datastax_rails/migrations.rb +36 -0
  60. data/lib/datastax_rails/mocking.rb +15 -0
  61. data/lib/datastax_rails/persistence.rb +133 -0
  62. data/lib/datastax_rails/railtie.rb +20 -0
  63. data/lib/datastax_rails/reflection.rb +472 -0
  64. data/lib/datastax_rails/relation/finder_methods.rb +184 -0
  65. data/lib/datastax_rails/relation/modification_methods.rb +80 -0
  66. data/lib/datastax_rails/relation/search_methods.rb +349 -0
  67. data/lib/datastax_rails/relation/spawn_methods.rb +107 -0
  68. data/lib/datastax_rails/relation.rb +393 -0
  69. data/lib/datastax_rails/schema/migration.rb +106 -0
  70. data/lib/datastax_rails/schema/migration_proxy.rb +25 -0
  71. data/lib/datastax_rails/schema/migrator.rb +212 -0
  72. data/lib/datastax_rails/schema.rb +37 -0
  73. data/lib/datastax_rails/scoping.rb +394 -0
  74. data/lib/datastax_rails/serialization.rb +6 -0
  75. data/lib/datastax_rails/tasks/column_family.rb +162 -0
  76. data/lib/datastax_rails/tasks/ds.rake +63 -0
  77. data/lib/datastax_rails/tasks/keyspace.rb +57 -0
  78. data/lib/datastax_rails/timestamps.rb +19 -0
  79. data/lib/datastax_rails/type.rb +16 -0
  80. data/lib/datastax_rails/types/array_type.rb +77 -0
  81. data/lib/datastax_rails/types/base_type.rb +26 -0
  82. data/lib/datastax_rails/types/binary_type.rb +15 -0
  83. data/lib/datastax_rails/types/boolean_type.rb +22 -0
  84. data/lib/datastax_rails/types/date_type.rb +17 -0
  85. data/lib/datastax_rails/types/float_type.rb +18 -0
  86. data/lib/datastax_rails/types/integer_type.rb +18 -0
  87. data/lib/datastax_rails/types/string_type.rb +16 -0
  88. data/lib/datastax_rails/types/text_type.rb +16 -0
  89. data/lib/datastax_rails/types/time_type.rb +17 -0
  90. data/lib/datastax_rails/types.rb +9 -0
  91. data/lib/datastax_rails/validations/uniqueness.rb +119 -0
  92. data/lib/datastax_rails/validations.rb +48 -0
  93. data/lib/datastax_rails/version.rb +3 -0
  94. data/lib/datastax_rails.rb +87 -0
  95. data/lib/solr_no_escape.rb +28 -0
  96. data/spec/datastax_rails/associations/belongs_to_association_spec.rb +7 -0
  97. data/spec/datastax_rails/associations/has_many_association_spec.rb +37 -0
  98. data/spec/datastax_rails/associations_spec.rb +22 -0
  99. data/spec/datastax_rails/attribute_methods_spec.rb +23 -0
  100. data/spec/datastax_rails/base_spec.rb +15 -0
  101. data/spec/datastax_rails/cql/select_spec.rb +12 -0
  102. data/spec/datastax_rails/cql/update_spec.rb +0 -0
  103. data/spec/datastax_rails/relation/finder_methods_spec.rb +54 -0
  104. data/spec/datastax_rails/relation/modification_methods_spec.rb +41 -0
  105. data/spec/datastax_rails/relation/search_methods_spec.rb +117 -0
  106. data/spec/datastax_rails/relation/spawn_methods_spec.rb +28 -0
  107. data/spec/datastax_rails/relation_spec.rb +130 -0
  108. data/spec/datastax_rails/validations/uniqueness_spec.rb +41 -0
  109. data/spec/datastax_rails_spec.rb +5 -0
  110. data/spec/dummy/Rakefile +8 -0
  111. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  112. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  113. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  114. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  115. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  116. data/spec/dummy/config/application.rb +47 -0
  117. data/spec/dummy/config/boot.rb +10 -0
  118. data/spec/dummy/config/database.yml +25 -0
  119. data/spec/dummy/config/datastax.yml +18 -0
  120. data/spec/dummy/config/environment.rb +5 -0
  121. data/spec/dummy/config/environments/development.rb +30 -0
  122. data/spec/dummy/config/environments/production.rb +60 -0
  123. data/spec/dummy/config/environments/test.rb +39 -0
  124. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  125. data/spec/dummy/config/initializers/inflections.rb +10 -0
  126. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  127. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  128. data/spec/dummy/config/initializers/session_store.rb +8 -0
  129. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  130. data/spec/dummy/config/locales/en.yml +5 -0
  131. data/spec/dummy/config/routes.rb +58 -0
  132. data/spec/dummy/config/sunspot.yml +17 -0
  133. data/spec/dummy/config.ru +4 -0
  134. data/spec/dummy/ks/migrate/20111117224534_models.rb +20 -0
  135. data/spec/dummy/ks/schema.json +180 -0
  136. data/spec/dummy/log/development.log +298 -0
  137. data/spec/dummy/log/production.log +0 -0
  138. data/spec/dummy/log/test.log +20307 -0
  139. data/spec/dummy/public/404.html +26 -0
  140. data/spec/dummy/public/422.html +26 -0
  141. data/spec/dummy/public/500.html +26 -0
  142. data/spec/dummy/public/favicon.ico +0 -0
  143. data/spec/dummy/script/rails +6 -0
  144. data/spec/spec.opts +5 -0
  145. data/spec/spec_helper.rb +29 -0
  146. data/spec/support/datastax_test_hook.rb +14 -0
  147. data/spec/support/models.rb +72 -0
  148. metadata +353 -0
@@ -0,0 +1,119 @@
1
+ require 'active_support/core_ext/array/wrap'
2
+
3
+ module DatastaxRails
4
+ module Validations
5
+ class UniquenessValidator < ActiveModel::EachValidator
6
+ def initialize(options)
7
+ super
8
+ end
9
+
10
+ def setup(klass)
11
+ @klass = klass
12
+ end
13
+
14
+ def validate_each(record, attribute, value)
15
+ return true if options[:allow_blank] && value.blank?
16
+ # XXX: The following will break if/when abstract base classes
17
+ # are implemented in datastax_rails (such as STI)
18
+ finder_class = record.class
19
+
20
+ scope = finder_class.unscoped.where(attribute => value)
21
+ scope = scope.where_not(:id => record.id) if record.persisted?
22
+
23
+ Array.wrap(options[:scope]).each do |scope_item|
24
+ scope_value = record.send(scope_item)
25
+ scope_value = nil if scope_value.blank?
26
+ scope = scope.where(scope_item => scope_value)
27
+ end
28
+
29
+ if scope.exists?
30
+ message = options[:message] || 'has already been taken'
31
+ record.errors.add(attribute, message, options.except(:case_sensitive, :scope).merge(:value => value))
32
+ end
33
+ end
34
+ end
35
+
36
+ module ClassMethods
37
+ # Validates whether the value of the specified attributes are unique across the system.
38
+ # Useful for making sure that only one user can be named "davidhh".
39
+ #
40
+ # class Person < DatastaxRails::Base
41
+ # validates_uniqueness_of :user_name
42
+ # end
43
+ #
44
+ # It can also validate whether the value of the specified attributes are unique based on a scope parameter:
45
+ #
46
+ # class Person < DatastaxRails::Base
47
+ # validates_uniqueness_of :user_name, :scope => :account_id
48
+ # end
49
+ #
50
+ # Or even multiple scope parameters. For example, making sure that a teacher can only be on the schedule once
51
+ # per semester for a particular class.
52
+ #
53
+ # class TeacherSchedule < DatastaxRails::Base
54
+ # validates_uniqueness_of :teacher_id, :scope => [:semester_id, :class_id]
55
+ # end
56
+ #
57
+ # When the record is created, a check is performed to make sure that no record exists in the database
58
+ # with the given value for the specified attribute (that maps to a column). When the record is updated,
59
+ # the same check is made but disregarding the record itself.
60
+ #
61
+ # Configuration options:
62
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "has already been taken").
63
+ # * <tt>:scope</tt> - One or more columns by which to limit the scope of the uniqueness constraint.
64
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
65
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
66
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
67
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
68
+ # The method, proc or string should return or evaluate to a true or false value.
69
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
70
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or
71
+ # <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method, proc or string should
72
+ # return or evaluate to a true or false value.
73
+ #
74
+ # === Concurrency and integrity
75
+ #
76
+ # Using this validation method in conjunction with DatastaxRails::Base#save
77
+ # does not guarantee the absence of duplicate record insertions, because
78
+ # uniqueness checks on the application level are inherently prone to race
79
+ # conditions. For example, suppose that two users try to post a Comment at
80
+ # the same time, and a Comment's title must be unique. At the database-level,
81
+ # the actions performed by these users could be interleaved in the following manner:
82
+ #
83
+ # User 1 | User 2
84
+ # ------------------------------------+--------------------------------------
85
+ # # User 1 checks whether there's |
86
+ # # already a comment with the title |
87
+ # # 'My Post'. This is not the case. |
88
+ # SELECT * FROM comments |
89
+ # WHERE title = 'My Post' |
90
+ # |
91
+ # | # User 2 does the same thing and also
92
+ # | # infers that his title is unique.
93
+ # | SELECT * FROM comments
94
+ # | WHERE title = 'My Post'
95
+ # |
96
+ # # User 1 inserts his comment. |
97
+ # INSERT INTO comments |
98
+ # (title, content) VALUES |
99
+ # ('My Post', 'hi!') |
100
+ # |
101
+ # | # User 2 does the same thing.
102
+ # | INSERT INTO comments
103
+ # | (title, content) VALUES
104
+ # | ('My Post', 'hello!')
105
+ # |
106
+ # | # ^^^^^^
107
+ # | # Boom! We now have a duplicate
108
+ # | # title!
109
+ #
110
+ # It is left as an exercise of the developer to figure out how to solve
111
+ # this problem at the application level because there is no way to do
112
+ # so generically since Cassandra doesn't support UNIQUE indexes.
113
+ #
114
+ def validates_uniqueness_of(*attr_names)
115
+ validates_with UniquenessValidator, _merge_attributes(attr_names)
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,48 @@
1
+ module DatastaxRails
2
+ class RecordInvalid < StandardError
3
+ attr_reader :record
4
+ def initialize(record)
5
+ @record = record
6
+ super("Invalid record: #{@record.errors.full_messages.to_sentence}")
7
+ end
8
+ end
9
+
10
+ module Validations
11
+ extend ActiveSupport::Concern
12
+ include ActiveModel::Validations
13
+
14
+ included do
15
+ define_model_callbacks :validation
16
+ define_callbacks :validate, :scope => :name
17
+ end
18
+
19
+ module ClassMethods
20
+ def create!(attributes = {})
21
+ new(attributes).tap do |object|
22
+ object.save!
23
+ end
24
+ end
25
+ end
26
+
27
+ def valid?
28
+ run_callbacks :validation do
29
+ super
30
+ end
31
+ end
32
+
33
+ def save(options={})
34
+ perform_validations(options) ? super : false
35
+ end
36
+
37
+ def save!
38
+ save || raise(RecordInvalid.new(self))
39
+ end
40
+
41
+ protected
42
+ def perform_validations(options={})
43
+ (options[:validate] != false) ? valid? : true
44
+ end
45
+ end
46
+ end
47
+
48
+ require 'datastax_rails/validations/uniqueness'
@@ -0,0 +1,3 @@
1
+ module DatastaxRails
2
+ VERSION = "1.0.5"
3
+ end
@@ -0,0 +1,87 @@
1
+ require 'active_support/all'
2
+ require 'cassandra-cql/1.0'
3
+
4
+ module DatastaxRails
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :Associations
8
+ autoload :AttributeMethods
9
+ autoload :Base
10
+ autoload :Batches
11
+ autoload :Callbacks
12
+ autoload :Collection
13
+ autoload :Connection
14
+ autoload :Consistency
15
+ autoload :Cql
16
+ autoload :Cursor
17
+ autoload :Identity
18
+ autoload :Migrations
19
+ #autoload :Mocking
20
+ autoload :Persistence
21
+ autoload :Reflection
22
+ autoload :Relation
23
+
24
+ autoload_under 'relation' do
25
+ autoload :FinderMethods
26
+ autoload :ModificationMethods
27
+ autoload :SearchMethods
28
+ autoload :SpawnMethods
29
+ end
30
+
31
+ autoload :Schema
32
+ autoload :Scoping
33
+ autoload :Serialization
34
+ autoload :Timestamps
35
+ autoload :Type
36
+ autoload :Validations
37
+
38
+ module AttributeMethods
39
+ extend ActiveSupport::Autoload
40
+
41
+ eager_autoload do
42
+ autoload :Definition
43
+ autoload :Dirty
44
+ autoload :Typecasting
45
+ end
46
+ end
47
+
48
+ module Tasks
49
+ extend ActiveSupport::Autoload
50
+ autoload :Keyspace
51
+ autoload :ColumnFamily
52
+ end
53
+
54
+ module Types
55
+ extend ActiveSupport::Autoload
56
+
57
+ autoload :BaseType
58
+ autoload :BinaryType
59
+ autoload :ArrayType
60
+ autoload :BooleanType
61
+ autoload :DateType
62
+ autoload :FloatType
63
+ autoload :IntegerType
64
+ autoload :JsonType
65
+ autoload :StringType
66
+ autoload :TextType
67
+ autoload :TimeType
68
+ autoload :TimeWithZoneType
69
+ end
70
+ end
71
+
72
+ # Fixup the thrift library
73
+ require "thrift"
74
+ module Thrift
75
+ class BinaryProtocol
76
+ def write_string(str)
77
+ write_i32(str.bytesize)
78
+ trans.write(str)
79
+ end
80
+ end
81
+ end
82
+
83
+ require 'datastax_rails/railtie' if defined?(Rails)
84
+ require 'datastax_rails/errors'
85
+ # require 'solr_no_escape'
86
+
87
+ ActiveSupport.run_load_hooks(:datastax_rails, DatastaxRails::Base)
@@ -0,0 +1,28 @@
1
+ require 'sunspot'
2
+ module SolrNoEscape
3
+ def escape(str)
4
+ # We are purposely not escaping since we want people to be able to do
5
+ # advanced queries that otherwise wouldn't work. Spaces are a special
6
+ # case due to later URL escaping.
7
+ str.gsub(/ /,"\\\\ ")
8
+ end
9
+ end
10
+
11
+ module Sunspot
12
+ module Query
13
+ class FunctionQuery
14
+ include SolrNoEscape
15
+ end
16
+ end
17
+ end
18
+
19
+ module Sunspot
20
+ module Query
21
+ module Restriction
22
+ class Base
23
+ include SolrNoEscape
24
+ end
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe DatastaxRails::Base do
4
+ describe "BelongsTo Association" do
5
+
6
+ end
7
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe DatastaxRails::Base do
4
+ describe "HasMany Associations" do
5
+ it "should destroy all objects with :dependent => :destroy" do
6
+ p = Person.create(:name => "jason")
7
+ Car.create(:name => "Jeep", :person_id => p.id)
8
+ Car.commit_solr
9
+ p.destroy
10
+ Car.commit_solr
11
+ Person.commit_solr
12
+ Car.count.should == 0
13
+ end
14
+
15
+ it "should retrieve child records" do
16
+ p = Person.create(:name => 'jason')
17
+ c = Car.create(:name => 'Jeep', :person_id => p.id)
18
+ Car.commit_solr
19
+ p.cars.should include(c)
20
+ end
21
+
22
+ it "should retrieve only child records" do
23
+ p = Person.create(:name => 'jason')
24
+ c = Car.create(:name => 'Jeep', :person_id => '12345')
25
+ Car.commit_solr
26
+ p.cars.should_not include(c)
27
+ end
28
+
29
+ it "should create records with the proper foreign key" do
30
+ p = Person.create(:name => 'jason')
31
+ p.cars.create(:name => 'Jeep')
32
+ Car.commit_solr
33
+ Person.commit_solr
34
+ Car.first.person.should == p
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe DatastaxRails::Base do
4
+ describe "Relations" do
5
+ describe "belongs_to" do
6
+ it "should set the id when setting the object" do
7
+ person = Person.create(:name => "Jason")
8
+ job = Job.create(:title => "Developer")
9
+ job.person = person
10
+ job.person_id.should == person.id
11
+ end
12
+
13
+ it "should look up the owning model by id" do
14
+ person = Person.create(:name => "John")
15
+ job = Job.create(:title => "Developer", :person_id => person.id)
16
+ Person.commit_solr
17
+ Job.commit_solr
18
+ Job.first.person.should == person
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ class AttributeMethodsTester < DatastaxRails::Base
4
+ string :test_string
5
+ string :non_search_string, :searchable => false
6
+ end
7
+
8
+ describe DatastaxRails::Base do
9
+ def tester
10
+ @tester ||= AttributeMethodsTester.new
11
+ end
12
+
13
+ describe "attribute methods" do
14
+ it "should create attribute setter methods" do
15
+ tester.should respond_to(:test_string=)
16
+ end
17
+
18
+ it "Should create attribute getter methods" do
19
+ tester.should respond_to(:test_string)
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe DatastaxRails::Base do
4
+ it "should run before_save" do
5
+ p = Person.new(:name => "Jason")
6
+ p.save
7
+ p.nickname.should == "Jason"
8
+ end
9
+
10
+ it "should run after_save" do
11
+ p = Person.new(:name => "Jason")
12
+ p.save!
13
+ p.instance_variable_get(:@after_save_ran).should == "yup"
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe DatastaxRails::Cql::Select do
4
+ before(:each) do
5
+ @model_class = mock("Model Class", :column_family => 'users')
6
+ end
7
+ it "should generate valid CQL" do
8
+ cql = DatastaxRails::Cql::Select.new(@model_class, ["*"])
9
+ cql.using(DatastaxRails::Cql::Consistency::QUORUM).conditions(:key => '12345').limit(1)
10
+ cql.to_cql.should == "SELECT * FROM users USING CONSISTENCY QUORUM WHERE key = '12345' LIMIT 1"
11
+ end
12
+ end
File without changes
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe DatastaxRails::Relation do
4
+ before(:each) do
5
+ @relation = DatastaxRails::Relation.new(Hobby, "hobbies")
6
+ end
7
+
8
+ describe "#first" do
9
+ it "should return the first result if records are already loaded" do
10
+ a_record = mock_model(Hobby)
11
+ @relation.stub(:loaded? => true)
12
+ @relation.instance_variable_set(:@results, [a_record, mock_model(Hobby)])
13
+ @relation.first.should == a_record
14
+ end
15
+
16
+ it "should look up the first result if records are not already loaded" do
17
+ a_record = mock_model(Hobby)
18
+ @relation.stub(:loaded? => false)
19
+ mock_relation = mock(DatastaxRails::Relation, :to_a => [a_record])
20
+ @relation.should_receive(:limit).with(1).and_return(mock_relation)
21
+ @relation.first.should == a_record
22
+ end
23
+ end
24
+
25
+ describe "#first!" do
26
+ it "should raise RecordNotFound if no record is returned" do
27
+ lambda { @relation.first! }.should raise_exception(DatastaxRails::RecordNotFound)
28
+ end
29
+ end
30
+
31
+ describe "#last" do
32
+ it "should return the last result if records are already loaded" do
33
+ a_record = mock_model(Hobby)
34
+ @relation.stub(:loaded? => true)
35
+ @relation.instance_variable_set(:@results, [mock_model(Hobby), a_record])
36
+ @relation.last.should == a_record
37
+ end
38
+
39
+ it "should look up the last result if records are not already loaded" do
40
+ a_record = mock_model(Hobby)
41
+ @relation.stub(:loaded? => false)
42
+ mock_relation = mock(DatastaxRails::Relation, :to_a => [a_record])
43
+ @relation.should_receive(:reverse_order).and_return(mock_relation)
44
+ mock_relation.should_receive(:limit).with(1).and_return(mock_relation)
45
+ @relation.last.should == a_record
46
+ end
47
+ end
48
+
49
+ describe "#last!" do
50
+ it "should raise RecordNotFound if no record is returned" do
51
+ lambda { @relation.last! }.should raise_exception(DatastaxRails::RecordNotFound)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe DatastaxRails::Relation do
4
+ before(:each) do
5
+ @relation = DatastaxRails::Relation.new(Hobby, "hobbies")
6
+ end
7
+
8
+ describe "Modification Methods" do
9
+ describe "#destroy_all" do
10
+ it "should destroy all matching records" do
11
+ Hobby.create(:name => "biking", :complexity => 1.0)
12
+ Hobby.create(:name => "skydiving", :complexity => 4.0)
13
+ @relation.commit_solr
14
+ @relation.where(:complexity).greater_than(2.0).destroy_all
15
+ @relation.commit_solr
16
+ @relation = DatastaxRails::Relation.new(Hobby, "hobbies")
17
+ @relation.count.should == 1
18
+ end
19
+ end
20
+
21
+ describe "#destroy" do
22
+ before(:each) do
23
+ @h1 = Hobby.create(:name => "biking", :complexity => 1.0)
24
+ @h2 = Hobby.create(:name => "skydiving", :complexity => 4.0)
25
+ @relation.commit_solr
26
+ end
27
+
28
+ it "should destroy 1 record by id" do
29
+ @relation.destroy(@h1.id)
30
+ @relation.commit_solr
31
+ @relation.count.should == 1
32
+ end
33
+
34
+ it "should destroy multiple records by id" do
35
+ @relation.destroy([@h1.id, @h2.id])
36
+ @relation.commit_solr
37
+ @relation.count.should == 0
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ describe DatastaxRails::Relation do
4
+ before(:each) do
5
+ @relation = DatastaxRails::Relation.new(Hobby, "hobbies")
6
+ end
7
+
8
+ describe "#limit" do
9
+ it "should limit the page size" do
10
+ "a".upto("l") do |letter|
11
+ Hobby.create(:name => letter)
12
+ end
13
+ Hobby.commit_solr
14
+ @relation.limit(7).all.size.should == 7
15
+ end
16
+ end
17
+
18
+ describe "#page" do
19
+ it "should get a particular page" do
20
+ "a".upto("l") do |letter|
21
+ Hobby.create(:name => letter)
22
+ end
23
+ Hobby.commit_solr
24
+ @relation.per_page(3).page(2).order(:name).all.first.name.should == "d"
25
+ end
26
+ end
27
+
28
+ describe "#group" do
29
+
30
+ end
31
+
32
+ describe "#order" do
33
+ it "should return items in ascending order" do
34
+ %w[fishing hiking boating jogging swimming chess].each do |word|
35
+ Hobby.create(:name => word)
36
+ end
37
+ @relation.commit_solr
38
+ @relation.order(:name).collect {|h| h.name}.should == %w[boating chess fishing hiking jogging swimming]
39
+ end
40
+
41
+ it "should return items in descending order" do
42
+ %w[fishing hiking boating jogging swimming chess].each do |word|
43
+ Hobby.create(:name => word)
44
+ end
45
+ @relation.commit_solr
46
+ @relation.order(:name => :desc).collect {|h| h.name}.should == %w[swimming jogging hiking fishing chess boating]
47
+ end
48
+ end
49
+
50
+ describe "#where" do
51
+ it "should return documents where a field is nil (does not exist)" do
52
+ Hobby.create(:name => 'Swimming')
53
+ Hobby.create(:name => nil)
54
+ @relation.commit_solr
55
+ @relation.where(:name => nil).should_not be_empty
56
+ end
57
+
58
+ it "should return documents where a value is greater than the given value" do
59
+ Hobby.create(:name => 'Swimming', :complexity => 1.1)
60
+ @relation.commit_solr
61
+ @relation.where(:complexity).greater_than(1.0).should_not be_empty
62
+ end
63
+
64
+ it "should return documents where a value is less than the given value" do
65
+ Hobby.create(:name => 'Swimming', :complexity => 1.1)
66
+ @relation.commit_solr
67
+ @relation.where(:complexity).less_than(2.0).should_not be_empty
68
+ end
69
+
70
+ it "should allow arrays to be passed as OR queries" do
71
+ %w[fishing hiking boating jogging swimming chess].each do |word|
72
+ Hobby.create(:name => word)
73
+ end
74
+ @relation.commit_solr
75
+ @relation.where(:name => ['boating', 'jogging', 'chess', 'skydiving']).size.should == 3
76
+ end
77
+
78
+ it "should handle negative numbers without breaking" do
79
+ Hobby.create(:name => 'jogging', :complexity => -1.2)
80
+ @relation.commit_solr
81
+ @relation.where(:complexity).less_than(-1).should_not be_empty
82
+ end
83
+
84
+ it "should not tokenize where queries on spaces" do
85
+ Hobby.create(:name => 'horseback riding')
86
+ @relation.commit_solr
87
+ @relation.where(:name => 'horseback').should be_empty
88
+ @relation.where(:name => 'horseback riding').should_not be_empty
89
+ @relation.where(:name => 'horseback ri*').should_not be_empty
90
+ end
91
+
92
+ it "should not tokenize where queries on spaces inside arrays" do
93
+ Hobby.create(:name => 'horseback riding')
94
+ @relation.commit_solr
95
+ @relation.where(:name => ['horseback riding', 'some other hobby']).should_not be_empty
96
+ end
97
+ end
98
+
99
+ describe "#where_not" do
100
+ it "should return documents where a field has any value" do
101
+ Hobby.create(:name => 'Swimming')
102
+ @relation.commit_solr
103
+ @relation.where_not(:name => nil).should_not be_empty
104
+ end
105
+
106
+ it "should return documents where none of the options are present" do
107
+ Hobby.create(:name => 'Swimming')
108
+ Hobby.create(:name => 'Biking')
109
+ @relation.commit_solr
110
+ @relation.where_not(:name => ['Swimming','Biking']).should be_empty
111
+ end
112
+ end
113
+
114
+ describe "#fulltext" do
115
+
116
+ end
117
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe DatastaxRails::Relation do
4
+ before(:each) do
5
+ @relation = DatastaxRails::Relation.new(Hobby, "hobbies")
6
+ end
7
+
8
+ describe "#merge" do
9
+ it "should merge two relations" do
10
+ r1 = @relation.where("name" => "biking")
11
+ r2 = @relation.order("name" => :desc)
12
+ r1.merge(r2).should == @relation.where("name" => "biking").order("name" => :desc)
13
+ end
14
+
15
+ it "should merge where conditions into a single hash" do
16
+ r1 = @relation.where("name" => "biking")
17
+ r2 = @relation.where("complexity" => 1.0)
18
+ r1.merge(r2).where_values.should == [{"name" => "biking", "complexity" => 1.0}]
19
+ end
20
+
21
+ it "should overwrite conditions on the same attribute" do
22
+ r1 = @relation.where("name" => "biking")
23
+ r2 = @relation.where("name" => "swimming")
24
+ r1.merge(r2).where_values.should == [{"name" => "swimming"}]
25
+ r2.merge(r1).where_values.should == [{"name" => "biking"}]
26
+ end
27
+ end
28
+ end