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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/README.rdoc +13 -13
  3. data/Rakefile +1 -0
  4. data/config/schema.xml.erb +0 -1
  5. data/config/{solrconfig.xml → solrconfig.xml.erb} +1 -1
  6. data/lib/blankslate.rb +1 -1
  7. data/lib/datastax_rails/associations/collection_proxy.rb +6 -2
  8. data/lib/datastax_rails/attribute_assignment.rb +114 -0
  9. data/lib/datastax_rails/attribute_methods/definition.rb +8 -2
  10. data/lib/datastax_rails/attribute_methods/typecasting.rb +2 -5
  11. data/lib/datastax_rails/attribute_methods.rb +9 -7
  12. data/lib/datastax_rails/base.rb +127 -109
  13. data/lib/datastax_rails/callbacks.rb +11 -7
  14. data/lib/datastax_rails/cassandra_only_model.rb +27 -0
  15. data/lib/datastax_rails/collection.rb +3 -1
  16. data/lib/datastax_rails/cql/base.rb +4 -0
  17. data/lib/datastax_rails/cql/select.rb +12 -2
  18. data/lib/datastax_rails/identity/abstract_key_factory.rb +1 -0
  19. data/lib/datastax_rails/identity/custom_key_factory.rb +1 -0
  20. data/lib/datastax_rails/identity/natural_key_factory.rb +1 -0
  21. data/lib/datastax_rails/identity/uuid_key_factory.rb +4 -0
  22. data/lib/datastax_rails/identity.rb +2 -1
  23. data/lib/datastax_rails/inheritance.rb +61 -0
  24. data/lib/datastax_rails/payload_model.rb +2 -5
  25. data/lib/datastax_rails/persistence.rb +63 -20
  26. data/lib/datastax_rails/railtie.rb +5 -1
  27. data/lib/datastax_rails/relation/batches.rb +2 -2
  28. data/lib/datastax_rails/relation/facet_methods.rb +56 -5
  29. data/lib/datastax_rails/relation/finder_methods.rb +55 -1
  30. data/lib/datastax_rails/relation/search_methods.rb +103 -32
  31. data/lib/datastax_rails/relation/spawn_methods.rb +3 -1
  32. data/lib/datastax_rails/relation/stats_methods.rb +1 -1
  33. data/lib/datastax_rails/relation.rb +166 -30
  34. data/lib/datastax_rails/schema/cassandra.rb +165 -0
  35. data/lib/datastax_rails/schema/migrator.rb +85 -193
  36. data/lib/datastax_rails/schema/solr.rb +158 -0
  37. data/lib/datastax_rails/schema.rb +2 -30
  38. data/lib/datastax_rails/scoping/default.rb +142 -0
  39. data/lib/datastax_rails/scoping/named.rb +200 -0
  40. data/lib/datastax_rails/scoping.rb +106 -349
  41. data/lib/datastax_rails/tasks/ds.rake +41 -42
  42. data/lib/datastax_rails/types/array_type.rb +1 -1
  43. data/lib/datastax_rails/types/base_type.rb +2 -2
  44. data/lib/datastax_rails/types/binary_type.rb +1 -1
  45. data/lib/datastax_rails/types/boolean_type.rb +1 -1
  46. data/lib/datastax_rails/types/date_type.rb +1 -1
  47. data/lib/datastax_rails/types/float_type.rb +4 -4
  48. data/lib/datastax_rails/types/integer_type.rb +3 -3
  49. data/lib/datastax_rails/types/string_type.rb +1 -1
  50. data/lib/datastax_rails/types/text_type.rb +1 -1
  51. data/lib/datastax_rails/types/time_type.rb +3 -3
  52. data/lib/datastax_rails/validations/uniqueness.rb +1 -1
  53. data/lib/datastax_rails/version.rb +1 -1
  54. data/lib/datastax_rails/wide_storage_model.rb +44 -0
  55. data/lib/datastax_rails.rb +16 -18
  56. data/spec/datastax_rails/associations_spec.rb +7 -3
  57. data/spec/datastax_rails/attribute_methods_spec.rb +23 -0
  58. data/spec/datastax_rails/base_spec.rb +1 -6
  59. data/spec/datastax_rails/inheritance_spec.rb +41 -0
  60. data/spec/datastax_rails/persistence_spec.rb +13 -3
  61. data/spec/datastax_rails/relation/batches_spec.rb +1 -1
  62. data/spec/datastax_rails/relation/facet_methods_spec.rb +52 -0
  63. data/spec/datastax_rails/relation/finder_methods_spec.rb +22 -1
  64. data/spec/datastax_rails/relation/search_methods_spec.rb +51 -1
  65. data/spec/datastax_rails/relation_spec.rb +14 -3
  66. data/spec/datastax_rails/schema/migrator_spec.rb +92 -0
  67. data/spec/datastax_rails/schema/solr_spec.rb +34 -0
  68. data/spec/datastax_rails/scoping/default_spec.rb +17 -0
  69. data/spec/datastax_rails/types/float_type_spec.rb +5 -9
  70. data/spec/datastax_rails/types/integer_type_spec.rb +5 -9
  71. data/spec/datastax_rails/types/time_type_spec.rb +28 -0
  72. data/spec/datastax_rails/validations/uniqueness_spec.rb +3 -1
  73. data/spec/dummy/config/application.rb +1 -4
  74. data/spec/dummy/config/datastax.yml +1 -1
  75. data/spec/dummy/config/environments/test.rb +2 -0
  76. data/spec/dummy/config/solr/articles-schema.xml.erb +1 -0
  77. data/spec/dummy/db/test.sqlite3 +0 -0
  78. data/spec/dummy/log/development.log +2 -0
  79. data/spec/dummy/log/production.log +2 -0
  80. data/spec/dummy/log/test.log +523 -0
  81. data/spec/spec_helper.rb +11 -0
  82. data/spec/support/models.rb +14 -0
  83. metadata +66 -22
  84. data/lib/datastax_rails/log_subscriber.rb +0 -37
  85. data/lib/datastax_rails/migrations/migration.rb +0 -15
  86. data/lib/datastax_rails/migrations.rb +0 -36
  87. data/lib/datastax_rails/mocking.rb +0 -15
  88. data/lib/datastax_rails/schema/migration.rb +0 -106
  89. data/lib/datastax_rails/schema/migration_proxy.rb +0 -25
  90. data/lib/datastax_rails/tasks/column_family.rb +0 -329
  91. data/lib/datastax_rails/tasks/keyspace.rb +0 -57
  92. data/spec/support/connection_double.rb +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 315f2c0bed2d3ebd73b696212d09be65be6071f1
