deferring 0.6.2 → 0.7.0

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
  SHA256:
3
- metadata.gz: b06d2014bec77285df7d494e04b1aceae86e4ce9b147f0916002db02e1e79cba
4
- data.tar.gz: d89af52998b5d67de9f29cf971a5f68f1ce9339e340f3170c9c0cbd6c4df1713
3
+ metadata.gz: 35b9b80d6c94a8b980f80cd953565bcf7cf2f8a207de3880904286e617ed30a0
4
+ data.tar.gz: f78c5caa4d9c1a5a446ac504c839bebf21e29a059e57e5739de4ef5842106b63
5
5
  SHA512:
6
- metadata.gz: 3fd88c4d8a0c1be57f6b4ac674faf39bc1a152117a86d719aa6e2727cd93b916d547404e66c5e67f636aeb209918a0dcbcf78db256704ff3e45c0f9951c592ca
7
- data.tar.gz: 15ac8fa0e41d23af97a1ac35ac0e29c429e1287bc83fa6cf7148437070a57a6bd8a36fa49910bc5d8ee4288d2ca20c091ac7289b63b210e2c13d4db4997453a8
6
+ metadata.gz: af8785f36ce8551ba95a9f7dab9d28fdfc8cd46bc6a427bddc70007985225ce3edd23daf1c1cdd21f5102d1c3bef0d2a0ae2598752b0fa38318225235db8a9e4
7
+ data.tar.gz: 549c445412012809bdbe613dd028395acc22ef4dc5e26fc803fc2db5734a2f7b26fc4c134693c6fae5147e6bb7d83d7b4afde8eed25719ef57ea47af3232c4d5
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- deferring (0.6.1)
4
+ deferring (0.7.0)
5
5
  activerecord (>= 4.2)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- deferring (0.6.1)
4
+ deferring (0.7.0)
5
5
  activerecord (>= 4.2)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- deferring (0.6.1)
4
+ deferring (0.7.0)
5
5
  activerecord (>= 4.2)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- deferring (0.6.1)
4
+ deferring (0.7.0)
5
5
  activerecord (>= 4.2)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- deferring (0.6.1)
4
+ deferring (0.7.0)
5
5
  activerecord (>= 4.2)
6
6
 
7
7
  GEM
@@ -26,14 +26,14 @@ module Deferring
26
26
  alias_method :pretty_inspect, :inspect
27
27
 
28
28
  delegate :to_s, :to_a, :inspect, :==, # methods undefined by SimpleDelegator
29
- :is_a?, :as_json, to: :objects
29
+ :as_json, to: :objects
30
30
 
31
31
  def each(&block)
32
32
  objects.each(&block)
33
33
  end
34
34
 
35
35
  # TODO: Add explanation about :first/:last loaded? problem.
36
- [:first, :last].each do |method|
36
+ [:first, :last, :empty?, :size].each do |method|
37
37
  define_method method do
38
38
  unless objects_loaded?
39
39
  original_association.send(method)
@@ -46,7 +46,7 @@ module Deferring
46
46
  # Delegates methods from Ruby's Array module to the object in the deferred
47
47
  # association.
48
48
  delegate :[]=, :[], :clear, :select!, :reject!, :flatten, :flatten!, :sort!,
49
- :keep_if, :delete_if, :sort_by!, :empty?, :size, :length,
49
+ :keep_if, :delete_if, :sort_by!, :length,
50
50
  :each_index,
51
51
  to: :objects
52
52
 
@@ -58,6 +58,14 @@ module Deferring
58
58
  original_association.find(*args)
59
59
  end
60
60
 
61
+ # Delegates Ruby's Enumerable#count method to the original association.
62
+ #
63
+ # The delegation has to be explicit in this case, because the inclusion of
64
+ # Enumerable also defines the count-method on DeferredAssociation.
65
+ def count(*args)
66
+ original_association.count(*args)
67
+ end
68
+
61
69
  # Delegates Ruby's Enumerable#select method to the original association when
62
70
  # no block has been given. Rails' select-method does not accept a block, so
63
71
  # we know that in that case the select-method has to be called on our
@@ -1,3 +1,3 @@
1
1
  module Deferring
2
- VERSION = '0.6.2'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -359,6 +359,58 @@ RSpec.describe 'deferred has_many associations' do
359
359
  people = Person.all
360
360
  expect(people[1].issues.loaded?).to be_falsey
361
361
  end
