Class: ModelSet
- Inherits:
-
Object
show all
- Includes:
- ActiveSupport::CoreExtensions::Array::Conversions, Enumerable
- Defined in:
- lib/model_set.rb,
lib/model_set/query.rb,
lib/model_set/raw_query.rb,
lib/model_set/set_query.rb,
lib/model_set/sql_query.rb,
lib/model_set/conditions.rb,
lib/model_set/solr_query.rb,
lib/model_set/conditioned.rb,
lib/model_set/sphinx_query.rb,
lib/model_set/raw_sql_query.rb,
lib/model_set/sql_base_query.rb
Defined Under Namespace
Modules: Conditioned
Classes: Conditions, Query, RawQuery, RawSQLQuery, SQLBaseQuery, SQLQuery, SetQuery, SolrQuery, SphinxQuery
Constant Summary
collapse
- MAX_CACHE_SIZE =
1000
- QUERY_TYPES =
{
:set => SetQuery,
:sql => SQLQuery,
:solr => SolrQuery,
:sphinx => SphinxQuery,
:raw => RawQuery,
}
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(query_or_models) ⇒ ModelSet
Returns a new instance of ModelSet.
28
29
30
31
32
33
34
35
36
37
38
|
# File 'lib/model_set.rb', line 28
def initialize(query_or_models)
if query_or_models.kind_of?(Query)
@query = query_or_models
elsif query_or_models.kind_of?(self.class)
self.ids = query_or_models.ids
@models_by_id = query_or_models.models_by_id
elsif query_or_models
self.ids = as_ids(query_or_models)
end
@created_at = Time.now
end
|
Instance Attribute Details
#created_at ⇒ Object
Returns the value of attribute created_at.
26
27
28
|
# File 'lib/model_set.rb', line 26
def created_at
@created_at
end
|
#query ⇒ Object
Returns the value of attribute query.
347
348
349
|
# File 'lib/model_set.rb', line 347
def query
@query
end
|
Class Method Details
.all ⇒ Object
503
504
505
|
# File 'lib/model_set.rb', line 503
def self.all
new(nil)
end
|
.as_id(model) ⇒ Object
487
488
489
490
491
492
493
494
495
496
497
|
# File 'lib/model_set.rb', line 487
def self.as_id(model)
id = model_class.as_id(model) if model_class.respond_to?(:as_id)
return id if id
case model
when model_class then model.send(id_field)
when ActiveRecord::Base then model.id
when String then model.split('-').last.to_i
else model.to_i
end
end
|
.as_ids(models) ⇒ Object
477
478
479
480
481
482
483
484
485
|
# File 'lib/model_set.rb', line 477
def self.as_ids(models)
return [] unless models
if models.kind_of?(self)
models.ids
else
models = [models] if not models.kind_of?(Enumerable)
models.collect {|model| as_id(model)}
end
end
|
.as_set(models) ⇒ Object
473
474
475
|
# File 'lib/model_set.rb', line 473
def self.as_set(models)
models.kind_of?(self) ? models : new(models)
end
|
.constructor(filter_name, opts = nil) ⇒ Object
523
524
525
526
527
528
529
530
531
532
|
# File 'lib/model_set.rb', line 523
def self.constructor(filter_name, opts = nil)
(class << self; self; end).module_eval do
define_method filter_name do |*args|
if opts
args.last.kind_of?(Hash) ? args.last.reverse_merge!(opts.clone) : args << opts.clone
end
self.all.send("#{filter_name}!", *args)
end
end
end
|
.empty ⇒ Object
499
500
501
|
# File 'lib/model_set.rb', line 499
def self.empty
new([])
end
|
.find(opts) ⇒ Object
507
508
509
510
511
512
513
514
515
|
# File 'lib/model_set.rb', line 507
def self.find(opts)
set = all
set.add_joins!(opts[:joins]) if opts[:joins]
set.add_conditions!(opts[:conditions]) if opts[:conditions]
set.order_by!(opts[:order]) if opts[:order]
set.limit!(opts[:limit], opts[:offset]) if opts[:limit]
set.page!(opts[:page]) if opts[:page]
set
end
|
.find_by_sql(sql) ⇒ Object
517
518
519
520
521
|
# File 'lib/model_set.rb', line 517
def self.find_by_sql(sql)
query = RawSQLQuery.new(self)
query.sql = sql
new(query)
end
|
.id_field(id_field = nil) ⇒ Object
570
571
572
573
574
575
576
|
# File 'lib/model_set.rb', line 570
def self.id_field(id_field = nil)
if id_field.nil?
@id_field ||= :id
else
@id_field = id_field
end
end
|
.id_field_with_prefix ⇒ Object
586
587
588
|
# File 'lib/model_set.rb', line 586
def self.id_field_with_prefix
self.id_field.is_a?(String) ? self.id_field : "#{self.table_name}.#{self.id_field}"
end
|
.id_type(id_type = nil) ⇒ Object
578
579
580
581
582
583
584
|
# File 'lib/model_set.rb', line 578
def self.id_type(id_type = nil)
if id_type.nil?
@id_type ||= :integer
else
@id_type = id_type.to_sym
end
end
|
.model_class(model_class = nil) ⇒ Object
By default the model class is the set class without the trailing “Set”. If you use a different model class you can call “model_class MyModel” in your set class.
536
537
538
539
540
541
542
543
544
|
# File 'lib/model_set.rb', line 536
def self.model_class(model_class = nil)
return ActiveRecord::Base if self == ModelSet
if model_class.nil?
@model_class ||= self.name.sub(/#{set_class_suffix}$/,'').constantize
else
@model_class = model_class
end
end
|
.model_name ⇒ Object
554
555
556
|
# File 'lib/model_set.rb', line 554
def self.model_name
model_class.name
end
|
.query_model_class(query_model_class = nil) ⇒ Object
546
547
548
549
550
551
552
|
# File 'lib/model_set.rb', line 546
def self.query_model_class(query_model_class = nil)
if query_model_class.nil?
@query_model_class ||= model_class
else
@query_model_class = query_model_class
end
end
|
.set_class_suffix ⇒ Object
558
559
560
|
# File 'lib/model_set.rb', line 558
def self.set_class_suffix
'Set'
end
|
.table_name(table_name = nil) ⇒ Object
562
563
564
565
566
567
568
|
# File 'lib/model_set.rb', line 562
def self.table_name(table_name = nil)
if table_name.nil?
@table_name ||= model_class.table_name
else
@table_name = table_name
end
end
|
Instance Method Details
#[](*args) ⇒ Object
Also known as:
slice
FIXME make work for nested offsets
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/model_set.rb', line 91
def [](*args)
case args.size
when 1
index = args[0]
if index.kind_of?(Range)
offset = index.begin
limit = index.end - index.begin
limit += 1 unless index.exclude_end?
self.limit(limit, offset)
else
by_id(ids[index])
end
when 2
offset, limit = args
self.limit(limit, offset)
else
raise ArgumentError.new("wrong number of arguments (#{args.size} for 1 or 2)")
end
end
|
#add_fields!(fields) ⇒ Object
420
421
422
423
424
425
426
|
# File 'lib/model_set.rb', line 420
def add_fields!(fields)
raise 'cannot use both add_fields and include_models' if @included_models
( @add_fields ||= {} ).merge!(fields)
self.clear_cache!
end
|
#aggregate(*args) ⇒ Object
438
439
440
441
|
# File 'lib/model_set.rb', line 438
def aggregate(*args)
anchor!(:sql)
query.aggregate(*args)
end
|
#anchor!(type = default_query_type, *args) ⇒ Object
357
358
359
360
361
362
363
364
|
# File 'lib/model_set.rb', line 357
def anchor!(type = default_query_type, *args)
return unless type
query_class = query_class(type)
if not query_type?(query_class)
self.query = query_class.new(self, *args)
end
self
end
|
#any? ⇒ Boolean
297
298
299
300
301
|
# File 'lib/model_set.rb', line 297
def any?
return super if block_given?
return false if query.nil?
size > 0
end
|
#by_id(id) ⇒ Object
84
85
86
87
88
|
# File 'lib/model_set.rb', line 84
def by_id(id)
return nil if id.nil?
fetch_models([id]) unless models_by_id[id]
models_by_id[id] || nil
end
|
#clear_cache! ⇒ Object
443
444
445
446
|
# File 'lib/model_set.rb', line 443
def clear_cache!
@models_by_id = nil
self
end
|
#clone_fields ⇒ Object
466
467
468
469
470
471
|
# File 'lib/model_set.rb', line 466
def clone_fields
@query = @query.clone if @query
@add_fields = @add_fields.clone if @add_fields
@included_models = @included_models.clone if @included_models
end
|
#count ⇒ Object
288
289
290
|
# File 'lib/model_set.rb', line 288
def count
query.count
end
|
#current_page ⇒ Object
307
308
309
|
# File 'lib/model_set.rb', line 307
def current_page query.page
end
|
#default_query_type ⇒ Object
373
374
375
|
# File 'lib/model_set.rb', line 373
def default_query_type
:sql
end
|
#each ⇒ Object
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
# File 'lib/model_set.rb', line 149
def each
num_models = ids.size
ids.each_slice(MAX_CACHE_SIZE) do |slice_ids|
clear_cache! if num_models > MAX_CACHE_SIZE
fetch_models(slice_ids)
slice_ids.each do |id|
model = models_by_id[id]
if model
yield model
else
( @missing_ids ||= [] ) << id
end
end
end
end
|
#each_slice(num = MAX_CACHE_SIZE) ⇒ Object
140
141
142
143
144
145
146
147
|
# File 'lib/model_set.rb', line 140
def each_slice(num=MAX_CACHE_SIZE)
ids.each_slice(num) do |slice_ids|
set = self.clone
set.ids = slice_ids
set.clear_cache!
yield set
end
end
|
#each_with_index ⇒ Object
166
167
168
169
170
171
172
|
# File 'lib/model_set.rb', line 166
def each_with_index
i = per_page ? (current_page - 1) * per_page : 0
each do |model|
yield(model, i)
i += 1
end
end
|
#empty! ⇒ Object
323
324
325
326
|
# File 'lib/model_set.rb', line 323
def empty!
self.ids = []
self
end
|
#empty? ⇒ Boolean
303
304
305
|
# File 'lib/model_set.rb', line 303
def empty?
not any?
end
|
413
414
415
416
417
418
|
# File 'lib/model_set.rb', line 413
def (key, args)
opts = args.last.kind_of?(Hash) ? args.pop : {}
opt = opts.delete(key)
args << opts unless opts.empty?
opt
end
|
#first(limit = nil) ⇒ Object
112
113
114
115
116
117
118
|
# File 'lib/model_set.rb', line 112
def first(limit=nil)
if limit
self.limit(limit)
else
self[0]
end
end
|
#ids ⇒ Object
44
45
46
|
# File 'lib/model_set.rb', line 44
def ids
model_ids.to_a
end
|
#ids=(model_ids) ⇒ Object
328
329
330
331
332
333
|
# File 'lib/model_set.rb', line 328
def ids=(model_ids)
model_ids = model_ids.collect {|id| id.to_i}
self.query = SetQuery.new(self.class)
query.add!(model_ids)
self
end
|
#in_groups_of(num) ⇒ Object
132
133
134
135
136
137
138
|
# File 'lib/model_set.rb', line 132
def in_groups_of(num)
each_slice(num) do |slice_set|
slice = slice_set.to_a
slice[num-1] = nil if slice.size < num
yield slice
end
end
|
#include?(model) ⇒ Boolean
79
80
81
82
|
# File 'lib/model_set.rb', line 79
def include?(model)
model_id = as_id(model)
model_ids.include?(model_id)
end
|
#include_models!(*models) ⇒ Object
428
429
430
431
432
433
434
435
436
|
# File 'lib/model_set.rb', line 428
def include_models!(*models)
raise 'cannot use both add_fields and include_models' if @add_fields
( @included_models ||= [] ).concat(models)
self.clear_cache!
end
|
#last(limit = nil) ⇒ Object
120
121
122
123
124
125
126
|
# File 'lib/model_set.rb', line 120
def last(limit=nil)
if limit
self.limit(limit, size - limit)
else
self[-1]
end
end
|
#lazy_limit!(limit, fetch = limit * 10) ⇒ Object
409
410
411
|
# File 'lib/model_set.rb', line 409
def lazy_limit!(limit, fetch = limit * 10)
anchor!(:sql, :limit_fetch => fetch).limit!(limit)
end
|
#marshal_dump ⇒ Object
597
598
599
|
# File 'lib/model_set.rb', line 597
def marshal_dump
[ @query, @add_fields, @included_models, @created_at ]
end
|
#marshal_load(fields) ⇒ Object
601
602
603
|
# File 'lib/model_set.rb', line 601
def marshal_load(fields)
@query, @add_fields, @included_models, @created_at = fields
end
|
#merge_cache!(other) ⇒ Object
448
449
450
451
452
|
# File 'lib/model_set.rb', line 448
def merge_cache!(other)
other_cache = other.models_by_id
models_by_id.merge!(other_cache)
self
end
|
#missing_ids ⇒ Object
48
49
50
|
# File 'lib/model_set.rb', line 48
def missing_ids
( @missing_ids || [] ).uniq
end
|
#older_than?(duration) ⇒ Boolean
40
41
42
|
# File 'lib/model_set.rb', line 40
def older_than?(duration)
created_at.nil? or created_at < Time.now - duration
end
|
#partition_by(filter) ⇒ Object
276
277
278
279
280
281
282
283
284
285
286
|
# File 'lib/model_set.rb', line 276
def partition_by(filter)
filter = filter.to_s
filter[-1] = '' if filter =~ /\!$/
positive = self.send(filter)
negative = self - positive
if block_given?
yield(positive, negative)
else
[positive, negative]
end
end
|
#per_page ⇒ Object
311
312
313
|
# File 'lib/model_set.rb', line 311
def per_page query.limit
end
|
#query_class(type = query.class) ⇒ Object
349
350
351
|
# File 'lib/model_set.rb', line 349
def query_class(type = query.class)
type.kind_of?(Symbol) ? QUERY_TYPES[type] : type
end
|
#query_type?(type) ⇒ Boolean
353
354
355
|
# File 'lib/model_set.rb', line 353
def query_type?(type)
query_class(type) == query_class
end
|
#reanchor!(type = default_query_type, *args) ⇒ Object
366
367
368
369
370
371
|
# File 'lib/model_set.rb', line 366
def reanchor!(type = default_query_type, *args)
return unless type
self.query = query_class(type).new(self, *args)
self
end
|
#reject(&block) ⇒ Object
174
175
176
|
# File 'lib/model_set.rb', line 174
def reject(&block)
self.clone.reject!(&block)
end
|
#reject! ⇒ Object
178
179
180
181
182
183
184
185
|
# File 'lib/model_set.rb', line 178
def reject!
filtered_ids = []
self.each do |model|
filtered_ids << model.send(id_field) unless yield model
end
self.ids = filtered_ids
self
end
|
#reject_ids(&block) ⇒ Object
203
204
205
|
# File 'lib/model_set.rb', line 203
def reject_ids(&block)
self.clone.select_ids!(&block)
end
|
#reject_ids! ⇒ Object
207
208
209
210
211
212
|
# File 'lib/model_set.rb', line 207
def reject_ids!
self.ids = ids.select do |id|
not yield id
end
self
end
|
#reject_raw(&block) ⇒ Object
225
226
227
|
# File 'lib/model_set.rb', line 225
def reject_raw(&block)
self.clone.reject_raw!(&block)
end
|
#reject_raw!(&block) ⇒ Object
229
230
231
232
233
|
# File 'lib/model_set.rb', line 229
def reject_raw!(&block)
anchor!(:raw)
query.reject!(&block)
self
end
|
#second ⇒ Object
128
129
130
|
# File 'lib/model_set.rb', line 128
def second
self[1]
end
|
#select(limit = nil, &block) ⇒ Object
187
188
189
|
# File 'lib/model_set.rb', line 187
def select(limit = nil, &block)
self.clone.select!(limit, &block)
end
|
#select!(limit = nil) ⇒ Object
191
192
193
194
195
196
197
198
199
200
201
|
# File 'lib/model_set.rb', line 191
def select!(limit = nil)
filtered_ids = []
self.each do |model|
if yield model
filtered_ids << model.send(id_field)
break if filtered_ids.size == limit
end
end
self.ids = filtered_ids
self
end
|
#select_ids(&block) ⇒ Object
214
215
216
|
# File 'lib/model_set.rb', line 214
def select_ids(&block)
self.clone.select_ids!(&block)
end
|
#select_ids! ⇒ Object
218
219
220
221
222
223
|
# File 'lib/model_set.rb', line 218
def select_ids!
self.ids = ids.select do |id|
yield id
end
self
end
|
#select_raw(&block) ⇒ Object
235
236
237
|
# File 'lib/model_set.rb', line 235
def select_raw(&block)
self.clone.select_raw!(&block)
end
|
#select_raw!(&block) ⇒ Object
239
240
241
242
243
|
# File 'lib/model_set.rb', line 239
def select_raw!(&block)
anchor!(:raw)
query.select!(&block)
self
end
|
#shuffle! ⇒ Object
73
74
75
76
77
|
# File 'lib/model_set.rb', line 73
def shuffle!
reanchor!(:set)
query.shuffle!
self
end
|
#size ⇒ Object
Also known as:
length
292
293
294
|
# File 'lib/model_set.rb', line 292
def size
query.size
end
|
#sort(&block) ⇒ Object
255
256
257
|
# File 'lib/model_set.rb', line 255
def sort(&block)
self.clone.sort!(&block)
end
|
#sort!(&block) ⇒ Object
259
260
261
262
263
264
|
# File 'lib/model_set.rb', line 259
def sort!(&block)
block ||= lambda {|a,b| a <=> b}
sorted_ids = to_a.sort(&block).collect {|m| m.id}
reorder!(sorted_ids)
self
end
|
#sort_by(&block) ⇒ Object
266
267
268
|
# File 'lib/model_set.rb', line 266
def sort_by(&block)
self.clone.sort_by!(&block)
end
|
#sort_by!(&block) ⇒ Object
270
271
272
273
274
|
# File 'lib/model_set.rb', line 270
def sort_by!(&block)
sorted_ids = to_a.sort_by(&block).collect {|m| m.id}
reorder!(sorted_ids)
self
end
|
#sort_by_raw(&block) ⇒ Object
245
246
247
|
# File 'lib/model_set.rb', line 245
def sort_by_raw(&block)
self.clone.sort_by_raw!(&block)
end
|
#sort_by_raw!(&block) ⇒ Object
249
250
251
252
253
|
# File 'lib/model_set.rb', line 249
def sort_by_raw!(&block)
anchor!(:raw)
query.sort_by!(&block)
self
end
|
#sync ⇒ Object
454
455
456
457
|
# File 'lib/model_set.rb', line 454
def sync
ids
self
end
|
#sync_models ⇒ Object
459
460
461
462
463
464
|
# File 'lib/model_set.rb', line 459
def sync_models
if size <= MAX_CACHE_SIZE
fetch_models(model_ids)
end
self
end
|
#to_conditions(*args) ⇒ Object
388
389
390
391
|
# File 'lib/model_set.rb', line 388
def to_conditions(*args)
anchor!( (:query_type, args) || default_query_type )
query.to_conditions(*args)
end
|
#total_entries ⇒ Object
315
316
317
|
# File 'lib/model_set.rb', line 315
def total_entries query.count
end
|
#total_pages ⇒ Object
319
320
321
|
# File 'lib/model_set.rb', line 319
def total_pages query.pages
end
|