activerecord-collections 0.0.23 → 0.0.24

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 192790cbc51085d35ee324b7c2e61936c56285ed
4
- data.tar.gz: 500efab14683ba051367ea4bcfa72757e8ba4761
3
+ metadata.gz: f6a1d8087898abadc4007581ab714424b15e797d
4
+ data.tar.gz: 4bd38a8e29b7e491e37b9337b7ee88d6c61042a0
5
5
  SHA512:
6
- metadata.gz: 8cc2ca473a2f4d6ccee65824c69940ace08445dfdb4ff36b174f3fbbd591f153d5d3eebe72ec6bf3cb532aa51fcaac2522034342b313d00ea1a5c30d6a615076
7
- data.tar.gz: 1f71fdfa21ecc5ab76419307eb2a23301d26cef231fbe08618c5d29e36f8bb09035eb27877b8b8ab637b120f7142d7e1611814c3cd5bfe99a6fdf32c64009b06
6
+ metadata.gz: 7a3a224370a7e042c1d1a184db1e38b70e0c93cd1614b1a5ad090d04b585218c9c2bd3a52e553f1432186a558cddcca062a2d119baa34e16e1df62c57090d921
7
+ data.tar.gz: 39574217740a6c075d46f413232d50020bdeb17a35c2ec88d0a03a0bd3710ce1ddfce0cf7d0bc03c241600e2bad99a0101b08f8c7347d583106165724c87cc72
@@ -12,30 +12,41 @@ module ActiveRecord
12
12
  COLLECTIONS = []
13
13
 
14
14
  class << self
15
- attr_reader :collections
16
15
  def inherited(subclass)
17
- ActiveRecord::Collection::COLLECTIONS << subclass
16
+ ActiveRecord::Collection::COLLECTIONS << subclass.name unless ActiveRecord::Collection::COLLECTIONS.include?(subclass.name)
17
+ # if parent class is not Collection, register the collectable on the class as the closest parent's collectable
18
+ end
19
+
20
+ def collections
21
+ ActiveRecord::Collection::COLLECTIONS.map(&:constantize)
18
22
  end
19
23
 
20
24
  def collectable(klass=nil)
21
25
  unless klass.nil?
22
26
  raise ArgumentError, "The collection model must inherit from ActiveRecord::Base" unless klass.ancestors.include?(ActiveRecord::Base)
23
- ActiveRecord::Collection::COLLECTABLES[name] ||= klass
27
+ ActiveRecord::Collection::COLLECTABLES[name] ||= klass.name
24
28
  end
25
29
 
26
30
  if ActiveRecord::Collection::COLLECTABLES[name].nil?
27
- begin
28
- klass = self.name.demodulize.singularize.constantize
29
- ActiveRecord::Collection::COLLECTABLES[name] = klass if !klass.nil? && klass.ancestors.include?(ActiveRecord::Base)
30
- rescue
31
- # singularized class doesn't exist
32
- end
31
+ klass = infer_collectable
32
+ ActiveRecord::Collection::COLLECTABLES[name] = klass.name if !klass.nil? && klass.ancestors.include?(ActiveRecord::Base)
33
33
  end
34
34
 
35
35
  raise "Unable to determine a model to use for your collection, please set one with the `collectable` class method" if ActiveRecord::Collection::COLLECTABLES[name].nil? # TODO implement real exceptions
36
- ActiveRecord::Collection::COLLECTABLES[name]
36
+
37
+ ActiveRecord::Collection::COLLECTABLES[name].constantize
37
38
  end
38
39
  alias_method :model, :collectable
40
+
41
+ def infer_collectable(klass=self)
42
+ singular = klass.name.demodulize.singularize
43
+ raise "Cannot infer collectable from singular collection" if singular == klass.name.demodulize
44
+ singular.constantize
45
+ rescue
46
+ parent = klass.ancestors[1]
47
+ return nil if parent.name == 'ActiveRecord::Collection'
48
+ parent.try(:collectable) || infer_collectable(parent)
49
+ end
39
50
  end
40
51
 
41
52
  def collectable
@@ -24,7 +24,13 @@ module ActiveRecord
24
24
  collection.includes!(*hash[:includes]) unless hash[:includes].empty?
25
25
 
26
26
  wheres = hash[:where].partition { |w| w.is_a?(Hash) }
27
- wheres.first.each { |wh| collection.where!(wh) }
27
+ wheres.first.each do |wh|
28
+ if wh.keys.first == :not
29
+ collection.not!(wh[:not])
30
+ else
31
+ collection.where!(wh)
32
+ end
33
+ end
28
34
  collection.where!(*hash[:bind].map { |b| b[:value] }.unshift(wheres.last.join(" AND ").gsub(/\$\d/,'?'))) unless wheres.last.empty?
29
35
 
30
36
  collection.group!(hash[:group]) unless hash[:group].empty?
@@ -123,6 +123,9 @@ module ActiveRecord
123
123
  serialize_node(node.expr)
124
124
  when Arel::Nodes::And
125
125
  node.children.map { |child| serialize_node(child) }
126
+ when Arel::Nodes::NotEqual
127
+ bound = bind.delete_at(bind.find_index { |b| b[:name] == node.left.name.to_s })[:value]
128
+ {not: {node.left.name.to_sym => bound}}
126
129
  when Arel::Nodes::Or
127
130
  {or: [serialize_node(node.left), serialize_node(node.right)]}