362
+
363
+ describe 'count' do
364
+ it 'should not load the association' do
365
+ person = Person.where(name: 'Bob').first
366
+ expect(person.issues.count).to eq(2)
367
+ expect(person.issues.loaded?).to be_falsey
368
+ end
369
+
370
+ it 'should execute a count(*) query, even if the association has already been loaded' do
371
+ person = Person.where(name: 'Bob').first
372
+ expect { person.issues.count }.to query(1) { |sql| expect(sql).to include('SELECT COUNT(*) FROM "issues"') }
373
+ expect { person.issues.to_a }.to query(1)
374
+ expect(person.issues.loaded?).to be_truthy
375
+ expect { person.issues.to_a }.to query(0)
376
+ expect { person.issues.count }.to query(1) { |sql| expect(sql).to include('SELECT COUNT(*) FROM "issues"') }
377
+ end
378
+ end
379
+
380
+ describe 'size' do
381
+ it 'should not load the association' do
382
+ person = Person.where(name: 'Bob').first
383
+ expect(person.issues.size).to eq(2)
384
+ expect { person.issues.size }.to query(1) { |sql| expect(sql).to include('SELECT COUNT(*) FROM "issues"') }
385
+ expect(person.issues.loaded?).to be_falsey
386
+ end
387
+
388
+ it 'should not execute query when the association has already been loaded' do
389
+ person = Person.where(name: 'Bob').first
390
+ expect { person.issues.size }.to query(1) { |sql| expect(sql).to include('SELECT COUNT(*) FROM "issues"') }
391
+ expect { person.issues.to_a }.to query(1)
392
+ expect(person.issues.loaded?).to be_truthy
393
+ expect { person.issues.to_a }.to query(0)
394
+ expect { person.issues.size }.to query(0)
395
+ end
396
+ end
397
+
398
+ describe 'empty?' do
399
+ it 'should not load the association' do
400
+ person = Person.where(name: 'Bob').first
401
+ expect(person.issues.empty?).to be_falsey
402
+ expect(person.issues.loaded?).to be_falsey
403
+ end
404
+
405
+ it 'should not execute query when the association has already been loaded' do
406
+ person = Person.where(name: 'Bob').first
407
+ expect { person.issues.empty? }.to query(1) { |sql| expect(sql).to include('SELECT 1') }
408
+ expect { person.issues.to_a }.to query(1)
409
+ expect(person.issues.loaded?).to be_truthy
410
+ expect { person.issues.to_a }.to query(0)
411
+ expect { person.issues.empty? }.to query(0)
412
+ end
413
+ end
362
414
  end # preloading associations
363
415
 
364
416
  describe 'active record api' do
@@ -9,7 +9,6 @@ RSpec.describe 'deferred accepts_nested_attributes' do
9
9
  Team.create!(name: 'Database Administration')
10
10
  Team.create!(name: 'End-User Support')
11
11
  Team.create!(name: 'Operations')
12
-
13
12
  end
14
13
 
15
14
  let(:bob) { Person.where(name: 'Bob').first }
@@ -48,21 +47,4 @@ RSpec.describe 'deferred accepts_nested_attributes' do
48
47
  expect(p.team_ids.sort).to eq([1])
49
48
  end
50
49
 
51
- it '' do
52
- issue = Issue.create!(subject: 'Foo', person: bob)
53
-
54
- p = Person.where(name: 'Alice').take
55
- p.attributes = {
56
- issues_attributes: [
57
- { id: issue.id },
58
- ]
59
- }
60
- p.save!
61
-
62
- p.reload
63
- expect(p.issues.size).to eq(1)
64
-
65
- bob.reload
66
- expect(bob.issues.size).to eq(0)
67
- end
68
50
  end
@@ -5,6 +5,7 @@ require 'support/models/team'
5
5
  require 'support/models/issue'
6
6
  require 'support/models/address'
7
7
  require 'support/models/non_validated_issue'
8
+ require 'support/matchers/query_matcher'
8
9
 
9
10
  RSpec.configure do |config|
10
11
  config.disable_monkey_patching!
@@ -18,6 +19,8 @@ RSpec.configure do |config|
18
19
  # --seed 1234
19
20
  config.order = 'random'
20
21
 
22
+ config.include(Deferring::Matchers)
23
+
21
24
  # Rollback all the database changes after each spec, poor man's
22
25
  # DatabaseCleaner :-)
23
26
  config.around do |example|
