better_ar 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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