datastax_rails 1.1.0.3 → 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.rdoc +13 -13
- data/Rakefile +1 -0
- data/config/schema.xml.erb +0 -1
- data/config/{solrconfig.xml → solrconfig.xml.erb} +1 -1
- data/lib/blankslate.rb +1 -1
- data/lib/datastax_rails/associations/collection_proxy.rb +6 -2
- data/lib/datastax_rails/attribute_assignment.rb +114 -0
- data/lib/datastax_rails/attribute_methods/definition.rb +8 -2
- data/lib/datastax_rails/attribute_methods/typecasting.rb +2 -5
- data/lib/datastax_rails/attribute_methods.rb +9 -7
- data/lib/datastax_rails/base.rb +127 -109
- data/lib/datastax_rails/callbacks.rb +11 -7
- data/lib/datastax_rails/cassandra_only_model.rb +27 -0
- data/lib/datastax_rails/collection.rb +3 -1
- data/lib/datastax_rails/cql/base.rb +4 -0
- data/lib/datastax_rails/cql/select.rb +12 -2
- data/lib/datastax_rails/identity/abstract_key_factory.rb +1 -0
- data/lib/datastax_rails/identity/custom_key_factory.rb +1 -0
- data/lib/datastax_rails/identity/natural_key_factory.rb +1 -0
- data/lib/datastax_rails/identity/uuid_key_factory.rb +4 -0
- data/lib/datastax_rails/identity.rb +2 -1
- data/lib/datastax_rails/inheritance.rb +61 -0
- data/lib/datastax_rails/payload_model.rb +2 -5
- data/lib/datastax_rails/persistence.rb +63 -20
- data/lib/datastax_rails/railtie.rb +5 -1
- data/lib/datastax_rails/relation/batches.rb +2 -2
- data/lib/datastax_rails/relation/facet_methods.rb +56 -5
- data/lib/datastax_rails/relation/finder_methods.rb +55 -1
- data/lib/datastax_rails/relation/search_methods.rb +103 -32
- data/lib/datastax_rails/relation/spawn_methods.rb +3 -1
- data/lib/datastax_rails/relation/stats_methods.rb +1 -1
- data/lib/datastax_rails/relation.rb +166 -30
- data/lib/datastax_rails/schema/cassandra.rb +165 -0
- data/lib/datastax_rails/schema/migrator.rb +85 -193
- data/lib/datastax_rails/schema/solr.rb +158 -0
- data/lib/datastax_rails/schema.rb +2 -30
- data/lib/datastax_rails/scoping/default.rb +142 -0
- data/lib/datastax_rails/scoping/named.rb +200 -0
- data/lib/datastax_rails/scoping.rb +106 -349
- data/lib/datastax_rails/tasks/ds.rake +41 -42
- data/lib/datastax_rails/types/array_type.rb +1 -1
- data/lib/datastax_rails/types/base_type.rb +2 -2
- data/lib/datastax_rails/types/binary_type.rb +1 -1
- data/lib/datastax_rails/types/boolean_type.rb +1 -1
- data/lib/datastax_rails/types/date_type.rb +1 -1
- data/lib/datastax_rails/types/float_type.rb +4 -4
- data/lib/datastax_rails/types/integer_type.rb +3 -3
- data/lib/datastax_rails/types/string_type.rb +1 -1
- data/lib/datastax_rails/types/text_type.rb +1 -1
- data/lib/datastax_rails/types/time_type.rb +3 -3
- data/lib/datastax_rails/validations/uniqueness.rb +1 -1
- data/lib/datastax_rails/version.rb +1 -1
- data/lib/datastax_rails/wide_storage_model.rb +44 -0
- data/lib/datastax_rails.rb +16 -18
- data/spec/datastax_rails/associations_spec.rb +7 -3
- data/spec/datastax_rails/attribute_methods_spec.rb +23 -0
- data/spec/datastax_rails/base_spec.rb +1 -6
- data/spec/datastax_rails/inheritance_spec.rb +41 -0
- data/spec/datastax_rails/persistence_spec.rb +13 -3
- data/spec/datastax_rails/relation/batches_spec.rb +1 -1
- data/spec/datastax_rails/relation/facet_methods_spec.rb +52 -0
- data/spec/datastax_rails/relation/finder_methods_spec.rb +22 -1
- data/spec/datastax_rails/relation/search_methods_spec.rb +51 -1
- data/spec/datastax_rails/relation_spec.rb +14 -3
- data/spec/datastax_rails/schema/migrator_spec.rb +92 -0
- data/spec/datastax_rails/schema/solr_spec.rb +34 -0
- data/spec/datastax_rails/scoping/default_spec.rb +17 -0
- data/spec/datastax_rails/types/float_type_spec.rb +5 -9
- data/spec/datastax_rails/types/integer_type_spec.rb +5 -9
- data/spec/datastax_rails/types/time_type_spec.rb +28 -0
- data/spec/datastax_rails/validations/uniqueness_spec.rb +3 -1
- data/spec/dummy/config/application.rb +1 -4
- data/spec/dummy/config/datastax.yml +1 -1
- data/spec/dummy/config/environments/test.rb +2 -0
- data/spec/dummy/config/solr/articles-schema.xml.erb +1 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +2 -0
- data/spec/dummy/log/production.log +2 -0
- data/spec/dummy/log/test.log +523 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/models.rb +14 -0
- metadata +66 -22
- data/lib/datastax_rails/log_subscriber.rb +0 -37
- data/lib/datastax_rails/migrations/migration.rb +0 -15
- data/lib/datastax_rails/migrations.rb +0 -36
- data/lib/datastax_rails/mocking.rb +0 -15
- data/lib/datastax_rails/schema/migration.rb +0 -106
- data/lib/datastax_rails/schema/migration_proxy.rb +0 -25
- data/lib/datastax_rails/tasks/column_family.rb +0 -329
- data/lib/datastax_rails/tasks/keyspace.rb +0 -57
- data/spec/support/connection_double.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8971782b7516d5060103ef9b6ed6b56b71a5ad4
|
4
|
+
data.tar.gz: 19487f48ae56cdf4ead4176377f5e0bbe3ac6bc3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7af9042a6919a4567e66b925934cd17e17fcbecb7dd6edf4ab6de5e66c6af378f942eab851bb962c197f6f46a44bd5a657df747c886f6169c1a9796c0ddc9e46
|
7
|
+
data.tar.gz: 9e0fef7994f2746c934f15b6922e6dfae0b7974b0b4ee88d7594287709f8c3cb7e25cea3dd936a4e16ecaa524eb6fa0ea255bbdc84f460f36040a1f58ca82669
|
data/README.rdoc
CHANGED
@@ -64,27 +64,27 @@ Create your keyspace:
|
|
64
64
|
|
65
65
|
Once you've created some models, the following will upload the solr schemas and create the column families:
|
66
66
|
|
67
|
-
rake ds:
|
68
|
-
rake ds:
|
67
|
+
rake ds:migrate
|
68
|
+
rake ds:migrate RAILS_ENV=test
|
69
69
|
|
70
|
-
It is safe to run ds:
|
70
|
+
It is safe to run ds:migrate over and over. In fact, it is necessary to re-run it any time you change the
|
71
71
|
attributes on any model. DSR will only upload schema files if they have changed.
|
72
72
|
|
73
73
|
Create a sample Model. See Base documentation for more details:
|
74
74
|
|
75
|
-
class Person < DatastaxRails::Base
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
75
|
+
class Person < DatastaxRails::Base
|
76
|
+
key :uuid
|
77
|
+
string :first_name
|
78
|
+
string :user_name
|
79
|
+
text :bio
|
80
|
+
date :birthdate
|
81
|
+
boolean :active
|
82
|
+
timestamps
|
83
|
+
end
|
84
84
|
|
85
85
|
=== Known issues
|
86
86
|
|
87
|
-
|
87
|
+
When doing a grouped query, the total groups reported is only the total groups included in your query, not the total matching groups (if you're paginating). This is due to the way solr sharding works with grouped queries.
|
88
88
|
|
89
89
|
=== More information
|
90
90
|
|
data/Rakefile
CHANGED
data/config/schema.xml.erb
CHANGED
@@ -48,7 +48,6 @@
|
|
48
48
|
<fieldType name="float" class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/>
|
49
49
|
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
|
50
50
|
<fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" positionIncrementGap="0"/>
|
51
|
-
|
52
51
|
</types>
|
53
52
|
<fields>
|
54
53
|
<field name="id" type="string" indexed="true" stored="true"/>
|
@@ -50,7 +50,7 @@
|
|
50
50
|
<luceneMatchVersion>LUCENE_40</luceneMatchVersion>
|
51
51
|
|
52
52
|
<!-- Enable DSE Search new type mappings -->
|
53
|
-
<dseTypeMappingVersion
|
53
|
+
<dseTypeMappingVersion><%= @legacy ? 0 : 1 %></dseTypeMappingVersion>
|
54
54
|
|
55
55
|
<!-- lib directives can be used to instruct Solr to load an Jars
|
56
56
|
identified and use them to resolve any "plugins" specified in
|
data/lib/blankslate.rb
CHANGED
@@ -21,7 +21,7 @@ class BlankSlate
|
|
21
21
|
def hide(name)
|
22
22
|
methods = instance_methods.map(&:to_sym)
|
23
23
|
if methods.include?(name.to_sym) and
|
24
|
-
name !~ /^(__|instance_eval)/
|
24
|
+
name !~ /^(__|instance_eval|object_id)/
|
25
25
|
@hidden_methods ||= {}
|
26
26
|
@hidden_methods[name.to_sym] = instance_method(name)
|
27
27
|
undef_method name
|
@@ -61,7 +61,11 @@ module DatastaxRails
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def method_missing(method, *args, &block)
|
64
|
-
|
64
|
+
if Rails.version =~ /^3.*/
|
65
|
+
match = ActiveRecord::DynamicFinderMatch.match(method)
|
66
|
+
elsif Rails.version =~ /^4.*/
|
67
|
+
match = ActiveRecord::DynamicMatchers::Method.match(self, method)
|
68
|
+
end
|
65
69
|
if match && match.instantiator?
|
66
70
|
send(:find_or_instantiator_by_attributes, match, match.attribute_names, *args) do |r|
|
67
71
|
proxy_association.send :set_owner_attributes, r
|
@@ -115,4 +119,4 @@ module DatastaxRails
|
|
115
119
|
end
|
116
120
|
end
|
117
121
|
end
|
118
|
-
end
|
122
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module DatastaxRails
|
4
|
+
module AttributeAssignment
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
if Rails.version =~ /^3.*/
|
7
|
+
include ActiveModel::MassAssignmentSecurity
|
8
|
+
elsif Rails.version =~ /^4.*/
|
9
|
+
include ActiveModel::DeprecatedMassAssignmentSecurity
|
10
|
+
include ActiveModel::ForbiddenAttributesProtection
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
private
|
15
|
+
|
16
|
+
# The primary key can never be set by mass-assignment for security reasons.
|
17
|
+
def attributes_protected_by_default
|
18
|
+
["key"]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Allows you to set all the attributes at once by passing in a hash with keys
|
23
|
+
# matching the attribute names (which again matches the column names).
|
24
|
+
#
|
25
|
+
# If any attributes are protected by either +attr_protected+ or
|
26
|
+
# +attr_accessible+ then only settable attributes will be assigned.
|
27
|
+
#
|
28
|
+
# class User < ActiveRecord::Base
|
29
|
+
# attr_protected :is_admin
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# user = User.new
|
33
|
+
# user.attributes = { :username => 'Phusion', :is_admin => true }
|
34
|
+
# user.username # => "Phusion"
|
35
|
+
# user.is_admin? # => false
|
36
|
+
def attributes=(new_attributes)
|
37
|
+
return unless new_attributes.is_a?(Hash)
|
38
|
+
|
39
|
+
assign_attributes(new_attributes)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Allows you to set all the attributes for a particular mass-assignment
|
43
|
+
# security role by passing in a hash of attributes with keys matching
|
44
|
+
# the attribute names (which again matches the column names) and the role
|
45
|
+
# name using the :as option.
|
46
|
+
#
|
47
|
+
# To bypass mass-assignment security you can use the :without_protection => true
|
48
|
+
# option.
|
49
|
+
#
|
50
|
+
# class User < ActiveRecord::Base
|
51
|
+
# attr_accessible :name
|
52
|
+
# attr_accessible :name, :is_admin, :as => :admin
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# user = User.new
|
56
|
+
# user.assign_attributes({ :name => 'Josh', :is_admin => true })
|
57
|
+
# user.name # => "Josh"
|
58
|
+
# user.is_admin? # => false
|
59
|
+
#
|
60
|
+
# user = User.new
|
61
|
+
# user.assign_attributes({ :name => 'Josh', :is_admin => true }, :as => :admin)
|
62
|
+
# user.name # => "Josh"
|
63
|
+
# user.is_admin? # => true
|
64
|
+
#
|
65
|
+
# user = User.new
|
66
|
+
# user.assign_attributes({ :name => 'Josh', :is_admin => true }, :without_protection => true)
|
67
|
+
# user.name # => "Josh"
|
68
|
+
# user.is_admin? # => true
|
69
|
+
def assign_attributes(new_attributes, options = {})
|
70
|
+
return if new_attributes.blank?
|
71
|
+
|
72
|
+
attributes = new_attributes.stringify_keys
|
73
|
+
nested_parameter_attributes = []
|
74
|
+
@mass_assignment_options = options
|
75
|
+
|
76
|
+
unless options[:without_protection]
|
77
|
+
if Rails.version =~ /3.*/
|
78
|
+
attributes = sanitize_for_mass_assignment(attributes, mass_assignment_role)
|
79
|
+
else
|
80
|
+
attributes = sanitize_for_mass_assignment(attributes)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
attributes.each do |k, v|
|
85
|
+
if respond_to?("#{k}=")
|
86
|
+
if v.is_a?(Hash)
|
87
|
+
nested_parameter_attributes << [ k, v ]
|
88
|
+
else
|
89
|
+
send("#{k}=", v)
|
90
|
+
end
|
91
|
+
else
|
92
|
+
raise(UnknownAttributeError, "unknown attribute: #{k}")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# assign any deferred nested attributes after the base attributes have been set
|
97
|
+
nested_parameter_attributes.each do |k,v|
|
98
|
+
send("#{k}=", v)
|
99
|
+
end
|
100
|
+
|
101
|
+
@mass_assignment_options = nil
|
102
|
+
end
|
103
|
+
|
104
|
+
protected
|
105
|
+
|
106
|
+
def mass_assignment_options
|
107
|
+
@mass_assignment_options ||= {}
|
108
|
+
end
|
109
|
+
|
110
|
+
def mass_assignment_role
|
111
|
+
mass_assignment_options[:as] || :default
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
module DatastaxRails
|
2
2
|
module AttributeMethods
|
3
3
|
class Definition
|
4
|
-
attr_reader :name, :coder, :lazy
|
5
|
-
def initialize(name, coder, options)
|
4
|
+
attr_reader :klass, :name, :coder, :lazy
|
5
|
+
def initialize(klass, name, coder, options)
|
6
|
+
@klass = klass
|
6
7
|
@name = name.to_s
|
7
8
|
@lazy = options.delete(:lazy)
|
8
9
|
@coder = coder.new(options)
|
@@ -16,6 +17,11 @@ module DatastaxRails
|
|
16
17
|
coder.wrap(record, name, value)
|
17
18
|
end
|
18
19
|
|
20
|
+
# Returns :solr, :cassandra, :both, or +false+
|
21
|
+
def indexed
|
22
|
+
coder.options[:indexed]
|
23
|
+
end
|
24
|
+
|
19
25
|
def type
|
20
26
|
coder.type
|
21
27
|
end
|
@@ -7,7 +7,7 @@ module DatastaxRails
|
|
7
7
|
class_attribute :attribute_definitions
|
8
8
|
class_attribute :lazy_attributes
|
9
9
|
class_attribute :readonly_attributes
|
10
|
-
self.attribute_definitions =
|
10
|
+
self.attribute_definitions = ActiveSupport::HashWithIndifferentAccess.new
|
11
11
|
self.lazy_attributes = []
|
12
12
|
self.readonly_attributes = []
|
13
13
|
|
@@ -20,12 +20,9 @@ module DatastaxRails
|
|
20
20
|
end
|
21
21
|
|
22
22
|
# We need to ensure that inherited classes get their own attribute definitions.
|
23
|
-
# In addition, we take the opportunity to track all the DatastaxRails::Base decendents.
|
24
|
-
# This will be useful when it comes to things like schema generation.
|
25
23
|
def inherited(child)
|
26
24
|
super
|
27
25
|
child.attribute_definitions = attribute_definitions.dup
|
28
|
-
self.models << child
|
29
26
|
end
|
30
27
|
|
31
28
|
# @!group Attribute Types
|
@@ -99,4 +96,4 @@ module DatastaxRails
|
|
99
96
|
end
|
100
97
|
end
|
101
98
|
end
|
102
|
-
end
|
99
|
+
end
|
@@ -32,6 +32,14 @@ module DatastaxRails
|
|
32
32
|
def attribute(name, options)
|
33
33
|
type = options.delete :type
|
34
34
|
coder = options.delete :coder
|
35
|
+
|
36
|
+
if self <= CassandraOnlyModel
|
37
|
+
if options[:indexed] == :both || options[:indexed] == :cassandra
|
38
|
+
options[:indexed] = :cassandra
|
39
|
+
else
|
40
|
+
options[:indexed] = false
|
41
|
+
end
|
42
|
+
end
|
35
43
|
|
36
44
|
if type.is_a?(Symbol)
|
37
45
|
coder = DatastaxRails::Type.get_coder(type) || (raise "Unknown type #{type}")
|
@@ -47,7 +55,7 @@ module DatastaxRails
|
|
47
55
|
readonly_attributes << name.to_sym
|
48
56
|
end
|
49
57
|
|
50
|
-
attribute_definitions[name.to_sym] = AttributeMethods::Definition.new(name, coder, options)
|
58
|
+
attribute_definitions[name.to_sym] = AttributeMethods::Definition.new(self, name, coder, options)
|
51
59
|
end
|
52
60
|
end
|
53
61
|
|
@@ -75,12 +83,6 @@ module DatastaxRails
|
|
75
83
|
@attributes.key?(name.to_s)
|
76
84
|
end
|
77
85
|
|
78
|
-
def attributes=(attributes)
|
79
|
-
attributes.each do |(name, value)|
|
80
|
-
send("#{name}=", value)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
86
|
def method_missing(method_id, *args, &block)
|
85
87
|
if !self.class.attribute_methods_generated?
|
86
88
|
self.class.define_attribute_methods
|
data/lib/datastax_rails/base.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require '
|
1
|
+
if Rails.version =~ /^3.*/
|
2
|
+
# Dynamic finders are only supported in Rails 3.x applications (depricated in 4.x)
|
3
|
+
require 'active_record/dynamic_finder_match'
|
4
|
+
require 'active_record/dynamic_scope_match'
|
5
|
+
elsif Rails.version =~ /^4.*./
|
6
|
+
require 'active_record/deprecated_finders/dynamic_matchers'
|
7
|
+
end
|
4
8
|
require 'datastax_rails/types'
|
5
9
|
require 'datastax_rails/errors'
|
6
10
|
module DatastaxRails #:nodoc:
|
@@ -222,6 +226,8 @@ module DatastaxRails #:nodoc:
|
|
222
226
|
#
|
223
227
|
# == Dynamic attribute-based finders
|
224
228
|
#
|
229
|
+
# Note: These are only available in Rails 3.x applications, and are not supported in Rails 4.x
|
230
|
+
#
|
225
231
|
# Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects
|
226
232
|
# by simple queries without using where chains. They work by appending the name of an attribute
|
227
233
|
# to <tt>find_by_</tt> or <tt>find_all_by_</tt> and thus produces finders
|
@@ -270,6 +276,32 @@ module DatastaxRails #:nodoc:
|
|
270
276
|
#
|
271
277
|
# User.scoped_by_user_name('David')
|
272
278
|
#
|
279
|
+
# == Facets
|
280
|
+
#
|
281
|
+
# DSR support both field and range facets. For additional detail on facets, see the documentation
|
282
|
+
# available under the FacetMethods module. The result is available through the facets accessor
|
283
|
+
#
|
284
|
+
# Facet examples:
|
285
|
+
#
|
286
|
+
# results = Article.field_facet(:author)
|
287
|
+
# results.facets => {"author"=>["vonnegut", 2. "asimov", 3]}
|
288
|
+
#
|
289
|
+
# Model.field_facet(:author)
|
290
|
+
# Model.field_facet(:author, :sort => 'count', :limit => 10, :mincount => 1)
|
291
|
+
# Model.range_facet(:price, 500, 1000, 10)
|
292
|
+
# Model.range_facet(:price, 500, 1000, 10, :include => 'all')
|
293
|
+
# Model.range_facet(:publication_date, "1968-01-01T00:00:00Z", "2000-01-01T00:00:00Z", "+1YEAR")
|
294
|
+
#
|
295
|
+
# Range Gap syntax for dates: +1YEAR, +5YEAR, +5YEARS, +1MONTH, +1DAY
|
296
|
+
#
|
297
|
+
# Useful constants:
|
298
|
+
#
|
299
|
+
# DatastaxRails::FacetMethods::BY_YEAR (+1YEAR)
|
300
|
+
# DatastaxRails::FacetMethods::BY_MONTH (+1MONTH)
|
301
|
+
# DatastaxRails::FacetMethods::BY_DAY (+1DAY)
|
302
|
+
#
|
303
|
+
# Model.range_facet(:publication_date, "1968-01-01T00:00:00Z", "2000-01-01T00:00:00Z", DatastaxRails::FacetMethods::BY_YEAR)
|
304
|
+
#
|
273
305
|
# == Exceptions
|
274
306
|
#
|
275
307
|
# * DatastaxRailsError - Generic error class and superclass of all other errors raised by DatastaxRails.
|
@@ -293,12 +325,13 @@ module DatastaxRails #:nodoc:
|
|
293
325
|
extend ActiveModel::Naming
|
294
326
|
include ActiveModel::Conversion
|
295
327
|
extend ActiveSupport::DescendantsTracker
|
296
|
-
include ActiveModel::MassAssignmentSecurity
|
297
328
|
|
298
329
|
include Connection
|
330
|
+
include Inheritance
|
299
331
|
include Identity
|
300
332
|
include FinderMethods
|
301
333
|
include Batches
|
334
|
+
include AttributeAssignment
|
302
335
|
include AttributeMethods
|
303
336
|
include AttributeMethods::Dirty
|
304
337
|
include AttributeMethods::Typecasting
|
@@ -310,7 +343,6 @@ module DatastaxRails #:nodoc:
|
|
310
343
|
include Scoping
|
311
344
|
include Timestamps
|
312
345
|
include Serialization
|
313
|
-
include Migrations
|
314
346
|
include SolrRepair
|
315
347
|
|
316
348
|
# Stores the default scope for the class
|
@@ -326,9 +358,6 @@ module DatastaxRails #:nodoc:
|
|
326
358
|
class_attribute :storage_method
|
327
359
|
self.storage_method = :cql
|
328
360
|
|
329
|
-
class_attribute :models
|
330
|
-
self.models = []
|
331
|
-
|
332
361
|
attr_reader :attributes
|
333
362
|
attr_reader :loaded_attributes
|
334
363
|
attr_accessor :key
|
@@ -338,29 +367,24 @@ module DatastaxRails #:nodoc:
|
|
338
367
|
class_attribute :serialized_attributes
|
339
368
|
self.serialized_attributes = {}
|
340
369
|
|
370
|
+
# Whether or not we are using solr legacy mappings
|
371
|
+
class_attribute :legacy_mapping
|
372
|
+
|
341
373
|
def initialize(attributes = {}, options = {})
|
342
374
|
@key = attributes.delete(:key)
|
343
375
|
@attributes = {}.with_indifferent_access
|
344
376
|
@loaded_attributes = {}.with_indifferent_access
|
345
377
|
|
346
|
-
@relation = nil
|
347
378
|
@new_record = true
|
348
379
|
@destroyed = false
|
349
380
|
@previously_changed = {}
|
350
381
|
@changed_attributes = {}
|
351
|
-
@schema_version = self.class.current_schema_version
|
352
382
|
|
353
383
|
__set_defaults
|
354
384
|
|
355
385
|
populate_with_current_scope_attributes
|
356
386
|
|
357
|
-
|
358
|
-
if respond_to?("#{k.to_s.downcase}=")
|
359
|
-
send("#{k.to_s.downcase}=",v)
|
360
|
-
else
|
361
|
-
raise(DatastaxRails::UnknownAttributeError, "unknown attribute: #{k}")
|
362
|
-
end
|
363
|
-
end
|
387
|
+
assign_attributes(attributes, options) if attributes
|
364
388
|
|
365
389
|
yield self if block_given?
|
366
390
|
run_callbacks :initialize
|
@@ -405,55 +429,6 @@ module DatastaxRails #:nodoc:
|
|
405
429
|
self == (comparison_object)
|
406
430
|
end
|
407
431
|
|
408
|
-
# Allows you to set all the attributes for a particular mass-assignment
|
409
|
-
# security role by passing in a hash of attributes with keys matching
|
410
|
-
# the attribute names (which again matches the column names) and the role
|
411
|
-
# name using the :as option.
|
412
|
-
#
|
413
|
-
# To bypass mass-assignment security you can use the :without_protection => true
|
414
|
-
# option.
|
415
|
-
#
|
416
|
-
# class User < ActiveRecord::Base
|
417
|
-
# attr_accessible :name
|
418
|
-
# attr_accessible :name, :is_admin, :as => :admin
|
419
|
-
# end
|
420
|
-
#
|
421
|
-
# user = User.new
|
422
|
-
# user.assign_attributes({ :name => 'Josh', :is_admin => true })
|
423
|
-
# user.name # => "Josh"
|
424
|
-
# user.is_admin? # => false
|
425
|
-
#
|
426
|
-
# user = User.new
|
427
|
-
# user.assign_attributes({ :name => 'Josh', :is_admin => true }, :as => :admin)
|
428
|
-
# user.name # => "Josh"
|
429
|
-
# user.is_admin? # => true
|
430
|
-
#
|
431
|
-
# user = User.new
|
432
|
-
# user.assign_attributes({ :name => 'Josh', :is_admin => true }, :without_protection => true)
|
433
|
-
# user.name # => "Josh"
|
434
|
-
# user.is_admin? # => true
|
435
|
-
def assign_attributes(new_attributes, options = {})
|
436
|
-
return unless new_attributes
|
437
|
-
|
438
|
-
attributes = new_attributes.stringify_keys
|
439
|
-
multi_parameter_attributes = []
|
440
|
-
@mass_assignment_options = options
|
441
|
-
|
442
|
-
unless options[:without_protection]
|
443
|
-
attributes = sanitize_for_mass_assignment(attributes, mass_assignment_role)
|
444
|
-
end
|
445
|
-
|
446
|
-
attributes.each do |k, v|
|
447
|
-
if respond_to?("#{k.to_s.downcase}=")
|
448
|
-
send("#{k.to_s.downcase}=",v)
|
449
|
-
else
|
450
|
-
raise(UnknownAttributeError, "unknown attribute: #{k}")
|
451
|
-
end
|
452
|
-
end
|
453
|
-
|
454
|
-
@mass_assignment_options = nil
|
455
|
-
end
|
456
|
-
|
457
432
|
def attribute_names
|
458
433
|
self.class.attribute_names
|
459
434
|
end
|
@@ -472,14 +447,15 @@ module DatastaxRails #:nodoc:
|
|
472
447
|
end
|
473
448
|
|
474
449
|
class << self
|
475
|
-
delegate :find, :first, :all, :exists?, :any?, :many?, :to => :scoped
|
450
|
+
delegate :find, :find_by, :find_by!, :first, :all, :exists?, :any?, :many?, :to => :scoped
|
476
451
|
delegate :destroy, :destroy_all, :delete, :update, :update_all, :to => :scoped
|
477
|
-
delegate :order, :limit, :where, :where_not, :page, :paginate, :select, :to => :scoped
|
452
|
+
delegate :order, :limit, :where, :where_not, :page, :paginate, :select, :slow_order, :to => :scoped
|
478
453
|
delegate :per_page, :each, :group, :total_pages, :search, :fulltext, :to => :scoped
|
479
454
|
delegate :count, :first, :first!, :last, :last!, :compute_stats, :to => :scoped
|
480
455
|
delegate :sum, :average, :minimum, :maximum, :stddev, :to => :scoped
|
481
|
-
delegate :cql, :with_cassandra, :with_solr, :commit_solr, :to => :scoped
|
456
|
+
delegate :cql, :with_cassandra, :with_solr, :commit_solr, :allow_filtering, :to => :scoped
|
482
457
|
delegate :find_each, :find_in_batches, :consistency, :to => :scoped
|
458
|
+
delegate :field_facet, :range_facet, :to => :scoped
|
483
459
|
|
484
460
|
# Sets the column family name
|
485
461
|
#
|
@@ -496,10 +472,22 @@ module DatastaxRails #:nodoc:
|
|
496
472
|
@column_family || name.underscore.pluralize
|
497
473
|
end
|
498
474
|
|
475
|
+
def models
|
476
|
+
self.descendants.reject {|m|m.abstract_class?}
|
477
|
+
end
|
478
|
+
|
499
479
|
def payload_model?
|
500
480
|
self.ancestors.include?(DatastaxRails::PayloadModel)
|
501
481
|
end
|
502
482
|
|
483
|
+
def wide_storage_model?
|
484
|
+
self.ancestors.include?(DatastaxRails::WideStorageModel)
|
485
|
+
end
|
486
|
+
|
487
|
+
def legacy_mapping?
|
488
|
+
@legacy_mapping
|
489
|
+
end
|
490
|
+
|
503
491
|
def base_class
|
504
492
|
klass = self
|
505
493
|
while klass.superclass != Base
|
@@ -519,12 +507,19 @@ module DatastaxRails #:nodoc:
|
|
519
507
|
end
|
520
508
|
|
521
509
|
def respond_to?(method_id, include_private = false)
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
510
|
+
|
511
|
+
if Rails.version =~ /^3.*/
|
512
|
+
if match = ActiveRecord::DynamicFinderMatch.match(method_id)
|
513
|
+
return true if all_attributes_exists?(match.attribute_names)
|
514
|
+
elsif match = ActiveRecord::DynamicScopeMatch.match(method_id)
|
515
|
+
return true if all_attributes_exists?(match.attribute_names)
|
516
|
+
end
|
517
|
+
elsif Rails.version =~ /^4.*/
|
518
|
+
if match = ActiveRecord::DynamicMatchers::Method.match(self, method_id)
|
519
|
+
return true if all_attributes_exists?(match.attribute_names)
|
520
|
+
end
|
526
521
|
end
|
527
|
-
|
522
|
+
|
528
523
|
super
|
529
524
|
end
|
530
525
|
|
@@ -578,41 +573,64 @@ module DatastaxRails #:nodoc:
|
|
578
573
|
# Each dynamic finder using <tt>scoped_by_*</tt> is also defined in the class after it
|
579
574
|
# is first invoked, so that future attempts to use it do not run through method_missing.
|
580
575
|
def method_missing(method_id, *arguments, &block)
|
581
|
-
if
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
576
|
+
if Rails.version =~ /^3.*/
|
577
|
+
if match = ActiveRecord::DynamicFinderMatch.match(method_id)
|
578
|
+
attribute_names = match.attribute_names
|
579
|
+
super unless all_attributes_exists?(attribute_names)
|
580
|
+
if !arguments.first.is_a?(Hash) && arguments.size < attribute_names.size
|
581
|
+
ActiveSupport::Deprecation.warn(
|
582
|
+
"Calling dynamic finder with less number of arguments than the number of attributes in " \
|
583
|
+
"method name is deprecated and will raise an ArguementError in the next version of Rails. " \
|
584
|
+
"Please passing `nil' to the argument you want it to be nil."
|
585
|
+
)
|
586
|
+
end
|
587
|
+
if match.finder?
|
588
|
+
options = arguments.extract_options!
|
589
|
+
relation = options.any? ? scoped(options) : scoped
|
590
|
+
relation.send :find_by_attributes, match, attribute_names, *arguments
|
591
|
+
elsif match.instantiator?
|
592
|
+
scoped.send :find_or_instantiator_by_attributes, match, attribute_names, *arguments, &block
|
593
|
+
end
|
594
|
+
elsif match = ActiveRecord::DynamicScopeMatch.match(method_id)
|
595
|
+
attribute_names = match.attribute_names
|
596
|
+
super unless all_attributes_exists?(attribute_names)
|
597
|
+
if arguments.size < attribute_names.size
|
598
|
+
ActiveSupport::Deprecation.warn(
|
599
|
+
"Calling dynamic scope with less number of arguments than the number of attributes in " \
|
600
|
+
"method name is deprecated and will raise an ArguementError in the next version of Rails. " \
|
601
|
+
"Please passing `nil' to the argument you want it to be nil."
|
602
|
+
)
|
603
|
+
end
|
604
|
+
if match.scope?
|
605
|
+
self.class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
606
|
+
def self.#{method_id}(*args) # def self.scoped_by_user_name_and_password(*args)
|
607
|
+
attributes = Hash[[:#{attribute_names.join(',:')}].zip(args)] # attributes = Hash[[:user_name, :password].zip(args)]
|
608
|
+
scoped(:conditions => attributes) # scoped(:conditions => attributes)
|
609
|
+
end # end
|
610
|
+
METHOD
|
611
|
+
send(method_id, *arguments)
|
612
|
+
end
|
613
|
+
else
|
614
|
+
super
|
607
615
|
end
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
+
elsif Rails.version =~ /^4.*/
|
617
|
+
if match = ActiveRecord::DynamicMatchers::Method.match(self, method_id)
|
618
|
+
attribute_names = match.attribute_names
|
619
|
+
super unless all_attributes_exists?(attribute_names)
|
620
|
+
if !arguments.first.is_a?(Hash) && arguments.size < attribute_names.size
|
621
|
+
ActiveSupport::Deprecation.warn(
|
622
|
+
"Calling dynamic scope with less number of arguments than the number of attributes in " \
|
623
|
+
"method name is deprecated and will raise an ArguementError in the next version of Rails. " \
|
624
|
+
"Please passing `nil' to the argument you want it to be nil."
|
625
|
+
)
|
626
|
+
end
|
627
|
+
if match.finder.present?
|
628
|
+
options = arguments.extract_options!
|
629
|
+
relation = options.any? ? scoped(options) : scoped
|
630
|
+
relation.send :find_by_attributes, match, attribute_names, *arguments
|
631
|
+
elsif match.instantiator?
|
632
|
+
scoped.send :find_or_instantiator_by_attributes, match, attribute_names, *arguments, &block
|
633
|
+
end
|
616
634
|
end
|
617
635
|
else
|
618
636
|
super
|
@@ -624,7 +642,7 @@ module DatastaxRails #:nodoc:
|
|
624
642
|
end
|
625
643
|
|
626
644
|
def relation #:nodoc:
|
627
|
-
|
645
|
+
Relation.new(self, column_family)
|
628
646
|
end
|
629
647
|
|
630
648
|
# Returns the class type of the record using the current module as a prefix. So descendants of
|