better_ar 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/HISTORY.txt CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.0.7
2
+ Added support for association collections
3
+ Moved ActiveRecord::Relation included methods into proper modules
4
+
1
5
  ## 0.0.6
2
6
  Moved methods as higher level module in ActiveRecord::Relation than ActiveRecord::FinderMethods. So the BetterAR modules take precedence.
3
7
 
data/README.markdown CHANGED
@@ -23,6 +23,14 @@ is the same as
23
23
 
24
24
  User.joins(:records).where(:age => 10, :records => {:name => 'test'}).limit(5).offset(10).order(:name)
25
25
 
26
+ It also works on association collections:
27
+
28
+ User.first.records.all(:level => 2, :limit! => 5, :offset! => 10, :order! => :name, :reports => {:name => 'test'})
29
+
30
+ This would be the same as:
31
+
32
+ User.first.records.joins(:reports).where(:level => 2, :reports => {:name => 'test'}).limit(5).offset(10).order(:name)
33
+
26
34
  While this may seem less concise the advantage is being able to dynamically construct the query with a single hash in code.
27
35
 
28
36
  ### Legacy
data/better_ar.gemspec CHANGED
@@ -20,6 +20,4 @@ Gem::Specification.new do |s|
20
20
  s.require_paths = ["lib"]
21
21
 
22
22
  s.add_development_dependency 'activerecord', ['~> 3.0.3']
23
- # s.add_development_dependency 'mocha'
24
- # s.add_development_dependency 'yard'
25
23
  end
data/lib/better_ar.rb CHANGED
@@ -1,107 +1,5 @@
1
- module BetterAr
1
+ module BetterAr; end
2
2
 