4
- data.tar.gz: 3c7f2f05d532f73ec40128bf748f032cb7825ec4
3
+ metadata.gz: a8971782b7516d5060103ef9b6ed6b56b71a5ad4
4
+ data.tar.gz: 19487f48ae56cdf4ead4176377f5e0bbe3ac6bc3
5
5
  SHA512:
6
- metadata.gz: 956823938bdc95ac435bd57a7ec19cd6d1f565790847d10117fb86f30a2db78cbbe3ca0466db66632c9cd6a826bc1564146b687ac15027e15e8de54639698754
7
- data.tar.gz: 0c082e39d39012a3c79dbed78180433dee4cd9bd0138aa3c9116aa03a267a5dff3f009973a9f86fb323e3a9a40254efd4d1afa8762f39ec72e56ca3909aed5aa
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:schema
68
- rake ds:schema RAILS_ENV=test
67
+ rake ds:migrate
68
+ rake ds:migrate RAILS_ENV=test
69
69
 
70
- It is safe to run ds:schema over and over. In fact, it is necessary to re-run it any time you change the
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
- key :uuid
77
- string :first_name
78
- string :user_name
79
- text :bio
80
- date :birthdate
81
- boolean :active
82
- timestamps
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
- Trying to set a value to nil via the solr API results in the field value not changing at all. Updating it via CQL doesn't have this issue.
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
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env rake
2
+ require 'rubygems'
2
3
  begin
3
4
  require 'bundler/setup'
4
5
  rescue LoadError
@@ -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>0</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
- match = ActiveRecord::DynamicFinderMatch.match(method)
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
@@ -1,6 +1,10 @@
1
- require 'active_record/dynamic_finder_match'
2
- require 'active_record/dynamic_scope_match'
3
- require 'datastax_rails/log_subscriber'
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
- sanitize_for_mass_assignment(attributes).each do |k,v|
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
- if match = ActiveRecord::DynamicFinderMatch.match(method_id)
523
- return true if all_attributes_exists?(match.attribute_names)
524
- elsif match = ActiveRecord::DynamicScopeMatch.match(method_id)
525
- return true if all_attributes_exists?(match.attribute_names)
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 match = ActiveRecord::DynamicFinderMatch.match(method_id)
582
- attribute_names = match.attribute_names
583
- super unless all_attributes_exists?(attribute_names)
584
- if !arguments.first.is_a?(Hash) && arguments.size < attribute_names.size
585
- ActiveSupport::Deprecation.warn(
586
- "Calling dynamic finder with less number of arguments than the number of attributes in " \
587
- "method name is deprecated and will raise an ArguementError in the next version of Rails. " \
588
- "Please passing `nil' to the argument you want it to be nil."
589
- )
590
- end
591
- if match.finder?
592
- options = arguments.extract_options!
593
- relation = options.any? ? scoped(options) : scoped
594
- relation.send :find_by_attributes, match, attribute_names, *arguments
595
- elsif match.instantiator?
596
- scoped.send :find_or_instantiator_by_attributes, match, attribute_names, *arguments, &block
597
- end
598
- elsif match = ActiveRecord::DynamicScopeMatch.match(method_id)
599
- attribute_names = match.attribute_names
600
- super unless all_attributes_exists?(attribute_names)
601
- if arguments.size < attribute_names.size
602
- ActiveSupport::Deprecation.warn(
603
- "Calling dynamic scope with less number of arguments than the number of attributes in " \
604
- "method name is deprecated and will raise an ArguementError in the next version of Rails. " \
605
- "Please passing `nil' to the argument you want it to be nil."
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
- if match.scope?
609
- self.class_eval <<-METHOD, __FILE__, __LINE__ + 1
610
- def self.#{method_id}(*args) # def self.scoped_by_user_name_and_password(*args)
611
- attributes = Hash[[:#{attribute_names.join(',:')}].zip(args)] # attributes = Hash[[:user_name, :password].zip(args)]
612
- scoped(:conditions => attributes) # scoped(:conditions => attributes)
613
- end # end
614
- METHOD
615
- send(method_id, *arguments)
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
- @relation ||= Relation.new(self, column_family)
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