datastax_rails 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +62 -0
  3. data/Rakefile +34 -0
  4. data/config/schema.xml +266 -0
  5. data/config/schema.xml.erb +70 -0
  6. data/config/solrconfig.xml +1564 -0
  7. data/config/stopwords.txt +58 -0
  8. data/lib/datastax_rails/associations/association.rb +224 -0
  9. data/lib/datastax_rails/associations/association_scope.rb +25 -0
  10. data/lib/datastax_rails/associations/belongs_to_association.rb +64 -0
  11. data/lib/datastax_rails/associations/builder/association.rb +56 -0
  12. data/lib/datastax_rails/associations/builder/belongs_to.rb +30 -0
  13. data/lib/datastax_rails/associations/builder/collection_association.rb +48 -0
  14. data/lib/datastax_rails/associations/builder/has_and_belongs_to_many.rb +36 -0
  15. data/lib/datastax_rails/associations/builder/has_many.rb +54 -0
  16. data/lib/datastax_rails/associations/builder/has_one.rb +52 -0
  17. data/lib/datastax_rails/associations/builder/singular_association.rb +56 -0
  18. data/lib/datastax_rails/associations/collection_association.rb +274 -0
  19. data/lib/datastax_rails/associations/collection_proxy.rb +118 -0
  20. data/lib/datastax_rails/associations/has_and_belongs_to_many_association.rb +44 -0
  21. data/lib/datastax_rails/associations/has_many_association.rb +58 -0
  22. data/lib/datastax_rails/associations/has_one_association.rb +68 -0
  23. data/lib/datastax_rails/associations/singular_association.rb +58 -0
  24. data/lib/datastax_rails/associations.rb +86 -0
  25. data/lib/datastax_rails/attribute_methods/definition.rb +20 -0
  26. data/lib/datastax_rails/attribute_methods/dirty.rb +43 -0
  27. data/lib/datastax_rails/attribute_methods/typecasting.rb +50 -0
  28. data/lib/datastax_rails/attribute_methods.rb +104 -0
  29. data/lib/datastax_rails/base.rb +587 -0
  30. data/lib/datastax_rails/batches.rb +35 -0
  31. data/lib/datastax_rails/callbacks.rb +37 -0
  32. data/lib/datastax_rails/collection.rb +9 -0
  33. data/lib/datastax_rails/connection.rb +21 -0
  34. data/lib/datastax_rails/consistency.rb +33 -0
  35. data/lib/datastax_rails/cql/base.rb +15 -0
  36. data/lib/datastax_rails/cql/column_family.rb +38 -0
  37. data/lib/datastax_rails/cql/consistency.rb +13 -0
  38. data/lib/datastax_rails/cql/create_column_family.rb +63 -0
  39. data/lib/datastax_rails/cql/create_keyspace.rb +30 -0
  40. data/lib/datastax_rails/cql/delete.rb +41 -0
  41. data/lib/datastax_rails/cql/drop_column_family.rb +13 -0
  42. data/lib/datastax_rails/cql/drop_keyspace.rb +13 -0
  43. data/lib/datastax_rails/cql/insert.rb +53 -0
  44. data/lib/datastax_rails/cql/select.rb +51 -0
  45. data/lib/datastax_rails/cql/truncate.rb +13 -0
  46. data/lib/datastax_rails/cql/update.rb +68 -0
  47. data/lib/datastax_rails/cql/use_keyspace.rb +13 -0
  48. data/lib/datastax_rails/cql.rb +25 -0
  49. data/lib/datastax_rails/cursor.rb +90 -0
  50. data/lib/datastax_rails/errors.rb +16 -0
  51. data/lib/datastax_rails/identity/abstract_key_factory.rb +26 -0
  52. data/lib/datastax_rails/identity/custom_key_factory.rb +36 -0
  53. data/lib/datastax_rails/identity/hashed_natural_key_factory.rb +10 -0
  54. data/lib/datastax_rails/identity/natural_key_factory.rb +37 -0
  55. data/lib/datastax_rails/identity/uuid_key_factory.rb +23 -0
  56. data/lib/datastax_rails/identity.rb +53 -0
  57. data/lib/datastax_rails/log_subscriber.rb +37 -0
  58. data/lib/datastax_rails/migrations/migration.rb +15 -0
  59. data/lib/datastax_rails/migrations.rb +36 -0
  60. data/lib/datastax_rails/mocking.rb +15 -0
  61. data/lib/datastax_rails/persistence.rb +133 -0
  62. data/lib/datastax_rails/railtie.rb +20 -0
  63. data/lib/datastax_rails/reflection.rb +472 -0
  64. data/lib/datastax_rails/relation/finder_methods.rb +184 -0
  65. data/lib/datastax_rails/relation/modification_methods.rb +80 -0
  66. data/lib/datastax_rails/relation/search_methods.rb +349 -0
  67. data/lib/datastax_rails/relation/spawn_methods.rb +107 -0
  68. data/lib/datastax_rails/relation.rb +393 -0
  69. data/lib/datastax_rails/schema/migration.rb +106 -0
  70. data/lib/datastax_rails/schema/migration_proxy.rb +25 -0
  71. data/lib/datastax_rails/schema/migrator.rb +212 -0
  72. data/lib/datastax_rails/schema.rb +37 -0
  73. data/lib/datastax_rails/scoping.rb +394 -0
  74. data/lib/datastax_rails/serialization.rb +6 -0
  75. data/lib/datastax_rails/tasks/column_family.rb +162 -0
  76. data/lib/datastax_rails/tasks/ds.rake +63 -0
  77. data/lib/datastax_rails/tasks/keyspace.rb +57 -0
  78. data/lib/datastax_rails/timestamps.rb +19 -0
  79. data/lib/datastax_rails/type.rb +16 -0
  80. data/lib/datastax_rails/types/array_type.rb +77 -0
  81. data/lib/datastax_rails/types/base_type.rb +26 -0
  82. data/lib/datastax_rails/types/binary_type.rb +15 -0
  83. data/lib/datastax_rails/types/boolean_type.rb +22 -0
  84. data/lib/datastax_rails/types/date_type.rb +17 -0
  85. data/lib/datastax_rails/types/float_type.rb +18 -0
  86. data/lib/datastax_rails/types/integer_type.rb +18 -0
  87. data/lib/datastax_rails/types/string_type.rb +16 -0
  88. data/lib/datastax_rails/types/text_type.rb +16 -0
  89. data/lib/datastax_rails/types/time_type.rb +17 -0
  90. data/lib/datastax_rails/types.rb +9 -0
  91. data/lib/datastax_rails/validations/uniqueness.rb +119 -0
  92. data/lib/datastax_rails/validations.rb +48 -0
  93. data/lib/datastax_rails/version.rb +3 -0
  94. data/lib/datastax_rails.rb +87 -0
  95. data/lib/solr_no_escape.rb +28 -0
  96. data/spec/datastax_rails/associations/belongs_to_association_spec.rb +7 -0
  97. data/spec/datastax_rails/associations/has_many_association_spec.rb +37 -0
  98. data/spec/datastax_rails/associations_spec.rb +22 -0
  99. data/spec/datastax_rails/attribute_methods_spec.rb +23 -0
  100. data/spec/datastax_rails/base_spec.rb +15 -0
  101. data/spec/datastax_rails/cql/select_spec.rb +12 -0
  102. data/spec/datastax_rails/cql/update_spec.rb +0 -0
  103. data/spec/datastax_rails/relation/finder_methods_spec.rb +54 -0
  104. data/spec/datastax_rails/relation/modification_methods_spec.rb +41 -0
  105. data/spec/datastax_rails/relation/search_methods_spec.rb +117 -0
  106. data/spec/datastax_rails/relation/spawn_methods_spec.rb +28 -0
  107. data/spec/datastax_rails/relation_spec.rb +130 -0
  108. data/spec/datastax_rails/validations/uniqueness_spec.rb +41 -0
  109. data/spec/datastax_rails_spec.rb +5 -0
  110. data/spec/dummy/Rakefile +8 -0
  111. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  112. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  113. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  114. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  115. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  116. data/spec/dummy/config/application.rb +47 -0
  117. data/spec/dummy/config/boot.rb +10 -0
  118. data/spec/dummy/config/database.yml +25 -0
  119. data/spec/dummy/config/datastax.yml +18 -0
  120. data/spec/dummy/config/environment.rb +5 -0
  121. data/spec/dummy/config/environments/development.rb +30 -0
  122. data/spec/dummy/config/environments/production.rb +60 -0
  123. data/spec/dummy/config/environments/test.rb +39 -0
  124. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  125. data/spec/dummy/config/initializers/inflections.rb +10 -0
  126. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  127. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  128. data/spec/dummy/config/initializers/session_store.rb +8 -0
  129. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  130. data/spec/dummy/config/locales/en.yml +5 -0
  131. data/spec/dummy/config/routes.rb +58 -0
  132. data/spec/dummy/config/sunspot.yml +17 -0
  133. data/spec/dummy/config.ru +4 -0
  134. data/spec/dummy/ks/migrate/20111117224534_models.rb +20 -0
  135. data/spec/dummy/ks/schema.json +180 -0
  136. data/spec/dummy/log/development.log +298 -0
  137. data/spec/dummy/log/production.log +0 -0
  138. data/spec/dummy/log/test.log +20307 -0
  139. data/spec/dummy/public/404.html +26 -0
  140. data/spec/dummy/public/422.html +26 -0
  141. data/spec/dummy/public/500.html +26 -0
  142. data/spec/dummy/public/favicon.ico +0 -0
  143. data/spec/dummy/script/rails +6 -0
  144. data/spec/spec.opts +5 -0
  145. data/spec/spec_helper.rb +29 -0
  146. data/spec/support/datastax_test_hook.rb +14 -0
  147. data/spec/support/models.rb +72 -0
  148. metadata +353 -0
