arlequin 0.1.0 → 0.1.1

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: 64dab272387e862b66546a8de88779cc36ffbdfaa0a6082125b8404509fec181
4
- data.tar.gz: 0c1d6fe9c4af985484476e81645ce54a1a1391ed19765276dd9d1915bc12b514
3
+ metadata.gz: c730c5e938ae2adf97538d4d30c69118a6dc4a9f8c290ed476cb8ea7d9115975
4
+ data.tar.gz: c815726ab257c2c478f55783ca90e1e7a5f948b819099fc607ffad1114336cfb
5
5
  SHA512:
6
- metadata.gz: 6dab0e3d89077eccf1a50591045e75720bade0b638ff4ab5c2e892c7297b6b12c314cdb25047094b50ac4a45895e18ebb6e2a742409dc290cb7d8620fa911995
7
- data.tar.gz: 194ba82a1169e3abec5d4114bd1fae8e3c51b169103f8ae3c2ae8fea8cb4bedc596e0681fbb75840fa6b94f0ea34e1e8acf431eb71e6ddf5efb9097fca91f503
6
+ metadata.gz: 726f9a8bb3f4c94aca726b43cdf3aa4bb09101122690ce78eab7ac90fa0ba34b4a2a222e39f6ebad1e9cb3f94f72f4b3fb9aa79ba2b8dcf889538f6db35af5e0
7
+ data.tar.gz: b87de6cdb5c012cb6471a5b6497f3f6cb765774fe4f87ab6837ed496f07b32b106971a0fe5d6b473041a592a0d42c220afc85602102987b783d10345d77daeb4
@@ -1,40 +1,107 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Arlequin
4
+ ##
5
+ # Middleware to detect and warn about N+1 queries in a Rails application.
4
6
  class Middleware
7
+ ##
8
+ # Initializes the middleware with the given app.
9
+ #
10
+ # @param app [Object] The Rack application this middleware wraps.
5
11
  def initialize(app)
6
12
  @app = app
7
13
  end
8
14
 
15
+ ##
16
+ # Processes the incoming request, detects N+1 queries, and injects a warning
17
+ # into the HTML response if necessary.
18
+ #
19
+ # @param env [Hash] The Rack environment.
20
+ # @return [Array] The status, headers, and response of the Rack application.
9
21
  def call(env)
10
- # Set up a query counter
11
22
  @queries = Hash.new { |hash, key| hash[key] = 0 }
12
-
13
23
  ActiveSupport::Notifications.subscribe("sql.active_record", &method(:on_sql))
14
24
 
15
25
  status, headers, response = @app.call(env)
16
26
 
17
- # Detect and log N+1 queries
18
- log_n_plus_one_warnings
27
+ if n_plus_one_detected?
28
+ html_fragment = generate_html_warning
29
+ response = inject_html_fragment(response, html_fragment)
30
+ end
31
+
32
+ ActiveSupport::Notifications.unsubscribe("sql.active_record")
19
33
 
20
34
  [ status, headers, response ]
21
35
  end
22
36
 
23
37
  private
24
38
 
39
+ ##
40
+ # Callback for ActiveSupport notifications on SQL queries.
41
+ #
42
+ # @param _name [String] The event name.
43
+ # @param _start [Time] The start time of the event.
44
+ # @param _finish [Time] The finish time of the event.
45
+ # @param _id [String] The event ID.
46
+ # @param payload [Hash] The event payload containing SQL information.
25
47
  def on_sql(_name, _start, _finish, _id, payload)
26
- return if payload[:name] == "SCHEMA" # Skip schema queries
48
+ return if payload[:name] == "SCHEMA"
27
49
 
28
50
  query = payload[:sql]
29
51
  @queries[query] += 1
30
52
  end
31
53
 
32
- def log_n_plus_one_warnings
54
+ ##
55
+ # Generates warnings for detected N+1 queries.
56
+ #
57
+ # @return [Array<String>] The list of N+1 query warnings.
58
+ def n_plus_one_warnings
59
+ warnings = []
60
+
33
61
  @queries.each do |query, count|
34
62
  if count > 1
35
- Rails.logger.warn("N+1 query detected: #{query}, executed #{count} times")
63
+ warnings << "N+1 query detected: #{query}, executed #{count} times"
36
64
  end
37
65
  end