@@ -0,0 +1,127 @@
1
+ module Deferring
2
+ module Matchers
3
+
4
+ class ArQuery #:nodoc:
5
+ cattr_accessor :executed
6
+
7
+ @@recording_queries = false
8
+ def self.recording_queries?
9
+ @@recording_queries
10
+ end
11
+
12
+ def initialize(expected, &block)
13
+ @expected = expected
14
+ @block = block
15
+ end
16
+
17
+ def matches?(given_proc)
18
+ @eval_block = false
19
+ @eval_error = nil
20
+ ArQuery.executed = []
21
+ @@recording_queries = true
22
+
23
+ given_proc.call
24
+
25
+ if @expected.is_a?(Integer)
26
+ @actual = ArQuery.executed.length
27
+ @matched = @actual == @expected
28
+ else
29
+ @actual = ArQuery.executed.detect { |sql| @expected === sql }
30
+ @matched = !@actual.nil?
31
+ end
32
+
33
+ eval_block if @block && @matched && !negative_expectation?
34
+
35
+ ensure
36
+ ArQuery.executed = nil
37
+ @@recording_queries = false
38
+ return @matched && @eval_error.nil?
39
+ end
40
+
41
+ def eval_block
42
+ @eval_block = true
43
+ begin
44
+ @block[ArQuery.executed]
45
+ rescue => err
46
+ @eval_error = err
47
+ end
48
+ end
49
+
50
+ def supports_block_expectations?
51
+ true
52
+ end
53
+
54
+ def failure_message
55
+ if @eval_error
56
+ @eval_error.message
57
+ elsif @expected.is_a?(Integer)
58
+ "expected #{@expected}, got #{@actual}"
59
+ else
60
+ "expected to execute a query with pattern #{@expected.inspect}, but it wasn't"
61
+ end
62
+ end
63
+
64
+ def failure_message_when_negated
65
+ if @expected.is_a?(Integer)
66
+ "did not expect #{@expected}"
67
+ else
68
+ "did not expect to execute a query with pattern #{@expected.inspect}, but it was executed"
69
+ end
70
+ end
71
+
72
+ def description
73
+ if @expected.is_a?(Integer)
74
+ @expected == 1 ? 'execute 1 query' : "execute #{@expected} queries"
75
+ else
76
+ "execute query with pattern #{@expected.inspect}"
77
+ end
78
+ end
79
+
80
+ def negative_expectation?
81
+ @negative_expectation ||= !caller.first(3).find { |s| s =~ /should_not/ }.nil?
82
+ end
83
+ end
84
+
85
+ def query(expected = 1, &block)
86
+ ArQuery.new(expected, &block)
87
+ end
88
+ end
89
+ end
90
+
91
+ # For Rails 6.0
92
+ module ActiveRecord
93
+ module ConnectionAdapters
94
+ module SQLite3
95
+ module DatabaseStatements
96
+ [:exec_query, :exec, :execute].each do |method|
97
+ if respond_to?(method)
98
+ define_method("#{method}_with_query_record") do |sql, *args|
99
+ Deferring::Matchers::ArQuery.executed << sql if Deferring::Matchers::ArQuery.recording_queries?
100
+ send("#{method}_without_query_record", sql, *args)
101
+ end
102
+
103
+ alias_method :"#{method}_without_query_record", method
104
+ alias_method method, :"#{method}_with_query_record"
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ # For previous versions of Rails
113
+ module ActiveRecord
114
+ module ConnectionAdapters
115
+ class SQLite3Adapter
116
+ [:exec_query, :exec, :execute].each do |method|
117
+ define_method("#{method}_with_query_record") do |sql, *args|
118
+ Deferring::Matchers::ArQuery.executed << sql if Deferring::Matchers::ArQuery.recording_queries?
119
+ send("#{method}_without_query_record", sql, *args)
120
+ end
121
+
122
+ alias_method :"#{method}_without_query_record", method
123
+ alias_method method, :"#{method}_with_query_record"
124
+ end
125
+ end
126
+ end
127
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deferring
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robin Roestenburg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-08 00:00:00.000000000 Z
11
+ date: 2020-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -116,6 +116,7 @@ files:
116
116
  - spec/lib/deferring_nested_attributes_spec.rb
117
117
  - spec/spec_helper.rb
118
118
  - spec/support/active_record.rb
119
+ - spec/support/matchers/query_matcher.rb
119
120
  - spec/support/models/address.rb
120
121
  - spec/support/models/issue.rb
121
122
  - spec/support/models/non_validated_issue.rb
@@ -151,6 +152,7 @@ test_files:
151
152
  - spec/lib/deferring_nested_attributes_spec.rb
152
153
  - spec/spec_helper.rb
153
154
  - spec/support/active_record.rb
155
+ - spec/support/matchers/query_matcher.rb
154
156
  - spec/support/models/address.rb
155
157
  - spec/support/models/issue.rb
156
158
  - spec/support/models/non_validated_issue.rb