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.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +62 -0
- data/Rakefile +34 -0
- data/config/schema.xml +266 -0
- data/config/schema.xml.erb +70 -0
- data/config/solrconfig.xml +1564 -0
- data/config/stopwords.txt +58 -0
- data/lib/datastax_rails/associations/association.rb +224 -0
- data/lib/datastax_rails/associations/association_scope.rb +25 -0
- data/lib/datastax_rails/associations/belongs_to_association.rb +64 -0
- data/lib/datastax_rails/associations/builder/association.rb +56 -0
- data/lib/datastax_rails/associations/builder/belongs_to.rb +30 -0
- data/lib/datastax_rails/associations/builder/collection_association.rb +48 -0
- data/lib/datastax_rails/associations/builder/has_and_belongs_to_many.rb +36 -0
- data/lib/datastax_rails/associations/builder/has_many.rb +54 -0
- data/lib/datastax_rails/associations/builder/has_one.rb +52 -0
- data/lib/datastax_rails/associations/builder/singular_association.rb +56 -0
- data/lib/datastax_rails/associations/collection_association.rb +274 -0
- data/lib/datastax_rails/associations/collection_proxy.rb +118 -0
- data/lib/datastax_rails/associations/has_and_belongs_to_many_association.rb +44 -0
- data/lib/datastax_rails/associations/has_many_association.rb +58 -0
- data/lib/datastax_rails/associations/has_one_association.rb +68 -0
- data/lib/datastax_rails/associations/singular_association.rb +58 -0
- data/lib/datastax_rails/associations.rb +86 -0
- data/lib/datastax_rails/attribute_methods/definition.rb +20 -0
- data/lib/datastax_rails/attribute_methods/dirty.rb +43 -0
- data/lib/datastax_rails/attribute_methods/typecasting.rb +50 -0
- data/lib/datastax_rails/attribute_methods.rb +104 -0
- data/lib/datastax_rails/base.rb +587 -0
- data/lib/datastax_rails/batches.rb +35 -0
- data/lib/datastax_rails/callbacks.rb +37 -0
- data/lib/datastax_rails/collection.rb +9 -0
- data/lib/datastax_rails/connection.rb +21 -0
- data/lib/datastax_rails/consistency.rb +33 -0
- data/lib/datastax_rails/cql/base.rb +15 -0
- data/lib/datastax_rails/cql/column_family.rb +38 -0
- data/lib/datastax_rails/cql/consistency.rb +13 -0
- data/lib/datastax_rails/cql/create_column_family.rb +63 -0
- data/lib/datastax_rails/cql/create_keyspace.rb +30 -0
- data/lib/datastax_rails/cql/delete.rb +41 -0
- data/lib/datastax_rails/cql/drop_column_family.rb +13 -0
- data/lib/datastax_rails/cql/drop_keyspace.rb +13 -0
- data/lib/datastax_rails/cql/insert.rb +53 -0
- data/lib/datastax_rails/cql/select.rb +51 -0
- data/lib/datastax_rails/cql/truncate.rb +13 -0
- data/lib/datastax_rails/cql/update.rb +68 -0
- data/lib/datastax_rails/cql/use_keyspace.rb +13 -0
- data/lib/datastax_rails/cql.rb +25 -0
- data/lib/datastax_rails/cursor.rb +90 -0
- data/lib/datastax_rails/errors.rb +16 -0
- data/lib/datastax_rails/identity/abstract_key_factory.rb +26 -0
- data/lib/datastax_rails/identity/custom_key_factory.rb +36 -0
- data/lib/datastax_rails/identity/hashed_natural_key_factory.rb +10 -0
- data/lib/datastax_rails/identity/natural_key_factory.rb +37 -0
- data/lib/datastax_rails/identity/uuid_key_factory.rb +23 -0
- data/lib/datastax_rails/identity.rb +53 -0
- data/lib/datastax_rails/log_subscriber.rb +37 -0
- data/lib/datastax_rails/migrations/migration.rb +15 -0
- data/lib/datastax_rails/migrations.rb +36 -0
- data/lib/datastax_rails/mocking.rb +15 -0
- data/lib/datastax_rails/persistence.rb +133 -0
- data/lib/datastax_rails/railtie.rb +20 -0
- data/lib/datastax_rails/reflection.rb +472 -0
- data/lib/datastax_rails/relation/finder_methods.rb +184 -0
- data/lib/datastax_rails/relation/modification_methods.rb +80 -0
- data/lib/datastax_rails/relation/search_methods.rb +349 -0
- data/lib/datastax_rails/relation/spawn_methods.rb +107 -0
- data/lib/datastax_rails/relation.rb +393 -0
- data/lib/datastax_rails/schema/migration.rb +106 -0
- data/lib/datastax_rails/schema/migration_proxy.rb +25 -0
- data/lib/datastax_rails/schema/migrator.rb +212 -0
- data/lib/datastax_rails/schema.rb +37 -0
- data/lib/datastax_rails/scoping.rb +394 -0
- data/lib/datastax_rails/serialization.rb +6 -0
- data/lib/datastax_rails/tasks/column_family.rb +162 -0
- data/lib/datastax_rails/tasks/ds.rake +63 -0
- data/lib/datastax_rails/tasks/keyspace.rb +57 -0
- data/lib/datastax_rails/timestamps.rb +19 -0
- data/lib/datastax_rails/type.rb +16 -0
- data/lib/datastax_rails/types/array_type.rb +77 -0
- data/lib/datastax_rails/types/base_type.rb +26 -0
- data/lib/datastax_rails/types/binary_type.rb +15 -0
- data/lib/datastax_rails/types/boolean_type.rb +22 -0
- data/lib/datastax_rails/types/date_type.rb +17 -0
- data/lib/datastax_rails/types/float_type.rb +18 -0
- data/lib/datastax_rails/types/integer_type.rb +18 -0
- data/lib/datastax_rails/types/string_type.rb +16 -0
- data/lib/datastax_rails/types/text_type.rb +16 -0
- data/lib/datastax_rails/types/time_type.rb +17 -0
- data/lib/datastax_rails/types.rb +9 -0
- data/lib/datastax_rails/validations/uniqueness.rb +119 -0
- data/lib/datastax_rails/validations.rb +48 -0
- data/lib/datastax_rails/version.rb +3 -0
- data/lib/datastax_rails.rb +87 -0
- data/lib/solr_no_escape.rb +28 -0
- data/spec/datastax_rails/associations/belongs_to_association_spec.rb +7 -0
- data/spec/datastax_rails/associations/has_many_association_spec.rb +37 -0
- data/spec/datastax_rails/associations_spec.rb +22 -0
- data/spec/datastax_rails/attribute_methods_spec.rb +23 -0
- data/spec/datastax_rails/base_spec.rb +15 -0
- data/spec/datastax_rails/cql/select_spec.rb +12 -0
- data/spec/datastax_rails/cql/update_spec.rb +0 -0
- data/spec/datastax_rails/relation/finder_methods_spec.rb +54 -0
- data/spec/datastax_rails/relation/modification_methods_spec.rb +41 -0
- data/spec/datastax_rails/relation/search_methods_spec.rb +117 -0
- data/spec/datastax_rails/relation/spawn_methods_spec.rb +28 -0
- data/spec/datastax_rails/relation_spec.rb +130 -0
- data/spec/datastax_rails/validations/uniqueness_spec.rb +41 -0
- data/spec/datastax_rails_spec.rb +5 -0
- data/spec/dummy/Rakefile +8 -0
- data/spec/dummy/app/assets/javascripts/application.js +9 -0
- data/spec/dummy/app/assets/stylesheets/application.css +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config/application.rb +47 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/datastax.yml +18 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +30 -0
- data/spec/dummy/config/environments/production.rb +60 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/config/sunspot.yml +17 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/ks/migrate/20111117224534_models.rb +20 -0
- data/spec/dummy/ks/schema.json +180 -0
- data/spec/dummy/log/development.log +298 -0
- data/spec/dummy/log/production.log +0 -0
- data/spec/dummy/log/test.log +20307 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/datastax_test_hook.rb +14 -0
- data/spec/support/models.rb +72 -0
- 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,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,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
|