3
- # Breaks down the hash to do a {ActiveRecord::Relation} query
4
- #
5
- # example:
6
- # User.all(:age => 10, :limit! => 2, :offset! => 3, :order! => :name)
7
- #
8
- # is the same as:
9
- # User.where(:age => 10).limit(2).offset(3).order(:name)
10
- #
11
- # if the key :conditions is present it will fall back to legacy
12
- #
13
- # any key with the '!' at the end will be assumed to be a sql operator. The key should match either an {ActiveRecord::Relation} instance method or an ARel predicate.
14
- #
15
- # Implicit joins are supported.
16
- # example:
17
- # User.all(:records => {:name => 'test'})
18
- #
19
- # is the same as:
20
- # User.joins(:records).where(:records => {:name => 'test'})
21
- #
22
- # @param [Hash]
23
- # Optional
24
- # @return [ActiveRecord::Relation]
25
- def all(opts = {})
26
- if opts.empty?
27
- super()
28
- elsif opts.key?(:conditions)
29
- super(opts)
30
- else
31
- relation = clone
32
-
33
- unless opts.key?(:conditions)
34
- unless opts.empty?
35
- opts.keys.select { |key| key.to_s =~ /!$/ }.each do |predicate|
36
- if value = opts.delete(predicate)
37
- relation = relation.send(predicate.to_s.sub('!',''), value)
38
- end
39
- end
40
-
41
- reflect_on_all_associations.map(&:name).each do |name|
42
- if opts.key?(name)
43
- relation = relation.joins(name)
44
- end
45
- end
46
-
47
- relation.where(opts)
48
- end
49
-
50
- if opts.empty?
51
- relation
52
- else
53
- relation.where(opts)
54
- end
55
- end
56
- end
57
- end
58
-
59
- # Forces a limit of 1 on the collection
60
- #
61
- # example:
62
- # User.first(:age => 10, :name => 'Brian')
63
- #
64
- # is the same as:
65
- # User.where(:age => 10, :name => 'Brian').limit(1).first
66
- #
67
- # if the key :conditions is present it will fall back to legacy
68
- #
69
- # @param [Hash]
70
- # Optional follows same convention as {#all}
71
- # @return [ActiveRecord::Base]
72
- def first(opts = {})
73
- if opts.empty?
74
- super()
75
- elsif opts.key?(:conditions)
76
- super(opts)
77
- else
78
- all(opts.merge(:limit! => 1)).first
79
- end
80
- end
81
-
82
- # Does a count on the query
83
- #
84
- # example:
85
- # User.count(:age => 20)
86
- #
87
- # is the same as:
88
- # User.where(:age => 20).count
89
- #
90
- # if the key :conditions is present it will fall back to legacy
91
- #
92
- # @param [Hash]
93
- # Optional follows same convention as {#all}
94
- # @return [Integer]
95
- def count(opts = {})
96
- if opts.empty?
97
- super()
98
- elsif opts.key?(:conditions)
99
- super(opts)
100
- else
101
- all(opts).count
102
- end
103
- end
104
-
105
- end
106
-
107
- ActiveRecord::Relation.send(:include, BetterAr)
3
+ require 'better_ar/finder_methods'
4
+ require 'better_ar/calculations'
5
+ require 'better_ar/association_collection'
@@ -0,0 +1,49 @@
1
+ module BetterAr
2
+ module AssociationCollection
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+ alias_method_chain :first, :better_ar
7
+ alias_method_chain :count, :better_ar
8
+ end
9
+ end
10
+
11
+ # Allows for the same interface as {BetterAr::Relation#first} on association collections
12
+ #
13
+ # example:
14
+ # User.first.records.first(:level => 2, :order! => :name)
15
+ #
16
+ # @param [Hash]
17
+ # Optional
18
+ # @returns [ActiveRecord::Base]
19
+ def first_with_better_ar(opts = {})
20
+ if opts.empty?
21
+ first_without_better_ar
22
+ elsif opts.key?(:conditions)
23
+ first_without_better_ar(opts)
24
+ else
25
+ scoped.first(opts)
26
+ end
27
+ end
28
+
29
+ # Allows for the same interface as {BetterAr::Relation#count} on association collections
30
+ #
31
+ # example:
32
+ # User.first.records.count(:level => 2)
33
+ #
34
+ # @param [Hash]
35
+ # Optional
36
+ # @returns [Integer]
37
+ def count_with_better_ar(opts = {})
38
+ if opts.empty?
39
+ count_without_better_ar
40
+ elsif opts.key?(:conditions)
41
+ count_without_better_ar(opts)
42
+ else
43
+ scoped.count(opts)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ ActiveRecord::Associations::AssociationCollection.send(:include, BetterAr::AssociationCollection)
@@ -0,0 +1,28 @@
1
+ module BetterAr
2
+ module Calculations
3
+ # Does a count on the query
4
+ #
5
+ # example:
6
+ # User.count(:age => 20)
7
+ #
8
+ # is the same as:
9
+ # User.where(:age => 20).count
10
+ #
11
+ # if the key :conditions is present it will fall back to legacy
12
+ #
13
+ # @param [Hash]
14
+ # Optional follows same convention as {#all}
15
+ # @return [Integer]
16
+ def count(opts = {}, extra = {})
17
+ if opts.nil? || opts.empty?
18
+ super(nil, extra)
19
+ elsif opts.key?(:conditions)
20
+ super(opts, extra)
21
+ else
22
+ all(opts).count
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ ActiveRecord::Relation.send(:include, BetterAr::Calculations)
@@ -0,0 +1,84 @@
1
+ module BetterAr
2
+ module FinderMethods
3
+ # Breaks down the hash to do a {ActiveRecord::Relation} query
4
+ #
5
+ # example:
6
+ # User.all(:age => 10, :limit! => 2, :offset! => 3, :order! => :name)
7
+ #
8
+ # is the same as:
9
+ # User.where(:age => 10).limit(2).offset(3).order(:name)
10
+ #
11
+ # if the key :conditions is present it will fall back to legacy
12
+ #
13
+ # any key with the '!' at the end will be assumed to be a sql operator. The key should match either an {ActiveRecord::Relation} instance method or an ARel predicate.
14
+ #
15
+ # Implicit joins are supported.
16
+ # example:
17
+ # User.all(:records => {:name => 'test'})
18
+ #
19
+ # is the same as:
20
+ # User.joins(:records).where(:records => {:name => 'test'})
21
+ #
22
+ # @param [Hash]
23
+ # Optional
24
+ # @return [ActiveRecord::Relation]
25
+ def all(opts = {})
26
+ if opts.empty?
27
+ super()
28
+ elsif opts.key?(:conditions)
29
+ super(opts)
30
+ else
31
+ relation = clone
32
+
33
+ unless opts.key?(:conditions)
34
+ unless opts.empty?
35
+ opts.keys.select { |key| key.to_s =~ /!$/ }.each do |predicate|
36
+ if value = opts.delete(predicate)
37
+ relation = relation.send(predicate.to_s.sub('!',''), value)
38
+ end
39
+ end
40
+
41
+ reflect_on_all_associations.map(&:name).each do |name|
42
+ if opts.key?(name)
43
+ relation = relation.joins(name)
44
+ end
45
+ end
46
+
47
+ relation.where(opts)
48
+ end
49
+
50
+ if opts.empty?
51
+ relation
52
+ else
53
+ relation.where(opts)
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ # Forces a limit of 1 on the collection
60
+ #
61
+ # example:
62
+ # User.first(:age => 10, :name => 'Brian')
63
+ #
64
+ # is the same as:
65
+ # User.where(:age => 10, :name => 'Brian').limit(1).first
66
+ #
67
+ # if the key :conditions is present it will fall back to legacy
68
+ #
69
+ # @param [Hash]
70
+ # Optional follows same convention as {#all}
71
+ # @return [ActiveRecord::Base]
72
+ def first(opts = {})
73
+ if opts.empty?
74
+ super()
75
+ elsif opts.key?(:conditions)
76
+ super(opts)
77
+ else
78
+ all(opts.merge(:limit! => 1)).first
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ ActiveRecord::Relation.send(:include, BetterAr::FinderMethods)
@@ -1,3 +1,3 @@
1
1
  module BetterAr
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
data/test/helper.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'ruby-debug'
3
3
  require 'minitest/autorun'
4
- # require 'mocha'
5
4
  require 'active_support/core_ext'
6
5
  require 'active_record'
7
6
  require 'better_ar'
@@ -19,8 +18,10 @@ ActiveRecord::Base.establish_connection(
19
18
 
20
19
  users_table = %{CREATE TABLE users (id INTEGER PRIMARY KEY, age INTEGER, name TEXT);}
21
20
  records_table = %{CREATE TABLE records (id INTEGER PRIMARY KEY, user_id INTEGER, name TEXT);}
21
+ reports_table = %{CREATE TABLE reports (id INTEGER PRIMARY KEY, record_id INTEGER, name TEXT);}
22
22
  ActiveRecord::Base.connection.execute(users_table)
23
23
  ActiveRecord::Base.connection.execute(records_table)
24
+ ActiveRecord::Base.connection.execute(reports_table)
24
25
 
25
26
  class User < ActiveRecord::Base
26
27
  has_many :records
@@ -28,5 +29,10 @@ end
28
29
 
29
30
  class Record < ActiveRecord::Base
30
31
  belongs_to :user
32
+ has_many :reports
33
+ end
34
+
35
+ class Report < ActiveRecord::Base
36
+ belongs_to :record
31
37
  end
32
38
 
@@ -1,6 +1,6 @@
1
1
  require 'helper'
2
2
 
3
- describe 'Enhanced Finder Methods' do
3
+ describe 'ActiveRecord::Relation Finder Methods' do
4
4
  after do
5
5
  User.destroy_all
6
6
  end
@@ -72,3 +72,73 @@ describe 'Enhanced Finder Methods' do
72
72
 
73
73
  end
74
74
 
75
+ describe 'ActiveRecord::Associations::AssociationCollection Finder Methods' do
76
+ before do
77
+ @user = User.create
78
+ @record_1 = @user.records.create(:name => 'one')
79
+ @record_2 = @user.records.create(:name => 'two')
80
+ end
81
+
82
+ after do
83
+ User.destroy_all
84
+ Record.destroy_all
85
+ end
86
+
87
+ describe '.all' do
88
+ it 'extracts the non-where scopes and applies' do
89
+ test_sql = @user.records.all(:limit! => 1, :offset! => 2, :order! => :name, :name => 'one').to_sql
90
+ expected_sql = @user.records.where(:name => 'one').limit(1).offset(2).order(:name).to_sql
91
+ test_sql.must_be_like expected_sql
92
+ end
93
+
94
+ it 'finds implicit joins by reflection' do
95
+ test_sql = @user.records.all(:reports => { :name => 'test' }).to_sql
96
+ expected_sql = @user.records.joins(:reports).where(:reports => { :name => 'test' }).to_sql
97
+ test_sql.must_be_like expected_sql
98
+ end
99
+ end
100
+
101
+ describe '.first' do
102
+ it 'calls #first on .all' do
103
+ @user.records.first(:name => 'two').must_equal @record_2
104
+ end
105
+ end
106
+
107
+ describe '.count' do
108
+ it 'calls #count on .all' do
109
+ @user.records.count(:name => 'one').must_equal 1
110
+ end
111
+ end
112
+
113
+ describe 'hash contains :conditions' do
114
+ describe 'with conditions' do
115
+ it 'falls back for .all' do
116
+ @user.records.all(:conditions => "name = 'one'").must_equal [@record_1]
117
+ end
118
+
119
+ it 'falls back for .first' do
120
+ @user.records.create(:name => 'one')
121
+ @user.records.first(:conditions => "name = 'one'").must_equal @record_1
122
+ end
123
+
124
+ # Note a valid test... need to rewrite.
125
+ # it 'falls back for .count' do
126
+ # @user.records.count(:conditions => "name = 'one'").must_equal 1
127
+ # end
128
+ end
129
+
130
+ describe 'without conditions' do
131
+ it 'falls back for .all' do
132
+ @user.records.all.must_equal [@record_1, @record_2]
133
+ end
134
+
135
+ it 'falls back for .first' do
136
+ @user.records.first.must_equal @record_1
137
+ end
138
+
139
+ it 'falls back for .count' do
140
+ @user.records.count.must_equal 2
141
+ end
142
+ end
143
+ end
144
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 6
9
- version: 0.0.6
8
+ - 7
9
+ version: 0.0.7
10
10
  platform: ruby
11
11
  authors:
12
12
  - Brian Cardarella
@@ -51,6 +51,9 @@ files:
51
51
  - Rakefile
52
52
  - better_ar.gemspec
53
53
  - lib/better_ar.rb
54
+ - lib/better_ar/association_collection.rb
55
+ - lib/better_ar/calculations.rb
56
+ - lib/better_ar/finder_methods.rb
54
57
  - lib/better_ar/version.rb
55
58
  - test/helper.rb
56
59
  - test/test_finder_methods.rb