66
+
67
+ warnings
68
+ end
69
+
70
+ ##
71
+ # Checks if any N+1 queries have been detected.
72
+ #
73
+ # @return [Boolean] True if N+1 queries are detected, otherwise false.
74
+ def n_plus_one_detected?
75
+ @queries.values.any? { |count| count > 1 }
76
+ end
77
+
78
+ ##
79
+ # Generates an HTML warning for detected N+1 queries.
80
+ #
81
+ # @return [String] The HTML warning to be injected into the response.
82
+ def generate_html_warning
83
+ "<div style='z-index: 9999; position: fixed; bottom: 0; left: 0; width: 100%; background-color: blue; color: white; text-align: center; padding: 5px;'>" +
84
+ "N+1 query detected! Check your queries. " +
85
+ n_plus_one_warnings.join("<br>") +
86
+ "</div>"
87
+ end
88
+
89
+ ##
90
+ # Injects an HTML fragment into the response body.
91
+ #
92
+ # @param response [Array<String>] The original response body.
93
+ # @param fragment [String] The HTML fragment to inject.
94
+ # @return [Array<String>] The modified response body.
95
+ def inject_html_fragment(response, fragment)
96
+ body = + ""
97
+
98
+ response.each do |part|
99
+ body << part
100
+ end
101
+
102
+ body.sub!("</body>", "#{fragment}</body>")
103
+
104
+ [ body ]
38
105
  end
39
106
  end
40
107
  end
data/lib/arlequin.rb CHANGED
@@ -1,7 +1,56 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Arlequin
3
+ require "active_support/all"
4
+ require "arlequin/middleware"
5
+
6
+ module Arlequin
7
+ # The `Railtie` class integrates the Arlequin middleware into Rails applications.
8
+ #
9
+ # This Railtie automatically adds the Arlequin middleware to the Rails middleware stack,
10
+ # but it is intended to be used only in the development environment. It helps in monitoring
11
+ # and providing warnings about N+1 SQL queries during development.
12
+ #
13
+ # ## Configuration
14
+ #
15
+ # To use Arlequin in your Rails application, you should include it in the development group
16
+ # of your Gemfile and require it in the application configuration.
17
+ #
18
+ # Example Gemfile configuration:
19
+ #
20
+ # group :development do
21
+ # gem 'arlequin'
22
+ # end
23
+ #
24
+ # To ensure the middleware is used in development, require the Railtie in your application:
25
+ #
26
+ # # In `config/application.rb`
27
+ # require "arlequin/railtie"
28
+ #
29
+ # module YourApp
30
+ # class Application < Rails::Application
31
+ # # other configurations
32
+ # # Ensure that the Railtie is required
33
+ # end
34
+ # end
35
+ #
36
+ # This setup will automatically add the Arlequin middleware to the middleware stack
37
+ # when running in development mode. The middleware will then be used to detect and
38
+ # provide warnings for N+1 SQL queries.
39
+ #
40
+ # ## Usage
41
+ #
42
+ # Once configured, the Arlequin middleware will monitor SQL queries and inject a warning
43
+ # into the response HTML if N+1 queries are detected.
44
+ #
45
+ # The Railtie is part of the Arlequin gem and is designed to integrate seamlessly into
46
+ # Rails applications for development purposes, facilitating easier identification and
47
+ # resolution of N+1 query issues.
4
48
  class Railtie < Rails::Railtie
49
+ # Initializes the Railtie and configures the Rails application to use the Arlequin middleware.
50
+ #
51
+ # This method is called during the initialization process of the Rails application.
52
+ # It adds the Arlequin middleware to the middleware stack in development environments,
53
+ # allowing it to intercept requests and monitor SQL queries.
5
54
  initializer "arlequin.configure_rails_initialization" do |app|
6
55
  app.middleware.use Arlequin::Middleware
7
56
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arlequin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominic Goulet
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-10 00:00:00.000000000 Z
11
+ date: 2024-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -32,7 +32,7 @@ extra_rdoc_files: []
32
32
  files:
33
33
  - lib/arlequin.rb
34
34
  - lib/arlequin/middleware.rb
35
- homepage: https://rubygems.org/gems/arlequin
35
+ homepage: https://github.com/dominicgoulet/arlequin
36
36
  licenses:
37
37
  - MIT
38
38
  metadata: {}