128
131
  else
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Collections
3
- VERSION = '0.0.23'
3
+ VERSION = '0.0.24'
4
4
  end
5
5
  end
@@ -2,36 +2,95 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.describe ActiveRecord::Collection do
4
4
  context 'querying' do
5
- before(:each) { create(:retailer) }
5
+ before(:each) { 5.times { create(:retailer) } }
6
6
 
7
- it 'should return the same records as a standard relation' do
7
+ it 'returns the same records as a standard relation' do
8
8
  retailer = Retailer.all.to_a.sample
9
9
  collection = StockedProducts.where(retailer_id: retailer.id)
10
10
  relation = StockedProduct.where(retailer_id: retailer.id)
11
11
  expect(collection.count).to eql(relation.count)
12
12
  expect(collection.pluck(:id).sort).to eql(relation.pluck(:id).sort)
13
13
  end
14
+
15
+ describe 'not' do
16
+ it 'excludes records matching the criteria' do
17
+ retailer = Retailer.all.to_a.sample
18
+ collection = StockedProducts.not(retailer_id: retailer.id)
19
+ relation = StockedProduct.where.not(retailer_id: retailer.id)
20
+ expect(collection.count).to eql(relation.count)
21
+ expect(collection.pluck(:id).sort).to eql(relation.pluck(:id).sort)
22
+ end
23
+ end
24
+
25
+ describe 'to_collection' do
26
+ it 'reproduces the same result set' do
27
+ retailer = Retailer.all.to_a.sample
28
+ product = retailer.stocked_products.sample.product
29
+ relation = StockedProduct.where.not(retailer_id: retailer.id)
30
+ collection = StockedProduct.where.not(retailer_id: retailer.id).to_collection
31
+ expect(collection.count).to eql(relation.count)
32
+ expect(collection.pluck(:id).sort).to eql(relation.pluck(:id).sort)
33
+ end
34
+
35
+ it 'supports multiple parameters' do
36
+ retailer = Retailer.all.to_a.sample
37
+ product = retailer.stocked_products.sample.product
38
+ relation = StockedProduct.where.not(retailer_id: retailer.id, product_id: product.id)
39
+ collection = StockedProduct.where.not(retailer_id: retailer.id, product_id: product.id).to_collection
40
+ expect(collection.count).to eql(relation.count)
41
+ expect(collection.pluck(:id).sort).to eql(relation.pluck(:id).sort)
42
+ end
43
+ end
14
44
  end
15
45
 
16
46
  context 'batching' do
17
47
  describe 'default_batch_size' do
18
- it 'should default to 500' do
48
+ it 'defaults to 500' do
19
49
  expect(ActiveRecord::Collection.default_batch_size).to eql(500)
20
50
  end
21
51
 
22
- it 'should be overridable by extending classes' do
52
+ it 'is overridable by extending classes' do
23
53
  expect(StockedProducts.default_batch_size).to eql(200)
24
54
  end
25
55
  end
26
56
 
27
57
  describe 'batching_threshold' do
28
- it 'should default to 0' do
58
+ it 'defaults to 0' do
29
59
  expect(ActiveRecord::Collection.batching_threshold).to eql(0)
30
60
  end
31
61
 
32
- it 'should be overridable by extending classes' do
62
+ it 'is overridable by extending classes' do
33
63
  expect(StockedProducts.batching_threshold).to eql(500)
34
64
  end
35
65
  end
36
66
  end
67
+
68
+ context 'subclassing' do
69
+ it 'infers the collectable from the class name' do
70
+ expect(Retailers.collectable).to eql(Retailer)
71
+ end
72
+
73
+ it 'allows setting a collectable' do
74
+ expect(ProductCollection.collectable).to eql(Product)
75
+ end
76
+
77
+ context 'multiple collections for the same model' do
78
+ it 'registers all of them as collections for the model' do
79
+ expect(ActiveRecord::Collection::COLLECTABLES[StockedProducts.name]).to eql('StockedProduct')
80
+ expect(ActiveRecord::Collection::COLLECTABLES[StockedProductCollection.name]).to eql('StockedProduct')
81
+ end
82
+ end
83
+
84
+ context 'a subclass' do
85
+ it 'registers itself as a collection' do
86
+ expect(ActiveRecord::Collection.collections).to include(ProductCollection)
87
+ expect(ActiveRecord::Collection.collections).to include(AnotherProductCollection)
88
+ end
89
+
90
+ it 'inherits the parent collectable' do
91
+ expect(AnotherProductCollection.collectable).to eql(Product)
92
+ expect(MoreRetailers.collectable).to eql(Retailer)
93
+ end
94
+ end
95
+ end
37
96
  end
@@ -21,3 +21,20 @@ class StockedProducts < ActiveRecord::Collection
21
21
  default_batch_size 200
22
22
  batching_threshold 500
23
23
  end
24
+
25
+ class StockedProductCollection < ActiveRecord::Collection
26
+ collectable StockedProduct
27
+ end
28
+
29
+ class ProductCollection < ActiveRecord::Collection
30
+ collectable Product
31
+ end
32
+
33
+ class AnotherProductCollection < ProductCollection
34
+ end
35
+
36
+ class Retailers < ActiveRecord::Collection
37
+ end
38
+
39
+ class MoreRetailers < Retailers
40
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-collections
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.23
4
+ version: 0.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Rebec
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-22 00:00:00.000000000 Z
11
+ date: 2015-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord