ar_attr_lazy 0.1.0
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/.gitignore +3 -0
- data/LICENSE +20 -0
- data/README.md +35 -0
- data/Rakefile +62 -0
- data/init.rb +1 -0
- data/lib/mcmire/ar_attr_lazy.rb +32 -0
- data/lib/mcmire/ar_attr_lazy/association_preload_ext.rb +55 -0
- data/lib/mcmire/ar_attr_lazy/base_ext.rb +69 -0
- data/lib/mcmire/ar_attr_lazy/belongs_to_association_ext.rb +19 -0
- data/lib/mcmire/ar_attr_lazy/habtm_ext.rb +23 -0
- data/lib/mcmire/ar_attr_lazy/has_many_through_association_ext.rb +9 -0
- data/lib/mcmire/ar_attr_lazy/join_base_ext.rb +14 -0
- data/lib/mcmire/ar_attr_lazy/version.rb +5 -0
- data/test/factories.rb +96 -0
- data/test/helper.rb +107 -0
- data/test/matchers.rb +172 -0
- data/test/not_using_attr_lazy_test.rb +324 -0
- data/test/setup_migration.rb +67 -0
- data/test/setup_sti_models.rb +61 -0
- data/test/setup_tables_for_not_using.rb +91 -0
- data/test/setup_tables_for_using.rb +35 -0
- data/test/using_attr_lazy_sti_test.rb +357 -0
- data/test/using_attr_lazy_test.rb +359 -0
- metadata +136 -0
data/test/helper.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
if ENV["AR_VERSION"]
|
6
|
+
gem 'activerecord', "= #{ENV["AR_VERSION"]}"
|
7
|
+
end
|
8
|
+
require 'activerecord'
|
9
|
+
require 'active_record/version'
|
10
|
+
ActiveRecord::Base.establish_connection(
|
11
|
+
"adapter" => "sqlite3",
|
12
|
+
"database" => ":memory:"
|
13
|
+
)
|
14
|
+
|
15
|
+
gem 'mcmire-protest'
|
16
|
+
require 'protest'
|
17
|
+
gem 'mcmire-matchy'
|
18
|
+
require 'matchy'
|
19
|
+
gem 'mcmire-mocha'
|
20
|
+
require 'mocha'
|
21
|
+
require 'mocha-protest-integration'
|
22
|
+
|
23
|
+
Protest.report_with :documentation
|
24
|
+
#Protest::Utils::BacktraceFilter::ESCAPE_PATHS << %r|test/unit| << %r|matchy| << %r|mocha-protest-integration|
|
25
|
+
Protest::Utils::BacktraceFilter::ESCAPE_PATHS.clear
|
26
|
+
|
27
|
+
#------------------------
|
28
|
+
|
29
|
+
module Protest
|
30
|
+
class TestCase
|
31
|
+
def full_name
|
32
|
+
self.class.description + " " + self.name
|
33
|
+
end
|
34
|
+
|
35
|
+
class TestWrapper #:nodoc:
|
36
|
+
attr_reader :name
|
37
|
+
|
38
|
+
def initialize(type, test_case)
|
39
|
+
@type = type
|
40
|
+
@test = test_case
|
41
|
+
@name = "Global #{@type} for #{test_case.description}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def run(report)
|
45
|
+
@test.send("do_global_#{@type}")
|
46
|
+
end
|
47
|
+
|
48
|
+
def full_name
|
49
|
+
@name
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module TestWithErrors
|
55
|
+
def file
|
56
|
+
file_and_line[0]
|
57
|
+
end
|
58
|
+
|
59
|
+
def line
|
60
|
+
file_and_line[1]
|
61
|
+
end
|
62
|
+
|
63
|
+
def file_and_line
|
64
|
+
backtrace.find {|x| x =~ %r{^.*/test/(.*_test|test_.*)\.rb} }.split(":")[0..1]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module Utils
|
69
|
+
module Summaries
|
70
|
+
def summarize_errors
|
71
|
+
return if failures_and_errors.empty?
|
72
|
+
|
73
|
+
puts "Failures:"
|
74
|
+
puts
|
75
|
+
|
76
|
+
pad_indexes = failures_and_errors.size.to_s.size
|
77
|
+
failures_and_errors.each_with_index do |error, index|
|
78
|
+
colorize_as = ErroredTest === error ? :errored : :failed
|
79
|
+
# PATCH: test.full_name
|
80
|
+
puts " #{pad(index+1, pad_indexes)}) #{test_type(error)} in `#{error.test.full_name}' (on line #{error.line} of `#{error.file}')", colorize_as
|
81
|
+
# If error message has line breaks, indent the message
|
82
|
+
prefix = "with"
|
83
|
+
unless error.error.is_a?(Protest::AssertionFailed) ||
|
84
|
+
((RUBY_VERSION =~ /^1\.9/) ? error.error.is_a?(MiniTest::Assertion) : error.error.is_a?(::Test::Unit::AssertionFailedError))
|
85
|
+
prefix << " #{error.error.class}"
|
86
|
+
end
|
87
|
+
if error.error_message =~ /\n/
|
88
|
+
puts indent("#{prefix}: <<", 6 + pad_indexes), colorize_as
|
89
|
+
puts indent(error.error_message, 6 + pad_indexes + 2), colorize_as
|
90
|
+
puts indent(">>", 6 + pad_indexes), colorize_as
|
91
|
+
else
|
92
|
+
puts indent("#{prefix} `#{error.error_message}'", 6 + pad_indexes), colorize_as
|
93
|
+
end
|
94
|
+
indent(error.backtrace, 6 + pad_indexes).each {|backtrace| puts backtrace, colorize_as }
|
95
|
+
puts
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
#------------------------
|
103
|
+
|
104
|
+
require 'matchers'
|
105
|
+
require 'factories'
|
106
|
+
|
107
|
+
require 'mcmire/ar_attr_lazy'
|
data/test/matchers.rb
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
module MatchyMatchers
|
2
|
+
# Ported from an RSpec matcher
|
3
|
+
# from https://rspec.lighthouseapp.com/projects/5645/tickets/896-lambda-should-query-matcher
|
4
|
+
# with a few tweaks
|
5
|
+
class ArQuery #:nodoc:
|
6
|
+
cattr_accessor :executed
|
7
|
+
|
8
|
+
@@recording_queries = false
|
9
|
+
def self.recording_queries?
|
10
|
+
@@recording_queries
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(test_case, expecteds, &block)
|
14
|
+
@test_case = test_case
|
15
|
+
@expecteds = expecteds
|
16
|
+
@expecteds = [1] if @expecteds.empty?
|
17
|
+
@block = block
|
18
|
+
end
|
19
|
+
|
20
|
+
def matches?(given_proc)
|
21
|
+
@eval_block = false
|
22
|
+
@eval_error = nil
|
23
|
+
ArQuery.executed = []
|
24
|
+
@@recording_queries = true
|
25
|
+
|
26
|
+
given_proc.call
|
27
|
+
|
28
|
+
if @expecteds[0].is_a?(Fixnum)
|
29
|
+
@expecteds = @expecteds[0]
|
30
|
+
@actuals = ArQuery.executed.length
|
31
|
+
@matched = (@actuals == @expecteds)
|
32
|
+
else
|
33
|
+
# assume that a block was not given
|
34
|
+
# PATCH: accept multiple queries
|
35
|
+
@expecteds = Array(@expecteds)
|
36
|
+
@actuals = @expecteds.map {|query| [query, ArQuery.executed.detect {|sql| query === sql }] }
|
37
|
+
@matched = @actuals.all? {|e,a| a }
|
38
|
+
end
|
39
|
+
|
40
|
+
eval_block if @block && @matched && !negative_expectation?
|
41
|
+
|
42
|
+
@matched && @eval_error.nil?
|
43
|
+
|
44
|
+
ensure
|
45
|
+
#ArQuery.executed = nil
|
46
|
+
@@recording_queries = false
|
47
|
+
end
|
48
|
+
|
49
|
+
# This is necessary for interoperability with Matchy
|
50
|
+
def fail!(which)
|
51
|
+
@test_case.flunk(which ? failure_message_for_should : failure_message_for_should_not)
|
52
|
+
end
|
53
|
+
|
54
|
+
# This is necessary for interoperability with Matchy
|
55
|
+
def pass!(which)
|
56
|
+
@test_case.assert true
|
57
|
+
end
|
58
|
+
|
59
|
+
def eval_block
|
60
|
+
@eval_block = true
|
61
|
+
begin
|
62
|
+
@block.call(ArQuery.executed)
|
63
|
+
rescue Exception => err
|
64
|
+
@eval_error = err
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def failure_message_for_should
|
69
|
+
if @eval_error
|
70
|
+
@eval_error.message
|
71
|
+
elsif @expecteds.is_a?(Fixnum)
|
72
|
+
"expected #{@expecteds} to be executed, when in fact #{@actuals} were"
|
73
|
+
else
|
74
|
+
# PATCH: better error message
|
75
|
+
msg = ""
|
76
|
+
@actuals.select {|e,a| !a }.each do |expected, _|
|
77
|
+
msg << "expected a query with pattern #{expected.inspect} to be executed, but it wasn't\n"
|
78
|
+
end
|
79
|
+
msg << "All queries executed:\n"
|
80
|
+
ArQuery.executed.each do |query|
|
81
|
+
msg << " - #{query}\n"
|
82
|
+
end
|
83
|
+
msg
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def failure_message_for_should_not
|
88
|
+
if @expecteds.is_a?(Fixnum)
|
89
|
+
"did not expect #{@expecteds} queries to be executed, but they were"
|
90
|
+
else
|
91
|
+
# PATCH: better error message
|
92
|
+
msg = ""
|
93
|
+
@actuals.select {|e,a| a }.each do |_, actual|
|
94
|
+
msg << "expected a query with pattern #{actual.inspect} not to be executed, but it was\n"
|
95
|
+
end
|
96
|
+
msg << "All queries executed:\n"
|
97
|
+
ArQuery.executed.each do |query|
|
98
|
+
msg << " - #{query}\n"
|
99
|
+
end
|
100
|
+
msg
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
#def description
|
105
|
+
# if @expecteds.is_a?(Fixnum)
|
106
|
+
# @expecteds == 1 ? "execute 1 query" : "execute #{@expecteds} queries"
|
107
|
+
# else
|
108
|
+
# "execute query with pattern #{@expecteds.inspect}"
|
109
|
+
# end
|
110
|
+
#end
|
111
|
+
|
112
|
+
# Copied from raise_error
|
113
|
+
def negative_expectation?
|
114
|
+
@negative_expectation ||= !caller.first(3).find { |s| s =~ /should_not/ }.nil?
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# :call-seq:
|
119
|
+
# response.should query
|
120
|
+
# response.should query(expected)
|
121
|
+
# response.should query(expected1, expected2)
|
122
|
+
# response.should query(expected) { |sql| ... }
|
123
|
+
# response.should_not query
|
124
|
+
# response.should_not query(expected)
|
125
|
+
# response.should_not query(expected1, expected2)
|
126
|
+
#
|
127
|
+
# Accepts a Fixnum, a String, a Regexp, or an array of Strings or Regexps as arguments.
|
128
|
+
#
|
129
|
+
# With no args, matches if exactly 1 query is executed.
|
130
|
+
# With a Fixnum arg, matches if the number of queries executed equals the given number.
|
131
|
+
# With a Regexp arg, matches if any query is executed with the given pattern.
|
132
|
+
# With multiple args, matches if all given patterns are matched by all queries executed.
|
133
|
+
#
|
134
|
+
# Pass an optional block to perform extra verifications of the queries matched.
|
135
|
+
# The argument of the block will receive an array of query strings that were executed.
|
136
|
+
#
|
137
|
+
# == Examples
|
138
|
+
#
|
139
|
+
# lambda { @object.posts }.should query # same as `should query(1)`
|
140
|
+
# lambda { @object.valid? }.should query(0)
|
141
|
+
# lambda { @object.save }.should query(3)
|
142
|
+
# lambda { @object.line_items }.should query("SELECT DISTINCT")
|
143
|
+
# lambda { @object.line_items }.should query(/SELECT DISTINCT/)
|
144
|
+
# lambda { @object.line_items }.should query(/SELECT DISTINCT/, /SELECT COUNT\(\*\)/)
|
145
|
+
# lambda { @object.line_items }.should query(1) { |sql| sql[0].should =~ /SELECT DISTINCT/ }
|
146
|
+
#
|
147
|
+
# lambda { @object.posts }.should_not query # same as `should_not query(1)`
|
148
|
+
# lambda { @object.valid? }.should_not query(0)
|
149
|
+
# lambda { @object.save }.should_not query(3)
|
150
|
+
# lambda { @object.line_items }.should_not query(/SELECT DISTINCT/)
|
151
|
+
# lambda { @object.line_items }.should_not query(/SELECT DISTINCT/, /SELECT COUNT\(\*\)/)
|
152
|
+
#
|
153
|
+
def query(*expecteds, &block)
|
154
|
+
ArQuery.new(self, expecteds, &block)
|
155
|
+
end
|
156
|
+
|
157
|
+
unless defined?(IGNORED_SQL)
|
158
|
+
# From active_record/test/cases/helper.rb :
|
159
|
+
::ActiveRecord::Base.connection.class.class_eval do
|
160
|
+
IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /SHOW FIELDS/]
|
161
|
+
def execute_with_query_record(sql, name = nil, &block)
|
162
|
+
if ArQuery.recording_queries?
|
163
|
+
# PATCH: squeeze and strip
|
164
|
+
ArQuery.executed << sql.squeeze(" ").strip unless IGNORED_SQL.any? { |ignore| sql =~ ignore }
|
165
|
+
end
|
166
|
+
execute_without_query_record(sql, name, &block)
|
167
|
+
end
|
168
|
+
alias_method_chain :execute, :query_record
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
Protest::TestCase.class_eval { include MatchyMatchers }
|
@@ -0,0 +1,324 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
# what about STI? (do the lazy attributes carry over?)
|
4
|
+
|
5
|
+
Protest.context "for a model that doesn't have lazy attributes" do
|
6
|
+
global_setup do
|
7
|
+
load File.dirname(__FILE__) + '/setup_migration.rb'
|
8
|
+
load File.dirname(__FILE__) + '/setup_tables_for_not_using.rb'
|
9
|
+
Account.make! do |account|
|
10
|
+
User.make!(:account => account) do |user|
|
11
|
+
Avatar.make!(:user => user)
|
12
|
+
Post.make!(:author => user) do |post|
|
13
|
+
Comment.make!(:post => post)
|
14
|
+
post.tags << Tag.make
|
15
|
+
post.categories << Category.make
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
global_teardown do
|
22
|
+
ObjectSpace.each_object(Class) do |klass|
|
23
|
+
Object.remove_class(klass) if klass < ActiveRecord::Base
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def regex(str)
|
28
|
+
Regexp.new(Regexp.escape(str))
|
29
|
+
end
|
30
|
+
|
31
|
+
context "with no associations involved" do
|
32
|
+
test "find selects all attributes by default" do
|
33
|
+
lambda { Account.find(:first) }.should query(regex(%|SELECT * FROM "accounts"|))
|
34
|
+
end
|
35
|
+
test "accessing any one attribute doesn't do a query" do
|
36
|
+
account = Account.first
|
37
|
+
lambda { account.name }.should_not query
|
38
|
+
end
|
39
|
+
test "find still honors an explicit select option" do
|
40
|
+
lambda { Account.find(:first, :select => "name") }.should query(regex(%|SELECT name FROM "accounts"|))
|
41
|
+
end
|
42
|
+
test "find still honors a select option in a parent scope" do
|
43
|
+
lambda {
|
44
|
+
Account.send(:with_scope, :find => {:select => "name"}) do
|
45
|
+
Account.find(:first)
|
46
|
+
end
|
47
|
+
}.should query(regex(%|SELECT name FROM "accounts"|))
|
48
|
+
end
|
49
|
+
if Mcmire::ArAttrLazy.ar_version >= 2.3
|
50
|
+
test "find still honors a select option in a default scope" do
|
51
|
+
lambda { AccountWithDefaultScope.find(:first) }.should query(regex(%|SELECT name FROM "accounts"|))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "accessing a has_many association" do
|
57
|
+
before do
|
58
|
+
@post = Post.first
|
59
|
+
end
|
60
|
+
test "find selects all attributes by default" do
|
61
|
+
lambda { @post.comments.find(:first) }.should query(regex(%|SELECT * FROM "comments"|))
|
62
|
+
end
|
63
|
+
test "find still honors an explicit select option" do
|
64
|
+
lambda { @post.comments.find(:first, :select => "name") }.should query(
|
65
|
+
regex(%|SELECT name FROM "comments"|)
|
66
|
+
)
|
67
|
+
end
|
68
|
+
test "find still honors a select option in a parent scope" do
|
69
|
+
lambda {
|
70
|
+
Comment.send(:with_scope, :find => {:select => "name"}) do
|
71
|
+
@post.comments.find(:first)
|
72
|
+
end
|
73
|
+
}.should query(
|
74
|
+
regex(%|SELECT name FROM "comments"|)
|
75
|
+
)
|
76
|
+
end
|
77
|
+
if Mcmire::ArAttrLazy.ar_version >= 2.3
|
78
|
+
test "find still honors a select option in a default scope" do
|
79
|
+
lambda { @post.comments_with_default_scope.find(:first) }.should query(
|
80
|
+
regex(%|SELECT name FROM "comments"|)
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
test "find still honors a select option in the association definition itself" do
|
85
|
+
lambda { @post.comments_with_select.find(:first) }.should query(
|
86
|
+
regex(%|SELECT name FROM "comments"|)
|
87
|
+
)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "accessing a belongs_to association" do
|
92
|
+
test "find selects all attributes by default" do
|
93
|
+
post = Post.first
|
94
|
+
lambda { post.author }.should query(regex(%|SELECT * FROM "users"|))
|
95
|
+
end
|
96
|
+
# can't do a find on a belongs_to, so no testing needed for that
|
97
|
+
end
|
98
|
+
|
99
|
+
context "accessing a has_one association" do
|
100
|
+
test "find selects all attributes by default" do
|
101
|
+
account = Account.first
|
102
|
+
lambda { account.user }.should query(regex(%|SELECT * FROM "users"|))
|
103
|
+
end
|
104
|
+
# can't do a find on a has_one, so no testing needed for that
|
105
|
+
end
|
106
|
+
|
107
|
+
context "accessing a has_and_belongs_to_many association" do
|
108
|
+
before do
|
109
|
+
@post = Post.first
|
110
|
+
end
|
111
|
+
test "find selects all attributes by default" do
|
112
|
+
lambda { @post.tags.find(:all) }.should query(regex(%|SELECT * FROM "tags"|))
|
113
|
+
end
|
114
|
+
test "find still honors an explicit select option" do
|
115
|
+
lambda { @post.tags.find(:all, :select => "tags.name") }.should query(
|
116
|
+
regex(%|SELECT tags.name FROM "tags"|)
|
117
|
+
)
|
118
|
+
end
|
119
|
+
test "find still honors a select option in a parent scope" do
|
120
|
+
pending "this fails on Rails 2.3.4"
|
121
|
+
lambda {
|
122
|
+
Tag.send(:with_scope, :find => {:select => "tags.name"}) do
|
123
|
+
@post.tags.find(:all)
|
124
|
+
end
|
125
|
+
}.should query(
|
126
|
+
regex(%|SELECT tags.name FROM "tags"|)
|
127
|
+
)
|
128
|
+
end
|
129
|
+
if Mcmire::ArAttrLazy.ar_version >= 2.3
|
130
|
+
test "find still honors a select option in a default scope" do
|
131
|
+
pending "this fails on Rails 2.3.4"
|
132
|
+
lambda {
|
133
|
+
@post.tags_with_default_scope.find(:all)
|
134
|
+
}.should query(
|
135
|
+
regex(%|SELECT tags.name FROM "tags"|)
|
136
|
+
)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
test "find still honors a select option in the association definition itself" do
|
140
|
+
lambda {
|
141
|
+
@post.tags_with_select.find(:all)
|
142
|
+
}.should query(
|
143
|
+
regex(%|SELECT tags.name FROM "tags"|)
|
144
|
+
)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context "accessing a has_many :through association" do
|
149
|
+
before do
|
150
|
+
@post = Post.first
|
151
|
+
end
|
152
|
+
test "find selects all attributes by default" do
|
153
|
+
lambda { @post.categories.find(:all) }.should query(
|
154
|
+
regex(%|SELECT "categories".* FROM "categories"|)
|
155
|
+
)
|
156
|
+
end
|
157
|
+
test "find still honors an explicit select option" do
|
158
|
+
lambda { @post.categories.find(:all, :select => "categories.name") }.should query(
|
159
|
+
regex(%|SELECT categories.name FROM "categories"|)
|
160
|
+
)
|
161
|
+
end
|
162
|
+
test "find still honors a select option in a parent scope" do
|
163
|
+
pending "this fails on Rails 2.3.4"
|
164
|
+
lambda {
|
165
|
+
Category.send(:with_scope, :find => {:select => "categories.name"}) do
|
166
|
+
@post.categories.find(:all)
|
167
|
+
end
|
168
|
+
}.should query(
|
169
|
+
regex(%|SELECT categories.name FROM "categories"|)
|
170
|
+
)
|
171
|
+
end
|
172
|
+
if Mcmire::ArAttrLazy.ar_version >= 2.3
|
173
|
+
test "find still honors a select option in a default scope" do
|
174
|
+
pending "this fails on Rails 2.3.4"
|
175
|
+
lambda {
|
176
|
+
@post.categories_with_default_scope.find(:all)
|
177
|
+
}.should query(
|
178
|
+
regex(%|SELECT categories.name FROM "categories"|)
|
179
|
+
)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
test "find still honors a select option in the association definition itself" do
|
183
|
+
lambda {
|
184
|
+
@post.categories_with_select.find(:all)
|
185
|
+
}.should query(
|
186
|
+
regex(%|SELECT categories.name FROM "categories"|)
|
187
|
+
)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# has_one :through didn't work properly prior to 2.3.4 - see LH #2719
|
192
|
+
if Mcmire::ArAttrLazy.ar_version >= "2.3.4"
|
193
|
+
context "accessing a has_one :through association" do
|
194
|
+
test "find selects all attributes by default" do
|
195
|
+
account = Account.first
|
196
|
+
lambda { account.avatar }.should query(
|
197
|
+
regex(%|SELECT "avatars".* FROM "avatars"|)
|
198
|
+
)
|
199
|
+
end
|
200
|
+
# can't do a find on a has_one, so no testing needed for that
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context "eager loading a has_many association (association preloading)" do
|
205
|
+
test "find selects all attributes by default" do
|
206
|
+
lambda {
|
207
|
+
Post.find(:first, :include => :comments)
|
208
|
+
}.should query(regex(%|SELECT * FROM "posts"|), regex(%|SELECT "comments".* FROM "comments"|))
|
209
|
+
end
|
210
|
+
# can't test for an explicit select since that will force a table join
|
211
|
+
# can't test for a scope select since association preloading doesn't honor those
|
212
|
+
end
|
213
|
+
context "eager loading a has_many association (table join)" do
|
214
|
+
test "find selects all attributes by default" do
|
215
|
+
lambda {
|
216
|
+
Post.find(:first, :include => :comments, :order => "comments.id")
|
217
|
+
}.should query(%r{"posts"\."body"}, %r{"comments"\."body"})
|
218
|
+
end
|
219
|
+
# can't test for an explicit select since that clashes with the table join anyway
|
220
|
+
# can't test for a scope for the same reason
|
221
|
+
end
|
222
|
+
|
223
|
+
context "eager loading a has_one association (association preloading)" do
|
224
|
+
test "find selects all attributes by default" do
|
225
|
+
lambda { Account.find(:first, :include => :user) }.should query(regex(%|SELECT "users".* FROM "users"|))
|
226
|
+
end
|
227
|
+
# can't test for an explicit select since that will force a table join
|
228
|
+
# can't test for a scope select since association preloading doesn't honor those
|
229
|
+
end
|
230
|
+
context "eager loading a has_one association (table join)" do
|
231
|
+
test "find selects all attributes by default" do
|
232
|
+
lambda {
|
233
|
+
Account.find(:first, :include => :user, :order => "users.id")
|
234
|
+
}.should query(%r{"users"\."bio"})
|
235
|
+
end
|
236
|
+
# can't test for an explicit select since that clashes with the table join anyway
|
237
|
+
# can't test for a scope for the same reason
|
238
|
+
end
|
239
|
+
|
240
|
+
context "eager loading a belongs_to association (association preloading)" do
|
241
|
+
test "find selects all attributes by default" do
|
242
|
+
lambda {
|
243
|
+
Post.find(:first, :include => :author)
|
244
|
+
}.should query(regex(%|SELECT * FROM "posts"|))
|
245
|
+
end
|
246
|
+
# can't test for an explicit select since that will force a table join
|
247
|
+
# can't test for a scope select since association preloading doesn't honor those
|
248
|
+
end
|
249
|
+
context "eager loading a belongs_to association (table join)" do
|
250
|
+
test "find selects all attributes by default" do
|
251
|
+
lambda {
|
252
|
+
Post.find(:first, :include => :author, :order => "users.id")
|
253
|
+
}.should query(%r{"posts"\."(body|summary)"}, %r{"users"\."bio"})
|
254
|
+
end
|
255
|
+
# can't test for an explicit select since that clashes with the table join anyway
|
256
|
+
# can't test for a scope for the same reason
|
257
|
+
end
|
258
|
+
|
259
|
+
context "eager loading a has_and_belongs_to_many association (association preloading)" do
|
260
|
+
test "find selects all attributes by default" do
|
261
|
+
lambda {
|
262
|
+
Post.find(:first, :include => :tags)
|
263
|
+
}.should query(regex(%|SELECT * FROM "posts"|), regex(%|SELECT "tags".*, t0.post_id as the_parent_record_id FROM "tags"|))
|
264
|
+
end
|
265
|
+
# can't test for an explicit select since that will force a table join
|
266
|
+
# can't test for a scope select since association preloading doesn't honor those
|
267
|
+
end
|
268
|
+
context "eager loading a has_and_belongs_to_many association (table join)" do
|
269
|
+
test "find selects all attributes by default" do
|
270
|
+
lambda {
|
271
|
+
Post.find(:first, :include => :tags, :order => "tags.id")
|
272
|
+
}.should query(%r{"posts"\."(body|summary)"}, %r{"tags"\."description"})
|
273
|
+
end
|
274
|
+
# can't test for an explicit select since that clashes with the table join anyway
|
275
|
+
# can't test for a scope for the same reason
|
276
|
+
end
|
277
|
+
|
278
|
+
context "eager loading a has_many :through association (association preloading)" do
|
279
|
+
test "find selects all attributes by default" do
|
280
|
+
lambda {
|
281
|
+
Post.find(:first, :include => :categories)
|
282
|
+
}.should query(
|
283
|
+
regex(%|SELECT * FROM "categories"|)
|
284
|
+
)
|
285
|
+
end
|
286
|
+
# can't test for an explicit select since that will force a table join
|
287
|
+
# can't test for a scope select since association preloading doesn't honor those
|
288
|
+
end
|
289
|
+
context "eager loading a has_many :through association (table join)" do
|
290
|
+
test "find selects all attributes by default" do
|
291
|
+
lambda {
|
292
|
+
Post.find(:first, :include => :categories, :order => "categories.id")
|
293
|
+
}.should query(
|
294
|
+
regex(%|SELECT "posts"."id" AS t0_r0, "posts"."type" AS t0_r1, "posts"."author_id" AS t0_r2, "posts"."title" AS t0_r3, "posts"."permalink" AS t0_r4, "posts"."body" AS t0_r5, "posts"."summary" AS t0_r6, "categories"."id" AS t1_r0, "categories"."type" AS t1_r1, "categories"."name" AS t1_r2, "categories"."description" AS t1_r3 FROM "posts"|)
|
295
|
+
)
|
296
|
+
end
|
297
|
+
# can't test for an explicit select since that clashes with the table join anyway
|
298
|
+
# can't test for a scope for the same reason
|
299
|
+
end
|
300
|
+
|
301
|
+
# has_one :through didn't work properly prior to 2.3.4 - see LH #2719
|
302
|
+
if Mcmire::ArAttrLazy.ar_version >= "2.3.4"
|
303
|
+
context "eager loading a has_one :through association (association preloading)" do
|
304
|
+
test "find selects all attributes by default" do
|
305
|
+
lambda { Account.find(:first, :include => :avatar) }.should query(
|
306
|
+
regex(%|SELECT "avatars".* FROM "avatars"|)
|
307
|
+
)
|
308
|
+
end
|
309
|
+
# can't test for an explicit select since that will force a table join
|
310
|
+
# can't test for a scope select since association preloading doesn't honor those
|
311
|
+
end
|
312
|
+
context "eager loading a has_one :through association (table join)" do
|
313
|
+
test "find selects all attributes by default" do
|
314
|
+
pending "this is failing for some reason!"
|
315
|
+
lambda {
|
316
|
+
Account.find(:first, :include => :avatar, :order => "avatars.filename")
|
317
|
+
}.should query(%|SELECT "accounts"."id" AS t0_r0, "accounts"."name" AS t0_r1, "avatars"."id" AS t1_r0, "avatars"."user_id" AS t1_r1, "avatars"."filename" AS t1_r2, "avatars"."data" AS t1_r3 FROM "accounts"|)
|
318
|
+
end
|
319
|
+
# can't test for an explicit select since that clashes with the table join anyway
|
320
|
+
# can't test for a scope for the same reason
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
end
|