@@ -0,0 +1,80 @@
1
+ module DatastaxRails
2
+ module ModificationMethods
3
+ # Destroys the records matching +conditions+ by instantiating each
4
+ # record and calling its +destroy+ method. Each object's callbacks are
5
+ # executed (including <tt>:dependent</tt> association options and
6
+ # +before_destroy+/+after_destroy+ Observer methods). Returns the
7
+ # collection of objects that were destroyed; each will be frozen, to
8
+ # reflect that no changes should be made (since they can't be
9
+ # persisted).
10
+ #
11
+ # Note: Instantiation, callback execution, and deletion of each
12
+ # record can be time consuming when you're removing many records at
13
+ # once. However, it is necessary to perform it this way to ensure
14
+ # that the SOLR index stays in sync with the Cassandra data store.
15
+ #
16
+ # +delete_all+ is aliased to this because you can't delete without running
17
+ # the requisite callbacks. (at least not yet)
18
+ #
19
+ # ==== Parameters
20
+ #
21
+ # * +conditions+ - A string, array, or hash that specifies which records
22
+ # to destroy. If omitted, all records matching the current relation are
23
+ # destroyed. See the Conditions section in the introduction to
24
+ # DatastaxRails::Base for more information.
25
+ #
26
+ # ==== Examples
27
+ #
28
+ # Person.destroy_all(:status => "inactive")
29
+ # Person.where(:age => 0..18).destroy_all
30
+ # Person.where_not(:status => "active").destroy_all
31
+ def destroy_all(conditions = nil)
32
+ if conditions
33
+ ret = where(conditions).destroy_all
34
+ else
35
+ ret = to_a.each {|object| object.destroy }
36
+ end
37
+ reset
38
+ ret
39
+ end
40
+ # TODO: Find a way to delete from both without instantiating
41
+ alias :delete_all :destroy_all
42
+
43
+ # Destroy an object (or multiple objects) that has the given id, the object is instantiated first,
44
+ # therefore all callbacks and filters are fired off before the object is deleted. This method is
45
+ # in-efficient since it actually has to instantiate the object just to delte it but allows cleanup
46
+ # methods such as the ones that remove the object from SOLR to be run.
47
+ #
48
+ # This essentially finds the object (or multiple objects) with the given id, creates a new object
49
+ # from the attributes, and then calls destroy on it.
50
+ #
51
+ # Note: this will only find objects that are matched by the current relation even if the ID would
52
+ # otherwise be valid.
53
+ #
54
+ # +delete+ is aliased to this because you can't delete without running
55
+ # the requisite callbacks. (at least not yet)
56
+ #
57
+ # ==== Parameters
58
+ #
59
+ # * +id+ - Can be either an Integer or an Array of Integers.
60
+ #
61
+ # ==== Examples
62
+ #
63
+ # # Destroy a single object
64
+ # Todo.destroy(1)
65
+ #
66
+ # # Destroy multiple objects
67
+ # todos = [1,2,3]
68
+ # Todo.destroy(todos)
69
+ def destroy(id)
70
+ if id.is_a?(Array)
71
+ ret = id.map { |one_id| destroy(one_id) }
72
+ else
73
+ ret = find(id).destroy
74
+ end
75
+ reset
76
+ ret
77
+ end
78
+ alias :delete :destroy
79
+ end
80
+ end
@@ -0,0 +1,349 @@
1
+ module DatastaxRails
2
+ module SearchMethods
3
+
4
+ # Normally special characters (other than wild cards) are escaped before the search
5
+ # is submitted. If you want to handle escaping yourself because you need to use
6
+ # those special characters, then just include this in your chain.
7
+ #
8
+ # Model.dont_escape.where("(some stuff I don\'t want escaped)")
9
+ #
10
+ # Note that fulltext searches are NEVER escaped. Use Relation.solr_escape if you
11
+ # want that done.
12
+ def dont_escape
13
+ clone.tap do |r|
14
+ r.escape_value = false
15
+ end
16
+ end
17
+
18
+ # Used to extend a scope with additional methods, either through
19
+ # a module or a block provided
20
+ #
21
+ # The object returned is a relation which can be further extended
22
+ def extending(*modules)
23
+ modules << Module.new(&Proc.new) if block_given?
24
+
25
+ return self if modules.empty?
26
+
27
+ clone.tap do |r|
28
+ r.send(:apply_modules, modules.flatten)
29
+ end
30
+ end
31
+
32
+ # Limit a single page to +value+ records
33
+ #
34
+ # Model.limit(1)
35
+ # Model.per_page(50)
36
+ #
37
+ # Normally DatastaxRails searches are paginated at a really high number
38
+ # so as to effectively disable pagination. However, you can cause
39
+ # all requests to be paginated on a per-model basis by overriding the
40
+ # +default_page_size+ class method in your model:
41
+ #
42
+ # class Model < DatastaxRails::Base
43
+ # def self.default_page_size
44
+ # 30
45
+ # end
46
+ # end
47
+ def limit(value)
48
+ clone.tap do |r|
49
+ r.per_page_value = value
50
+ end
51
+ end
52
+ alias :per_page :limit
53
+
54
+ # Sets the page number to retrieve
55
+ #
56
+ # Model.page(2)
57
+ def page(value)
58
+ clone.tap do |r|
59
+ r.page_value = value
60
+ end
61
+ end
62
+
63
+ # WillPaginate compatible method for paginating
64
+ #
65
+ # Model.paginate(:page => 2, :per_page => 10)
66
+ def paginate(options = {})
67
+ options = options.reverse_merge({:page => 1, :per_page => 30})
68
+ clone.tap do |r|
69
+ r.page_value = options[:page]
70
+ r.per_page_value = options[:per_page]
71
+ end
72
+ end
73
+
74
+ # Group results by one or more attributes only returning the top result
75
+ # for each group.
76
+ #
77
+ # Model.group(:program_id)
78
+ def group(*attrs)
79
+ return self if attrs.blank?
80
+
81
+ clone.tap do |r|
82
+ r.group_values += args.flatten
83
+ end
84
+ end
85
+
86
+ # Orders the result set by a particular attribute. Note that text fields
87
+ # may not be used for ordering as they are tokenized. Valid candidates
88
+ # are fields of type +string+, +integer+, +long+, +float+, +double+, and
89
+ # +time+. In addition, the symbol +:score+ can be used to sort on the
90
+ # relevance rating returned by Solr. The default direction is ascending
91
+ # but may be reversed by passing a hash where the field is the key and
92
+ # the value is :desc
93
+ #
94
+ # Model.order(:name)
95
+ # Model.order(:name => :desc)
96
+ def order(attribute)
97
+ return self if attribute.blank?
98
+
99
+ clone.tap do |r|
100
+ order_by = attribute.is_a?(Hash) ? attribute.dup : {attribute => :asc}
101
+
102
+ r.order_values << order_by
103
+ end
104
+ end
105
+
106
+ # Works in two unique ways.
107
+ #
108
+ # _First_: takes a block so it can be used just like Array#select.
109
+ #
110
+ # Model.scoped.select { |m| m.field == value }
111
+ #
112
+ # This will build an array of objects from the database for the scope,
113
+ # converting them into an array and iterating through them using Array#select.
114
+ #
115
+ # _Second_: Modifies the query so that only certain fields are retrieved:
116
+ #
117
+ # >> Model.select(:field)
118
+ # => [#<Model field:value>]
119
+ #
120
+ # Although in the above example it looks as though this method returns an
121
+ # array, it actually returns a relation object and can have other query
122
+ # methods appended to it, such as the other methods in DatastaxRails::SearchMethods.
123
+ #
124
+ # This method will also take multiple parameters:
125
+ #
126
+ # >> Model.select(:field, :other_field, :and_one_more)
127
+ # => [#<Model field: "value", other_field: "value", and_one_more: "value">]
128
+ #
129
+ # Any attributes that do not have fields retrieved by a select
130
+ # will return `nil` when the getter method for that attribute is used:
131
+ #
132
+ # >> Model.select(:field).first.other_field
133
+ # => nil
134
+ #
135
+ # The exception to this rule is when an attribute is lazy-loaded (e.g., binary).
136
+ # In that case, it is never retrieved until you call the getter method.
137
+ def select(value = Proc.new)
138
+ if block_given?
139
+ to_a.select {|*block_args| value.call(*block_args) }
140
+ else
141
+ clone.tap do |r|
142
+ r.select_values += Array.wrap(value)
143
+ end
144
+ end
145
+ end
146
+
147
+ # Reverses the order of the results
148
+ #
149
+ # Model.order(:name).reverse_order
150
+ # is equivalent to
151
+ # Model.order(:name => :desc)
152
+ #
153
+ # Model.order(:name).reverse_order.reverse_order
154
+ # is equivalent to
155
+ # Model.order(:name => :asc)
156
+ def reverse_order
157
+ clone.tap do |r|
158
+ r.reverse_order_value == !r.reverse_order_value
159
+ end
160
+ end
161
+
162
+ # By default, DatastaxRails uses the LuceneQueryParser. Note that this
163
+ # is a change from the underlying Sunspot gem. Sunspot defaults to the
164
+ # +disMax+ query parser. If you want to use that, then pass that in here.
165
+ #
166
+ # *This only applies to fulltext queries*
167
+ #
168
+ # Model.query_parser('disMax').fulltext("john smith")
169
+ def query_parser(attribute)
170
+ return self if attribute.blank?
171
+
172
+ clone.tap do |r|
173
+ r.query_parser_value = attribute
174
+ end
175
+ end
176
+
177
+ # By default, DatastaxRails will try to pick the right method of performing
178
+ # a search. You can use this method to force it to make the query via SOLR.
179
+ #
180
+ # NOTE that the time between when a record is placed into Cassandra and when
181
+ # it becomes available in SOLR is not guaranteed to be insignificant. It's
182
+ # very possible to insert a new record and not find it when immediately doing
183
+ # a SOLR search for it.
184
+ def with_solr
185
+ clone.tap do |r|
186
+ r.use_solr_value = true
187
+ end
188
+ end
189
+
190
+ # By default, DatastaxRails will try to pick the right method of performing
191
+ # a search. You can use this method to force it to make the query via
192
+ # cassandra.
193
+ #
194
+ # NOTE that this method assumes that you have all the proper secondary indexes
195
+ # in place before you attempt to use it. If not, you will get an error.
196
+ def with_cassandra
197
+ clone.tap do |r|
198
+ r.use_solr_value = false
199
+ end
200
+ end
201
+
202
+ # Specifies restrictions (scoping) on the result set. Expects a hash
203
+ # in the form +attribute => value+ for equality comparisons.
204
+ #
205
+ # Model.where(:group_id => '1234', :active => 'Y')
206
+ #
207
+ # The value of the comparison does not need to be a scalar. For example:
208
+ #
209
+ # Model.where(:name => ["Bob", "Tom", "Sally"])
210
+ # Model.where(:age => 18..65)
211
+ #
212
+ # Inequality comparisons such as greater_than and less_than are
213
+ # specified via chaining:
214
+ #
215
+ # Model.where(:created_at).greater_than(1.day.ago)
216
+ # Model.where(:age).less_than(65)
217
+ #
218
+ # NOTE: Due to the way SOLR handles range queries, all greater/less than
219
+ # queries are actually greater/less than or equal to queries.
220
+ # There is no way to perform a strictly greater/less than query.
221
+ def where(attribute)
222
+ return self if attribute.blank?
223
+
224
+ if attribute.is_a?(Symbol)
225
+ WhereProxy.new(self, attribute)
226
+ else
227
+ attributes = attribute.dup
228
+ attributes.each do |k,v|
229
+ attributes[k] = solr_format(v)
230
+ end
231
+ clone.tap do |r|
232
+ r.where_values << attributes
233
+ end
234
+ end
235
+ end
236
+
237
+ # Specifies restrictions (scoping) that should not match the result set.
238
+ # Expects a hash in the form +attribute => value+.
239
+ #
240
+ # Model.where_not(:group_id => '1234', :active => 'N')
241
+ #
242
+ # Passing an array will search for records where none of the array entries
243
+ # are present
244
+ #
245
+ # Model.where_not(:group_id => ['1234', '5678'])
246
+ #
247
+ # The above would find all models where group id is neither 1234 or 5678.
248
+ def where_not(attribute)
249
+ return self if attribute.blank?
250
+
251
+ attributes = []
252
+ attribute.each do |k,v|
253
+ if v.is_a?(Array)
254
+ v.each do |val|
255
+ attributes << {k => solr_format(val)}
256
+ end
257
+ else
258
+ attributes << {k => solr_format(v)}
259
+ end
260
+ end
261
+ clone.tap do |r|
262
+ r.where_not_values += attributes
263
+ end
264
+ end
265
+
266
+ # Specifies a full text search string to be processed by SOLR
267
+ #
268
+ # Model.fulltext("john smith")
269
+ #
270
+ # You can also pass in an options hash with the following options:
271
+ #
272
+ # * :fields => list of fields to search instead of the default of all fields
273
+ # * :highlight => List of fields to retrieve highlights for. Note that highlighted fields *must* be +:stored+
274
+ #
275
+ # Model.fulltext("john smith", :fields => [:title])
276
+ # Model.fulltext("john smith", :hightlight => [:body])
277
+ def fulltext(query, opts = {})
278
+ return self if query.blank?
279
+
280
+ opts[:query] = query
281
+
282
+ clone.tap do |r|
283
+ r.fulltext_values << opts
284
+ end
285
+ end
286
+
287
+ # See documentation for +where+
288
+ def less_than(value)
289
+ raise ArgumentError, "#less_than can only be called after an appropriate where call. e.g. where(:created_at).less_than(1.day.ago)"
290
+ end
291
+
292
+ # See documentation for +where+
293
+ def greater_than(value)
294
+ raise ArgumentError, "#greater_than can only be called after an appropriate where call. e.g. where(:created_at).greater_than(1.day.ago)"
295
+ end
296
+
297
+ def solr_format(value)
298
+ case
299
+ when value.is_a?(Date), value.is_a?(Time)
300
+ value.strftime('%Y-%m-%dT%H\:%M\:%SZ')
301
+ when value.is_a?(Array)
302
+ value.collect {|v| v.gsub(/ /,"\\ ") }.join(" OR ")
303
+ when value.is_a?(Fixnum)
304
+ value < 0 ? "\\#{value}" : value
305
+ when value.is_a?(String)
306
+ value.gsub(/ /,"\\ ")
307
+ else
308
+ value
309
+ end
310
+ end
311
+
312
+ protected
313
+ def find_by_attributes(match, attributes, *args) #:nodoc:
314
+ conditions = Hash[attributes.map {|a| [a, args[attributes.index(a)]]}]
315
+ result = where(conditions).send(match.finder)
316
+
317
+ if match.blank? && result.blank?
318
+ raise RecordNotFound, "Couldn't find #{klass.name} with #{conditions.to_a.collect {|p| p.join('=')}.join(', ')}"
319
+ else
320
+ yield(result) if block_given?
321
+ result
322
+ end
323
+ end
324
+
325
+ class WhereProxy #:nodoc:
326
+ def initialize(relation, attribute) #:nodoc:
327
+ @relation, @attribute = relation, attribute
328
+ end
329
+
330
+ def equal_to(value) #:nodoc:
331
+ @relation.clone.tap do |r|
332
+ r.where_values << {@attribute => r.solr_format(value)}
333
+ end
334
+ end
335
+
336
+ def greater_than(value) #:nodoc:
337
+ @relation.clone.tap do |r|
338
+ r.greater_than_values << {@attribute => r.solr_format(value)}
339
+ end
340
+ end
341
+
342
+ def less_than(value) #:nodoc:
343
+ @relation.clone.tap do |r|
344
+ r.less_than_values << {@attribute => r.solr_format(value)}
345
+ end
346
+ end
347
+ end
348
+ end
349
+ end
@@ -0,0 +1,107 @@
1
+ module DatastaxRails
2
+ module SpawnMethods
3
+ # def scoped #:nodoc:
4
+ # self
5
+ # end
6
+
7
+ def merge(r) #:nodoc:
8
+ return self unless r
9
+ return to_a & r if r.is_a?(Array)
10
+
11
+ merged_relation = clone
12
+
13
+ (Relation::MULTI_VALUE_METHODS - [:where, :where_not]).each do |method|
14
+ value = r.send(:"#{method}_values")
15
+ merged_relation.send(:"#{method}_values=", merged_relation.send(:"#{method}_values") + value) if value.present?
16
+ end
17
+
18
+ merged_wheres = {}
19
+ # This will merge all the where clauses into a single hash. If the same attribute is
20
+ # specified multiple times, the last one will win.
21
+ (@where_values + r.where_values).each { |w| merged_wheres.merge!(w)}
22
+
23
+ merged_relation.where_values = [merged_wheres] unless merged_wheres.empty?
24
+
25
+ merged_where_nots = {}
26
+ # This will merge all the where not clauses into a single hash. If the same attribute is
27
+ # specified multiple times, the last one will win.
28
+ (@where_not_values + r.where_not_values).each { |w| merged_where_nots.merge!(w)}
29
+
30
+ merged_relation.where_not_values = [merged_where_nots] unless merged_where_nots.empty?
31
+
32
+ (Relation::SINGLE_VALUE_METHODS).each do |method|
33
+ value = r.send(:"#{method}_value")
34
+ merged_relation.send(:"#{method}_value=", value) unless value.nil?
35
+ end
36
+
37
+ merged_relation
38
+ end
39
+
40
+ # Removes from the query the condition(s) specified in +skips+.
41
+ #
42
+ # Example:
43
+ #
44
+ # Post.where(:active => true).order('id').except(:order) # discards the order condition
45
+ # Post.where(:active => true).order('id').except(:where) # discards the where condition but keeps the order
46
+ def except(*skips)
47
+ result = self.class.new(@klass, table)
48
+ result.default_scoped = default_scoped
49
+
50
+ ((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) - skips).each do |method|
51
+ result.send(:"#{method}_values=", send(:"#{method}_values"))
52
+ end
53
+
54
+ (Relation::SINGLE_VALUE_METHODS - skips).each do |method|
55
+ result.send(:"#{method}_value=", send(:"#{method}_value"))
56
+ end
57
+
58
+ # Apply scope extension modules
59
+ result.send(:apply_modules, extensions)
60
+
61
+ result
62
+ end
63
+
64
+ # Removes any condition from the query other than the one(s) specified in +onlies+.
65
+ #
66
+ # Example:
67
+ #
68
+ # Post.order('id').only(:where) # discards the order condition
69
+ # Post.order('id').only(:where, :order) # uses the specified order
70
+ #
71
+ def only(*onlies)
72
+ result = self.class.new(@klass, table)
73
+ result.default_scoped = default_scoped
74
+
75
+ ((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) & onlies).each do |method|
76
+ result.send(:"#{method}_values=", send(:"#{method}_values"))
77
+ end
78
+
79
+ (Relation::SINGLE_VALUE_METHODS & onlies).each do |method|
80
+ result.send(:"#{method}_value=", send(:"#{method}_value"))
81
+ end
82
+
83
+ # Apply scope extension modules
84
+ result.send(:apply_modules, extensions)
85
+
86
+ result
87
+ end
88
+
89
+ VALID_FIND_OPTIONS = [:conditions, :limit, :offset, :order, :group, :page, :per_page]
90
+ def apply_finder_options(options) #:nodoc:
91
+ relation = clone
92
+ return relation unless options
93
+
94
+ options.assert_valid_keys(VALID_FIND_OPTIONS)
95
+ finders = options.dup
96
+ finders.delete_if { |key, value| value.nil? }
97
+
98
+ ([:group, :order, :limit, :offset, :page, :per_page] & finders.keys).each do |finder|
99
+ relation = relation.send(finder, finders[finder])
100
+ end
101
+
102
+ relation.where(finders[:conditions]) if options.has_key?(:conditions)
103
+
104
+ relation
105
+ end
106
+ end
107
+ end