arlequin 0.1.0 → 0.1.1

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 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: {}