bullet 8.0.0 → 8.0.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +25 -5
- data/lib/bullet/dependency.rb +6 -0
- data/lib/bullet/detector/association.rb +1 -1
- data/lib/bullet/detector/n_plus_one_query.rb +6 -5
- data/lib/bullet/ext/object.rb +10 -9
- data/lib/bullet/ext/string.rb +2 -1
- data/lib/bullet/mongoid9x.rb +72 -0
- data/lib/bullet/stack_trace_filter.rb +2 -4
- data/lib/bullet/version.rb +1 -1
- data/lib/bullet.rb +5 -4
- metadata +4 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69ace15062b915463985d5257ca7b054b482ca842f05f832dc45c1134bc7c8cd
|
4
|
+
data.tar.gz: a43533c8d894791edffcb4cbd9ad4ceba1dd238a8b736d23e3444ca7f766c57c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 262e12b9be4eeae23494a06eb71d6c6823674ecfa8ec9a0c5a5eaff7d7bf268a52cb35ee8198cf0712312745735bc4ad2a6474e3a6a5a6fa8820ed896754795a
|
7
|
+
data.tar.gz: b16503b483682cb94121442f8ee1d74145cb835031e62a864765629b0dbffd6b360136ee3b09f1b14d1e35a25794c06ace1579415829ad0dfdcff1ae2be0b3bf
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
## Next Release
|
2
2
|
|
3
|
+
## 8.0.2 (04/02/2025)
|
4
|
+
|
5
|
+
* Do not cache `bullet_key` if object is not persisted
|
6
|
+
|
7
|
+
## 8.0.1 (02/10/2025)
|
8
|
+
|
9
|
+
* Update benchmark to use sqlite
|
10
|
+
* Reduce mem allocations
|
11
|
+
* Require active_support's inflections module before requiring the delegation module
|
12
|
+
|
3
13
|
## 8.0.0 (11/10/2024)
|
4
14
|
|
5
15
|
* Support Rails 8
|
data/README.md
CHANGED
@@ -121,8 +121,6 @@ Bullet.unused_eager_loading_enable = false
|
|
121
121
|
Bullet.counter_cache_enable = false
|
122
122
|
```
|
123
123
|
|
124
|
-
Note: When calling `Bullet.enable`, all other detectors are reset to their defaults (`true`) and need reconfiguring.
|
125
|
-
|
126
124
|
## Safe list
|
127
125
|
|
128
126
|
Sometimes Bullet may notify you of query problems you don't care to fix, or
|
@@ -240,7 +238,7 @@ If your application generates a Content-Security-Policy via a separate middlewar
|
|
240
238
|
|
241
239
|
### Run in tests
|
242
240
|
|
243
|
-
First you need to enable Bullet in test environment.
|
241
|
+
First you need to enable Bullet in the test environment.
|
244
242
|
|
245
243
|
```ruby
|
246
244
|
# config/environments/test.rb
|
@@ -251,11 +249,13 @@ config.after_initialize do
|
|
251
249
|
end
|
252
250
|
```
|
253
251
|
|
254
|
-
Then wrap each test in Bullet api.
|
252
|
+
Then wrap each test in the Bullet api.
|
253
|
+
|
254
|
+
With RSpec:
|
255
255
|
|
256
256
|
```ruby
|
257
257
|
# spec/rails_helper.rb
|
258
|
-
|
258
|
+
RSpec.configure do |config|
|
259
259
|
config.before(:each) do
|
260
260
|
Bullet.start_request
|
261
261
|
end
|
@@ -267,6 +267,26 @@ if Bullet.enable?
|
|
267
267
|
end
|
268
268
|
```
|
269
269
|
|
270
|
+
With Minitest:
|
271
|
+
|
272
|
+
```ruby
|
273
|
+
# test/test_helper.rb
|
274
|
+
module ActiveSupport
|
275
|
+
class TestCase
|
276
|
+
def before_setup
|
277
|
+
Bullet.start_request
|
278
|
+
super
|
279
|
+
end
|
280
|
+
|
281
|
+
def after_teardown
|
282
|
+
super
|
283
|
+
Bullet.perform_out_of_channel_notifications if Bullet.notification?
|
284
|
+
Bullet.end_request
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
```
|
289
|
+
|
270
290
|
## Debug Mode
|
271
291
|
|
272
292
|
Bullet outputs some details info, to enable debug mode, set
|
data/lib/bullet/dependency.rb
CHANGED
@@ -56,6 +56,8 @@ module Bullet
|
|
56
56
|
'mongoid7x'
|
57
57
|
elsif mongoid8x?
|
58
58
|
'mongoid8x'
|
59
|
+
elsif mongoid9x?
|
60
|
+
'mongoid9x'
|
59
61
|
else
|
60
62
|
raise "Bullet does not support mongoid #{::Mongoid::VERSION} yet"
|
61
63
|
end
|
@@ -149,5 +151,9 @@ module Bullet
|
|
149
151
|
def mongoid8x?
|
150
152
|
mongoid? && ::Mongoid::VERSION =~ /\A8/
|
151
153
|
end
|
154
|
+
|
155
|
+
def mongoid9x?
|
156
|
+
mongoid? && ::Mongoid::VERSION =~ /\A9/
|
157
|
+
end
|
152
158
|
end
|
153
159
|
end
|
@@ -81,7 +81,7 @@ module Bullet
|
|
81
81
|
Thread.current.thread_variable_get(:bullet_eager_loadings)
|
82
82
|
end
|
83
83
|
|
84
|
-
#
|
84
|
+
# call_stacks keeps stacktraces where querie-objects were called from.
|
85
85
|
# e.g. { 'Object:111' => [SomeProject/app/controllers/...] }
|
86
86
|
def call_stacks
|
87
87
|
Thread.current.thread_variable_get(:bullet_call_stacks)
|
@@ -27,7 +27,7 @@ module Bullet
|
|
27
27
|
)
|
28
28
|
if !excluded_stacktrace_path? && conditions_met?(object, associations)
|
29
29
|
Bullet.debug('detect n + 1 query', "object: #{object.bullet_key}, associations: #{associations}")
|
30
|
-
create_notification
|
30
|
+
create_notification(caller_in_project(object.bullet_key), object.class.to_s, associations)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -38,16 +38,17 @@ module Bullet
|
|
38
38
|
objects = Array.wrap(object_or_objects)
|
39
39
|
class_names_match_regex = true
|
40
40
|
primary_key_values_are_empty = true
|
41
|
-
|
42
|
-
objects.
|
41
|
+
|
42
|
+
keys_joined = objects.map do |obj|
|
43
43
|
unless obj.class.name =~ /^HABTM_/
|
44
44
|
class_names_match_regex = false
|
45
45
|
end
|
46
46
|
unless obj.bullet_primary_key_value.nil?
|
47
47
|
primary_key_values_are_empty = false
|
48
48
|
end
|
49
|
-
|
50
|
-
end
|
49
|
+
obj.bullet_key
|
50
|
+
end.join(", ")
|
51
|
+
|
51
52
|
unless class_names_match_regex || primary_key_values_are_empty
|
52
53
|
Bullet.debug('Detector::NPlusOneQuery#add_possible_objects', "objects: #{keys_joined}")
|
53
54
|
objects.each { |object| possible_objects.add object.bullet_key }
|
data/lib/bullet/ext/object.rb
CHANGED
@@ -4,22 +4,23 @@ module Bullet
|
|
4
4
|
module Ext
|
5
5
|
module Object
|
6
6
|
refine ::Object do
|
7
|
+
attr_writer :bullet_key, :bullet_primary_key_value
|
8
|
+
|
7
9
|
def bullet_key
|
8
|
-
"#{self.class}
|
10
|
+
return "#{self.class}:" if respond_to?(:persisted?) && !persisted?
|
11
|
+
|
12
|
+
@bullet_key ||= "#{self.class}:#{bullet_primary_key_value}"
|
9
13
|
end
|
10
14
|
|
11
15
|
def bullet_primary_key_value
|
12
16
|
return if respond_to?(:persisted?) && !persisted?
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
primary_key = self.class.primary_key
|
18
|
-
else
|
19
|
-
primary_key = :id
|
20
|
-
end
|
18
|
+
@bullet_primary_key_value ||=
|
19
|
+
begin
|
20
|
+
primary_key = self.class.try(:primary_keys) || self.class.try(:primary_key) || :id
|
21
21
|
|
22
|
-
|
22
|
+
bullet_join_potential_composite_primary_key(primary_key)
|
23
|
+
end
|
23
24
|
end
|
24
25
|
|
25
26
|
private
|
data/lib/bullet/ext/string.rb
CHANGED
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bullet
|
4
|
+
module Mongoid
|
5
|
+
def self.enable
|
6
|
+
require 'mongoid'
|
7
|
+
require 'rubygems'
|
8
|
+
::Mongoid::Contextual::Mongo.class_eval do
|
9
|
+
alias_method :origin_first, :first
|
10
|
+
alias_method :origin_last, :last
|
11
|
+
alias_method :origin_each, :each
|
12
|
+
alias_method :origin_eager_load, :eager_load
|
13
|
+
|
14
|
+
%i[first last].each do |context|
|
15
|
+
default = Gem::Version.new(::Mongoid::VERSION) >= Gem::Version.new('7.5') ? nil : {}
|
16
|
+
define_method(context) do |opts = default|
|
17
|
+
result = send(:"origin_#{context}", opts)
|
18
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
|
19
|
+
result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def each(&_block)
|
24
|
+
return to_enum unless block_given?
|
25
|
+
|
26
|
+
first_document = nil
|
27
|
+
document_count = 0
|
28
|
+
|
29
|
+
origin_each do |document|
|
30
|
+
document_count += 1
|
31
|
+
|
32
|
+
if document_count == 1
|
33
|
+
first_document = document
|
34
|
+
elsif document_count == 2
|
35
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects([first_document, document])
|
36
|
+
yield(first_document)
|
37
|
+
first_document = nil
|
38
|
+
yield(document)
|
39
|
+
else
|
40
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(document)
|
41
|
+
yield(document)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if document_count == 1
|
46
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(first_document)
|
47
|
+
yield(first_document)
|
48
|
+
end
|
49
|
+
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def eager_load(docs)
|
54
|
+
associations = criteria.inclusions.map(&:name)
|
55
|
+
docs.each { |doc| Bullet::Detector::NPlusOneQuery.add_object_associations(doc, associations) }
|
56
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(docs, associations)
|
57
|
+
origin_eager_load(docs)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
::Mongoid::Association::Accessors.class_eval do
|
62
|
+
alias_method :origin_get_relation, :get_relation
|
63
|
+
|
64
|
+
def get_relation(name, association, object, reload = false)
|
65
|
+
result = origin_get_relation(name, association, object, reload)
|
66
|
+
Bullet::Detector::NPlusOneQuery.call_association(self, name) unless association.embedded?
|
67
|
+
result
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -7,7 +7,6 @@ using Bullet::Ext::Object
|
|
7
7
|
module Bullet
|
8
8
|
module StackTraceFilter
|
9
9
|
VENDOR_PATH = '/vendor'
|
10
|
-
IS_RUBY_19 = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0')
|
11
10
|
|
12
11
|
# @param bullet_key[String] - use this to get stored call stack from call_stacks object.
|
13
12
|
def caller_in_project(bullet_key = nil)
|
@@ -56,13 +55,12 @@ module Bullet
|
|
56
55
|
def location_as_path(location)
|
57
56
|
return location if location.is_a?(String)
|
58
57
|
|
59
|
-
|
58
|
+
location.absolute_path.to_s
|
60
59
|
end
|
61
60
|
|
62
61
|
def select_caller_locations(bullet_key = nil)
|
63
|
-
return caller.select { |caller_path| yield caller_path } if IS_RUBY_19
|
64
|
-
|
65
62
|
call_stack = bullet_key ? call_stacks[bullet_key] : caller_locations
|
63
|
+
|
66
64
|
call_stack.select { |location| yield location }
|
67
65
|
end
|
68
66
|
end
|
data/lib/bullet/version.rb
CHANGED
data/lib/bullet.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
3
4
|
require 'active_support/core_ext/module/delegation'
|
4
5
|
require 'set'
|
5
6
|
require 'uniform_notifier'
|
@@ -63,7 +64,7 @@ module Bullet
|
|
63
64
|
].freeze
|
64
65
|
|
65
66
|
def enable=(enable)
|
66
|
-
@enable =
|
67
|
+
@enable = enable
|
67
68
|
|
68
69
|
if enable?
|
69
70
|
reset_safelist
|
@@ -89,15 +90,15 @@ module Bullet
|
|
89
90
|
end
|
90
91
|
|
91
92
|
def n_plus_one_query_enable?
|
92
|
-
enable? &&
|
93
|
+
enable? && (@n_plus_one_query_enable.nil? ? true : @n_plus_one_query_enable)
|
93
94
|
end
|
94
95
|
|
95
96
|
def unused_eager_loading_enable?
|
96
|
-
enable? &&
|
97
|
+
enable? && (@unused_eager_loading_enable.nil? ? true : @unused_eager_loading_enable)
|
97
98
|
end
|
98
99
|
|
99
100
|
def counter_cache_enable?
|
100
|
-
enable? &&
|
101
|
+
enable? && (@counter_cache_enable.nil? ? true : @counter_cache_enable)
|
101
102
|
end
|
102
103
|
|
103
104
|
def stacktrace_includes
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.0.
|
4
|
+
version: 8.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Huang
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-04-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: activesupport
|
@@ -76,6 +75,7 @@ files:
|
|
76
75
|
- lib/bullet/mongoid6x.rb
|
77
76
|
- lib/bullet/mongoid7x.rb
|
78
77
|
- lib/bullet/mongoid8x.rb
|
78
|
+
- lib/bullet/mongoid9x.rb
|
79
79
|
- lib/bullet/notification.rb
|
80
80
|
- lib/bullet/notification/base.rb
|
81
81
|
- lib/bullet/notification/counter_cache.rb
|
@@ -98,7 +98,6 @@ licenses:
|
|
98
98
|
metadata:
|
99
99
|
changelog_uri: https://github.com/flyerhzm/bullet/blob/main/CHANGELOG.md
|
100
100
|
source_code_uri: https://github.com/flyerhzm/bullet
|
101
|
-
post_install_message:
|
102
101
|
rdoc_options: []
|
103
102
|
require_paths:
|
104
103
|
- lib
|
@@ -113,8 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
112
|
- !ruby/object:Gem::Version
|
114
113
|
version: 1.3.6
|
115
114
|
requirements: []
|
116
|
-
rubygems_version: 3.
|
117
|
-
signing_key:
|
115
|
+
rubygems_version: 3.6.2
|
118
116
|
specification_version: 4
|
119
117
|
summary: help to kill N+1 queries and unused eager loading.
|
120
118
|
test_files: []
|