bulletmark_repairer 0.1.4 → 0.1.6

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: 4b793a019d2937170c113a1b95eeea035a23e0f85a36f5c86382628467d3b006
4
- data.tar.gz: 0e513ae03aab2b2f21785d31be5141abe0a34759a16a97e41b32871caf01d531
3
+ metadata.gz: 5eabc96bcf1961f834090322c3b9a62173139f806513c5ec99d452f18a661c71
4
+ data.tar.gz: b55ab6f5adade690b6cb34ef92fc752bdfa697a3b8d7779d54150aaf4e1083bb
5
5
  SHA512:
6
- metadata.gz: bb0869546bfe5bd2c29586cffc2261f58680bb114a7f5dd01c0d4325df6736d49e24e743200285eb5cf199b87123e22bfe85cb8dce0eb2546d469e71fd98afd9
7
- data.tar.gz: 2ef8b880ef7e027b3a49a08638235a342ad8e8f1c7a35485f01f3c3cbbbb09b8cd4b75ec21b7522a2439e685833b05ed9488d3a75c916df8391453ea618f7aa8
6
+ metadata.gz: 714da7b74b7015194f965c83c1260d31b8a4f75b4f7a24b3038eac6c81ced4aa8a77a79abbe5a684a347093fbb00d0e9f1b05682729b96afe64ed2a83b110534
7
+ data.tar.gz: e48064688caaa2003d30192bfd2a76ff677fdcb4b4bb02bb8b828fece22b9fd5dab69a47aef2fb836a69e9f5b16db10d2c1faefcb9e249ba5b8a3df671310c03
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [0.1.6] - 2023-11-09
2
+
3
+ Fix a bug when N+1 is caused not in the request (e.g. Sidekiq) [51f051e](https://github.com/makicamel/bulletmark_repairer/commit/51f051e608b84b7da96ac879a324ed438c14eeeb)
4
+
5
+ ## [0.1.5] - 2023-10-27
6
+
7
+ Be able to patch for nested associations require `includes` though child associations are already included [d1b7445](https://github.com/makicamel/bulletmark_repairer/commit/d1b7445556c20bc037beb6a013ac70531426a7ea)
8
+
1
9
  ## [0.1.4] - 2023-10-22
2
10
 
3
11
  - Patch files other than controllers [218566d](https://github.com/makicamel/bulletmark_repairer/commit/218566d1531751f204941c3dcff7f095a056d39f)
data/README.md CHANGED
@@ -47,12 +47,12 @@ For example, the following cases are not supported as known cases currently:
47
47
 
48
48
  ```ruby
49
49
  def index
50
- # Nested associations require `includes` though child associations are already included
50
+ # Multiple nested associations require `includes` though child associations are already included
51
51
  @plays = Play.includes(:actors)
52
52
  # expected correct
53
- @plays = Play.includes(actors: [:company])
53
+ @plays = Play.includes(:actors).includes({:actors=>{:company=>[:offices]}})
54
54
  # actual correct
55
- @plays = Play.includes(:actors).includes([:company])
55
+ @plays = Play.includes(:actors).includes({:actors=>[:company]})
56
56
  end
57
57
  ```
58
58
 
@@ -10,7 +10,11 @@ module BulletmarkRepairer
10
10
  if associations[marker.index]
11
11
  associations[marker.index].add(marker)
12
12
  else
13
- associations[marker.index] = Associations.new(marker, @application_associations)
13
+ associations[marker.index] = Associations.new(
14
+ marker,
15
+ @application_associations,
16
+ @loaded_associations
17
+ )
14
18
  end
15
19
  end
16
20
 
@@ -20,8 +24,9 @@ module BulletmarkRepairer
20
24
 
21
25
  private
22
26
 
23
- def initialize
27
+ def initialize(loaded_associations)
24
28
  @application_associations = BulletmarkRepairer::ApplicationAssociations.new
29
+ @loaded_associations = BulletmarkRepairer::LoadedAssociations.new(loaded_associations)
25
30
  end
26
31
  end
27
32
 
@@ -44,10 +49,12 @@ module BulletmarkRepairer
44
49
 
45
50
  private
46
51
 
47
- def initialize(marker, application_associations)
52
+ def initialize(marker, application_associations, loaded_associations)
48
53
  @marker = marker
49
- @associations = { base: marker.associations }
50
54
  @application_associations = application_associations
55
+ @loaded_associations = loaded_associations
56
+ key = @loaded_associations.key(marker.base_class)
57
+ @associations = { base: key ? { key => marker.associations } : marker.associations }
51
58
  end
52
59
 
53
60
  # @return [Hash, nil]
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BulletmarkRepairer
4
+ class LoadedAssociations
5
+ attr_reader :associations
6
+
7
+ def key(target_klass_name)
8
+ key = target_klass_name.underscore
9
+
10
+ result = []
11
+ @associations.each do |_base_klass_name, all_associations|
12
+ all_associations.each do |_key, associations|
13
+ # TODO: reccurent check
14
+ associations.each do |values|
15
+ values.flatten.each do |value|
16
+ result.append search_key(key, value)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ result = result.flatten.compact.uniq.presence
22
+ build_keys(result)
23
+ end
24
+
25
+ private
26
+
27
+ def search_key(key, value)
28
+ case value
29
+ when Hash
30
+ search_key(key, value.keys) || search_key(key, value.values)
31
+ when Array
32
+ value.map { |v| search_key(key, v) }
33
+ else
34
+ if key.pluralize.to_sym == value
35
+ key.pluralize.to_sym
36
+ elsif key.singularize.to_sym == value
37
+ key.singularize.to_sym
38
+ end
39
+ end
40
+ end
41
+
42
+ def build_keys(keys)
43
+ return unless keys
44
+
45
+ if keys.size == 1
46
+ keys.first
47
+ else
48
+ { keys.first => keys.last }
49
+ end
50
+ end
51
+
52
+ def initialize(original_associations)
53
+ @associations = Hash.new { |h, k| h[k] = {} }
54
+ original_associations.each do |base_class, all_associations|
55
+ all_associations.each do |key, associations|
56
+ @associations[base_class][key] = associations.to_a
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BulletmarkRepairer
4
+ module ActiveRecord
5
+ module QueryMethod
6
+ def includes(*args)
7
+ BulletmarkRepairer::Thread.add(name: model.name, method_type: :includes, args: args)
8
+ super(args)
9
+ end
10
+
11
+ def eager_load(*args)
12
+ BulletmarkRepairer::Thread.add(name: model.name, method_type: :eager_load, args: args)
13
+ super(args)
14
+ end
15
+
16
+ def preload(*args)
17
+ BulletmarkRepairer::Thread.add(name: model.name, method_type: :preload, args: args)
18
+ super(args)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -6,8 +6,8 @@ require 'parser/runner/ruby_rewrite'
6
6
 
7
7
  module BulletmarkRepairer
8
8
  class Patcher
9
- def self.execute(notifications:, controller:, action:)
10
- new(notifications: notifications, controller: controller, action: action).execute
9
+ def self.execute(notifications:, controller:, action:, loaded_associations:)
10
+ new(notifications: notifications, controller: controller, action: action, loaded_associations: loaded_associations).execute
11
11
  end
12
12
 
13
13
  def execute
@@ -24,9 +24,9 @@ module BulletmarkRepairer
24
24
 
25
25
  private
26
26
 
27
- def initialize(notifications:, controller:, action:)
27
+ def initialize(notifications:, controller:, action:, loaded_associations:)
28
28
  @markers = Markers.new(notifications, controller: controller, action: action)
29
- @associations_builder = BulletmarkRepairer::AssociationsBuilder.new
29
+ @associations_builder = BulletmarkRepairer::AssociationsBuilder.new(loaded_associations)
30
30
  end
31
31
  end
32
32
  end
@@ -10,16 +10,18 @@ module BulletmarkRepairer
10
10
  @app.call(env)
11
11
  ensure
12
12
  begin
13
- if Thread.current[:bullet_notification_collector].notifications_present?
13
+ if ::Thread.current[:bullet_notification_collector].notifications_present?
14
14
  BulletmarkRepairer::Patcher.execute(
15
- notifications: Thread.current[:bullet_notification_collector],
15
+ notifications: ::Thread.current[:bullet_notification_collector],
16
16
  controller: env['action_dispatch.request.parameters']['controller'],
17
- action: env['action_dispatch.request.parameters']['action']
17
+ action: env['action_dispatch.request.parameters']['action'],
18
+ loaded_associations: BulletmarkRepairer::Thread.current
18
19
  )
19
20
  end
20
21
  rescue StandardError => e
21
22
  raise e if BulletmarkRepairer.config.debug?
22
23
  end
24
+ BulletmarkRepairer::Thread.clear
23
25
  end
24
26
  end
25
27
  end
@@ -9,5 +9,10 @@ module BulletmarkRepairer
9
9
  require 'bulletmark_repairer/rack'
10
10
  app.middleware.insert_after Bullet::Rack, BulletmarkRepairer::Rack
11
11
  end
12
+
13
+ ActiveSupport.on_load(:active_record) do
14
+ require 'bulletmark_repairer/monkey_patches/active_record/query_method'
15
+ ::ActiveRecord::Relation.prepend(BulletmarkRepairer::ActiveRecord::QueryMethod)
16
+ end
12
17
  end
13
18
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails'
4
+
5
+ module BulletmarkRepairer
6
+ class Thread
7
+ class << self
8
+ def current
9
+ touch
10
+ end
11
+
12
+ def add(name:, method_type:, args:)
13
+ touch
14
+ ::Thread.current[:bulletmark_repaier_loaded_associations][name][method_type].add(args)
15
+ end
16
+
17
+ def clear
18
+ ::Thread.current[:bulletmark_repaier_loaded_associations] = nil
19
+ end
20
+
21
+ private
22
+
23
+ def touch
24
+ ::Thread.current[:bulletmark_repaier_loaded_associations] ||= Hash.new do |hash, key|
25
+ hash[key] = { includes: Set.new, eager_load: Set.new, preload: Set.new }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BulletmarkRepairer
4
- VERSION = '0.1.4'
4
+ VERSION = '0.1.6'
5
5
  end
@@ -6,8 +6,10 @@ require 'bulletmark_repairer/application_associations'
6
6
  require 'bulletmark_repairer/associations_builder'
7
7
  require 'bulletmark_repairer/configuration'
8
8
  require 'bulletmark_repairer/corrector_builder'
9
+ require 'bulletmark_repairer/loaded_associations'
9
10
  require 'bulletmark_repairer/markers'
10
11
  require 'bulletmark_repairer/patcher'
12
+ require 'bulletmark_repairer/thread'
11
13
 
12
14
  module BulletmarkRepairer
13
15
  class Error < StandardError; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bulletmark_repairer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - makicamel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-22 00:00:00.000000000 Z
11
+ date: 2023-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -88,11 +88,14 @@ files:
88
88
  - lib/bulletmark_repairer/configuration.rb
89
89
  - lib/bulletmark_repairer/controller_corrector.rb
90
90
  - lib/bulletmark_repairer/corrector_builder.rb
91
+ - lib/bulletmark_repairer/loaded_associations.rb
91
92
  - lib/bulletmark_repairer/markers.rb
93
+ - lib/bulletmark_repairer/monkey_patches/active_record/query_method.rb
92
94
  - lib/bulletmark_repairer/patcher.rb
93
95
  - lib/bulletmark_repairer/rack.rb
94
96
  - lib/bulletmark_repairer/railtie.rb
95
97
  - lib/bulletmark_repairer/retry_corrector.rb
98
+ - lib/bulletmark_repairer/thread.rb
96
99
  - lib/bulletmark_repairer/version.rb
97
100
  - sig/bulletmark_repairer.rbs
98
101
  homepage: https://github.com/makicamel/bulletmark_repairer
@@ -118,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
121
  - !ruby/object:Gem::Version
119
122
  version: '0'
120
123
  requirements: []
121
- rubygems_version: 3.4.10
124
+ rubygems_version: 3.1.4
122
125
  signing_key:
123
126
  specification_version: 4
124
127
  summary: Auto corrector for N+1 queries detected at runtime with Bullet