QueryWise 0.2.3 → 1.0.0
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/INSTALLATION.md +197 -0
- data/README.md +13 -3
- data/lib/generators/query_wise/install_generator.rb +47 -0
- data/lib/generators/query_wise/templates/README +46 -0
- data/lib/generators/query_wise/templates/analysis_job.rb +84 -0
- data/lib/generators/query_wise/templates/initializer.rb +30 -0
- data/lib/generators/query_wise_generator.rb +45 -0
- data/lib/query_optimizer_client/generators/install_generator.rb +9 -3
- data/lib/query_optimizer_client/install.rb +132 -0
- data/lib/query_optimizer_client/railtie.rb +1 -1
- data/lib/query_optimizer_client/tasks.rake +6 -0
- data/lib/query_optimizer_client/version.rb +1 -1
- data/lib/query_optimizer_client.rb +1 -1
- data/query_optimizer_client.gemspec +1 -0
- metadata +26 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1054fa9e712ee211b953b341da4a29183c85b3dd0aa4303818e6b300b15bde04
|
4
|
+
data.tar.gz: b08cacfd54a45d587e4ae6e0bdcb720f74359d96eb1dba9c9ad0c4f5ef245b89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba2c980bcd16e9bee22c30bb51e09674c0cd2d88d3c194aa9b7736f903e8278b9ba6e519052f5cd08fc77e5fe2e9bcef0720d86bef359e6c50f36cb13966ae22
|
7
|
+
data.tar.gz: a18e469a91d16e9e5923e7f75f67081a16bde822cfaa0828f56540685614a2a72260a4dafdac7c82a7b0cdf06d236a751540bf94d8dff451f0757e31dd23f863
|
data/INSTALLATION.md
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
# QueryWise Installation Guide
|
2
|
+
|
3
|
+
This guide provides step-by-step instructions for integrating QueryWise into your Rails application.
|
4
|
+
|
5
|
+
## Quick Start
|
6
|
+
|
7
|
+
### 1. Add to Gemfile
|
8
|
+
|
9
|
+
Add QueryWise to your Rails application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'QueryWise'
|
13
|
+
```
|
14
|
+
|
15
|
+
Then run:
|
16
|
+
|
17
|
+
```bash
|
18
|
+
bundle install
|
19
|
+
```
|
20
|
+
|
21
|
+
### 2. Run Installation Script
|
22
|
+
|
23
|
+
QueryWise provides an easy installation script that sets up all necessary configuration files:
|
24
|
+
|
25
|
+
```bash
|
26
|
+
# Option 1: Using the bundled script
|
27
|
+
bundle exec ruby -e "require 'query_optimizer_client/install'; QueryOptimizerClient::Install.run"
|
28
|
+
|
29
|
+
# Option 2: Using rake task (if available)
|
30
|
+
bundle exec rake query_optimizer:install
|
31
|
+
|
32
|
+
# Option 3: Download and run the standalone script
|
33
|
+
curl -fsSL https://raw.githubusercontent.com/your-username/QueryWise/main/bin/query_wise_install | ruby
|
34
|
+
```
|
35
|
+
|
36
|
+
### 3. Configure Your API Credentials
|
37
|
+
|
38
|
+
Update the generated `.env` file with your API credentials:
|
39
|
+
|
40
|
+
```bash
|
41
|
+
# .env
|
42
|
+
QUERY_OPTIMIZER_API_URL=https://your-api-endpoint.com/api/v1
|
43
|
+
QUERY_OPTIMIZER_API_KEY=your_api_key_here
|
44
|
+
QUERY_OPTIMIZER_ENABLED=true
|
45
|
+
```
|
46
|
+
|
47
|
+
### 4. Restart Your Rails Server
|
48
|
+
|
49
|
+
```bash
|
50
|
+
rails server
|
51
|
+
```
|
52
|
+
|
53
|
+
## What Gets Installed
|
54
|
+
|
55
|
+
The installation script creates the following files:
|
56
|
+
|
57
|
+
### Configuration Files
|
58
|
+
|
59
|
+
1. **`config/initializers/query_optimizer_client.rb`** - Main configuration
|
60
|
+
2. **`.env.example`** - Environment variables template
|
61
|
+
3. **`.env`** - Your environment variables (if it doesn't exist)
|
62
|
+
|
63
|
+
### Background Job
|
64
|
+
|
65
|
+
4. **`app/jobs/query_optimizer_client/analysis_job.rb`** - Background job for query analysis
|
66
|
+
|
67
|
+
## Manual Installation
|
68
|
+
|
69
|
+
If you prefer to set up the files manually:
|
70
|
+
|
71
|
+
### 1. Create Initializer
|
72
|
+
|
73
|
+
Create `config/initializers/query_optimizer_client.rb`:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
# frozen_string_literal: true
|
77
|
+
|
78
|
+
QueryOptimizerClient.configure do |config|
|
79
|
+
# API Configuration
|
80
|
+
config.api_url = ENV.fetch('QUERY_OPTIMIZER_API_URL', 'https://your-api-url.com/api/v1')
|
81
|
+
config.api_key = ENV.fetch('QUERY_OPTIMIZER_API_KEY', nil)
|
82
|
+
|
83
|
+
# Feature toggles
|
84
|
+
config.enabled = ENV.fetch('QUERY_OPTIMIZER_ENABLED', 'true') == 'true'
|
85
|
+
config.auto_analyze = ENV.fetch('QUERY_OPTIMIZER_AUTO_ANALYZE', 'false') == 'true'
|
86
|
+
|
87
|
+
# Performance thresholds
|
88
|
+
config.slow_query_threshold = ENV.fetch('QUERY_OPTIMIZER_THRESHOLD', '100').to_i
|
89
|
+
|
90
|
+
# Logging
|
91
|
+
config.log_level = ENV.fetch('QUERY_OPTIMIZER_LOG_LEVEL', 'info').to_sym
|
92
|
+
|
93
|
+
# Analysis settings
|
94
|
+
config.batch_size = ENV.fetch('QUERY_OPTIMIZER_BATCH_SIZE', '10').to_i
|
95
|
+
config.analysis_interval = ENV.fetch('QUERY_OPTIMIZER_ANALYSIS_INTERVAL', '300').to_i
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
### 2. Create Background Job
|
100
|
+
|
101
|
+
Create `app/jobs/query_optimizer_client/analysis_job.rb`:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
# frozen_string_literal: true
|
105
|
+
|
106
|
+
module QueryOptimizerClient
|
107
|
+
class AnalysisJob < ApplicationJob
|
108
|
+
queue_as :default
|
109
|
+
|
110
|
+
def perform(queries)
|
111
|
+
return unless QueryOptimizerClient.configuration.enabled?
|
112
|
+
|
113
|
+
client = QueryOptimizerClient.client
|
114
|
+
|
115
|
+
begin
|
116
|
+
result = client.analyze_queries(queries)
|
117
|
+
Rails.logger.info "Query analysis completed: #{result.inspect}"
|
118
|
+
rescue => e
|
119
|
+
Rails.logger.error "Query analysis failed: #{e.message}"
|
120
|
+
raise e
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
### 3. Add Environment Variables
|
128
|
+
|
129
|
+
Add to your `.env` file:
|
130
|
+
|
131
|
+
```bash
|
132
|
+
# Query Optimizer Client Configuration
|
133
|
+
QUERY_OPTIMIZER_API_URL=https://your-api-url.com/api/v1
|
134
|
+
QUERY_OPTIMIZER_API_KEY=your_api_key_here
|
135
|
+
QUERY_OPTIMIZER_ENABLED=true
|
136
|
+
QUERY_OPTIMIZER_AUTO_ANALYZE=false
|
137
|
+
QUERY_OPTIMIZER_THRESHOLD=100
|
138
|
+
QUERY_OPTIMIZER_LOG_LEVEL=info
|
139
|
+
QUERY_OPTIMIZER_BATCH_SIZE=10
|
140
|
+
QUERY_OPTIMIZER_ANALYSIS_INTERVAL=300
|
141
|
+
```
|
142
|
+
|
143
|
+
## Configuration Options
|
144
|
+
|
145
|
+
| Environment Variable | Default | Description |
|
146
|
+
|---------------------|---------|-------------|
|
147
|
+
| `QUERY_OPTIMIZER_API_URL` | - | Your QueryWise API endpoint |
|
148
|
+
| `QUERY_OPTIMIZER_API_KEY` | - | Your API key |
|
149
|
+
| `QUERY_OPTIMIZER_ENABLED` | `true` | Enable/disable the client |
|
150
|
+
| `QUERY_OPTIMIZER_AUTO_ANALYZE` | `false` | Automatically analyze queries |
|
151
|
+
| `QUERY_OPTIMIZER_THRESHOLD` | `100` | Slow query threshold (ms) |
|
152
|
+
| `QUERY_OPTIMIZER_LOG_LEVEL` | `info` | Logging level |
|
153
|
+
| `QUERY_OPTIMIZER_BATCH_SIZE` | `10` | Batch size for analysis |
|
154
|
+
| `QUERY_OPTIMIZER_ANALYSIS_INTERVAL` | `300` | Analysis interval (seconds) |
|
155
|
+
|
156
|
+
## Verification
|
157
|
+
|
158
|
+
After installation, you can verify everything is working:
|
159
|
+
|
160
|
+
```bash
|
161
|
+
# Check configuration status
|
162
|
+
bundle exec rake query_optimizer:check
|
163
|
+
|
164
|
+
# Test API connection
|
165
|
+
bundle exec rake query_optimizer:analyze
|
166
|
+
```
|
167
|
+
|
168
|
+
## Troubleshooting
|
169
|
+
|
170
|
+
### Installation Issues
|
171
|
+
|
172
|
+
1. **Permission errors**: Make sure you have write permissions in your Rails app directory
|
173
|
+
2. **Missing directories**: The script will create necessary directories automatically
|
174
|
+
3. **Existing files**: The script won't overwrite existing configuration files
|
175
|
+
|
176
|
+
### Configuration Issues
|
177
|
+
|
178
|
+
1. **API connection fails**: Check your API URL and key
|
179
|
+
2. **Queries not being analyzed**: Ensure `QUERY_OPTIMIZER_ENABLED=true`
|
180
|
+
3. **Background jobs not running**: Check your job queue configuration
|
181
|
+
|
182
|
+
## Next Steps
|
183
|
+
|
184
|
+
After installation:
|
185
|
+
|
186
|
+
1. [Configure your middleware](MIDDLEWARE.md)
|
187
|
+
2. [Set up automatic analysis](ANALYSIS.md)
|
188
|
+
3. [Customize optimization rules](CONFIGURATION.md)
|
189
|
+
4. [Monitor performance](MONITORING.md)
|
190
|
+
|
191
|
+
## Support
|
192
|
+
|
193
|
+
If you encounter any issues during installation:
|
194
|
+
|
195
|
+
1. Check the [troubleshooting guide](TROUBLESHOOTING.md)
|
196
|
+
2. Review the [configuration documentation](CONFIGURATION.md)
|
197
|
+
3. Open an issue on [GitHub](https://github.com/your-username/QueryWise/issues)
|
data/README.md
CHANGED
@@ -35,16 +35,26 @@ bundle install
|
|
35
35
|
|
36
36
|
### Step 2: Generate Configuration Files (1 minute)
|
37
37
|
|
38
|
-
Run the installation
|
38
|
+
Run the installation command:
|
39
39
|
|
40
40
|
```bash
|
41
|
-
|
41
|
+
# Option 1: Ruby command (recommended)
|
42
|
+
bundle exec ruby -e "require 'query_optimizer_client/install'; QueryOptimizerClient::Install.run"
|
43
|
+
|
44
|
+
# Option 2: Rake task
|
45
|
+
bundle exec rake query_optimizer:install
|
46
|
+
|
47
|
+
# Option 3: Standalone script
|
48
|
+
curl -fsSL https://raw.githubusercontent.com/your-username/QueryWise/main/bin/query_wise_install | ruby
|
42
49
|
```
|
43
50
|
|
44
51
|
This creates:
|
45
52
|
- `config/initializers/query_optimizer_client.rb` - Configuration file
|
46
53
|
- `app/jobs/query_optimizer_client/analysis_job.rb` - Background job
|
47
|
-
- `.env`
|
54
|
+
- `.env.example` - Environment variables template
|
55
|
+
- Updates your `.env` file with configuration options
|
56
|
+
|
57
|
+
> **Note**: The `rails generate QueryWise:install` command is not currently supported due to Rails generator namespace complexities. Use the methods above instead. For detailed installation instructions, see [INSTALLATION.md](INSTALLATION.md).
|
48
58
|
|
49
59
|
### Step 3: Set Up API Connection (5 minutes)
|
50
60
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
|
5
|
+
module QueryWise
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
7
|
+
desc "Install QueryWise"
|
8
|
+
|
9
|
+
source_root File.expand_path('templates', __dir__)
|
10
|
+
|
11
|
+
def create_initializer
|
12
|
+
template 'initializer.rb', 'config/initializers/query_optimizer_client.rb'
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_job
|
16
|
+
template 'analysis_job.rb', 'app/jobs/query_optimizer_client/analysis_job.rb'
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_environment_variables
|
20
|
+
environment_template = <<~ENV
|
21
|
+
# Query Optimizer Client Configuration
|
22
|
+
# QUERY_OPTIMIZER_API_URL=http://localhost:3000/api/v1
|
23
|
+
# QUERY_OPTIMIZER_API_KEY=your_api_key_here
|
24
|
+
# QUERY_OPTIMIZER_ENABLED=true
|
25
|
+
# QUERY_OPTIMIZER_THRESHOLD=80
|
26
|
+
ENV
|
27
|
+
|
28
|
+
# Create or append to .env.example
|
29
|
+
if File.exist?('.env.example')
|
30
|
+
append_to_file '.env.example', environment_template
|
31
|
+
else
|
32
|
+
create_file '.env.example', environment_template
|
33
|
+
end
|
34
|
+
|
35
|
+
# Create or append to .env
|
36
|
+
if File.exist?('.env')
|
37
|
+
append_to_file '.env', environment_template
|
38
|
+
else
|
39
|
+
create_file '.env', environment_template
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def show_readme
|
44
|
+
readme 'README'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
===============================================================================
|
2
|
+
|
3
|
+
QueryWise has been installed!
|
4
|
+
|
5
|
+
===============================================================================
|
6
|
+
|
7
|
+
Next steps:
|
8
|
+
|
9
|
+
1. Set up your environment variables:
|
10
|
+
|
11
|
+
Add to your .env file:
|
12
|
+
QUERY_OPTIMIZER_API_URL=http://localhost:3000/api/v1
|
13
|
+
QUERY_OPTIMIZER_API_KEY=your_api_key_here
|
14
|
+
QUERY_OPTIMIZER_ENABLED=true
|
15
|
+
|
16
|
+
2. Generate an API key (if you don't have one):
|
17
|
+
|
18
|
+
rails query_optimizer:generate_key["My App Name"]
|
19
|
+
|
20
|
+
3. Test your configuration:
|
21
|
+
|
22
|
+
rails query_optimizer:check
|
23
|
+
|
24
|
+
4. Run a sample analysis:
|
25
|
+
|
26
|
+
rails query_optimizer:analyze
|
27
|
+
|
28
|
+
5. Set up CI/CD integration:
|
29
|
+
|
30
|
+
Add to your CI pipeline:
|
31
|
+
rails query_optimizer:ci[85]
|
32
|
+
|
33
|
+
6. Customize the configuration in:
|
34
|
+
|
35
|
+
config/initializers/query_optimizer_client.rb
|
36
|
+
|
37
|
+
7. Optional: Customize the analysis job in:
|
38
|
+
|
39
|
+
app/jobs/query_optimizer_client/analysis_job.rb
|
40
|
+
|
41
|
+
===============================================================================
|
42
|
+
|
43
|
+
For more information, visit:
|
44
|
+
https://github.com/yourusername/query_optimizer_client
|
45
|
+
|
46
|
+
===============================================================================
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module QueryOptimizerClient
|
4
|
+
class AnalysisJob < ApplicationJob
|
5
|
+
queue_as :default
|
6
|
+
|
7
|
+
def perform(queries, endpoint = nil)
|
8
|
+
return unless QueryOptimizerClient.enabled?
|
9
|
+
|
10
|
+
result = QueryOptimizerClient.analyze_queries(queries)
|
11
|
+
|
12
|
+
return unless result&.dig('success')
|
13
|
+
|
14
|
+
data = result['data']
|
15
|
+
score = data['summary']['optimization_score']
|
16
|
+
|
17
|
+
# Log analysis results
|
18
|
+
log_analysis_results(data, endpoint)
|
19
|
+
|
20
|
+
# Store results (optional - implement based on your needs)
|
21
|
+
store_analysis_results(data, endpoint) if respond_to?(:store_analysis_results, true)
|
22
|
+
|
23
|
+
# Send alerts if performance is poor
|
24
|
+
send_alerts(data, endpoint, score) if score < 70
|
25
|
+
|
26
|
+
rescue => e
|
27
|
+
Rails.logger.error "Query analysis failed: #{e.message}"
|
28
|
+
Rails.logger.error e.backtrace.join("\n") if Rails.env.development?
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def log_analysis_results(data, endpoint)
|
34
|
+
endpoint_info = endpoint ? " on #{endpoint}" : ""
|
35
|
+
|
36
|
+
Rails.logger.info "Query analysis completed#{endpoint_info}: Score #{data['summary']['optimization_score']}%, #{data['summary']['issues_found']} issues found"
|
37
|
+
|
38
|
+
# Log N+1 queries
|
39
|
+
if data['n_plus_one']['detected']
|
40
|
+
Rails.logger.warn "N+1 queries detected#{endpoint_info}:"
|
41
|
+
data['n_plus_one']['patterns'].each do |pattern|
|
42
|
+
Rails.logger.warn " - #{pattern['table']}.#{pattern['column']}: #{pattern['suggestion']}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Log slow queries
|
47
|
+
data['slow_queries'].each do |query|
|
48
|
+
Rails.logger.warn "Slow query#{endpoint_info} (#{query['duration_ms']}ms): #{query['sql'][0..100]}..."
|
49
|
+
query['suggestions'].each do |suggestion|
|
50
|
+
Rails.logger.warn " 💡 #{suggestion}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Log missing indexes
|
55
|
+
data['missing_indexes'].each do |index|
|
56
|
+
Rails.logger.info "Missing index suggestion#{endpoint_info}: #{index['sql']}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def send_alerts(data, endpoint, score)
|
61
|
+
endpoint_info = endpoint ? " on #{endpoint}" : ""
|
62
|
+
|
63
|
+
if score < 50
|
64
|
+
Rails.logger.error "🚨 CRITICAL: Very low performance score (#{score}%)#{endpoint_info}"
|
65
|
+
# Add your critical alerting logic here (Slack, email, etc.)
|
66
|
+
elsif score < 70
|
67
|
+
Rails.logger.warn "⚠️ WARNING: Low performance score (#{score}%)#{endpoint_info}"
|
68
|
+
# Add your warning alerting logic here
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Optional: Implement this method to store analysis results in your database
|
73
|
+
# def store_analysis_results(data, endpoint)
|
74
|
+
# PerformanceAnalysis.create!(
|
75
|
+
# endpoint: endpoint,
|
76
|
+
# optimization_score: data['summary']['optimization_score'],
|
77
|
+
# issues_found: data['summary']['issues_found'],
|
78
|
+
# total_queries: data['summary']['total_queries'],
|
79
|
+
# analysis_data: data,
|
80
|
+
# analyzed_at: Time.current
|
81
|
+
# )
|
82
|
+
# end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
QueryOptimizerClient.configure do |config|
|
4
|
+
# API Configuration
|
5
|
+
config.api_url = ENV.fetch('QUERY_OPTIMIZER_API_URL', 'http://localhost:3000/api/v1')
|
6
|
+
config.api_key = ENV['QUERY_OPTIMIZER_API_KEY']
|
7
|
+
config.enabled = ENV.fetch('QUERY_OPTIMIZER_ENABLED', 'false') == 'true'
|
8
|
+
|
9
|
+
# Request Configuration
|
10
|
+
config.timeout = ENV.fetch('QUERY_OPTIMIZER_TIMEOUT', '30').to_i
|
11
|
+
config.retries = ENV.fetch('QUERY_OPTIMIZER_RETRIES', '3').to_i
|
12
|
+
config.batch_size = ENV.fetch('QUERY_OPTIMIZER_BATCH_SIZE', '50').to_i
|
13
|
+
|
14
|
+
# Analysis Configuration
|
15
|
+
config.default_threshold = ENV.fetch('QUERY_OPTIMIZER_THRESHOLD', '80').to_i
|
16
|
+
config.rate_limit_retry = ENV.fetch('QUERY_OPTIMIZER_RATE_LIMIT_RETRY', 'true') == 'true'
|
17
|
+
|
18
|
+
# Logging
|
19
|
+
config.logger = Rails.logger
|
20
|
+
end
|
21
|
+
|
22
|
+
# Optional: Configure Rails-specific settings
|
23
|
+
Rails.application.configure do
|
24
|
+
# Middleware configuration
|
25
|
+
config.query_optimizer_client.min_queries = 3
|
26
|
+
config.query_optimizer_client.min_duration = 10
|
27
|
+
config.query_optimizer_client.skip_paths = ['/assets', '/health', '/api']
|
28
|
+
config.query_optimizer_client.async = true
|
29
|
+
config.query_optimizer_client.job_class = 'QueryOptimizerClient::AnalysisJob'
|
30
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
|
5
|
+
class QueryWiseGenerator < Rails::Generators::Base
|
6
|
+
desc "Install QueryWise gem"
|
7
|
+
|
8
|
+
source_root File.expand_path('query_optimizer_client/generators/templates', __dir__)
|
9
|
+
|
10
|
+
def create_initializer
|
11
|
+
template 'initializer.rb', 'config/initializers/query_optimizer_client.rb'
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_job
|
15
|
+
template 'analysis_job.rb', 'app/jobs/query_optimizer_client/analysis_job.rb'
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_environment_variables
|
19
|
+
environment_template = <<~ENV
|
20
|
+
# Query Optimizer Client Configuration
|
21
|
+
# QUERY_OPTIMIZER_API_URL=http://localhost:3000/api/v1
|
22
|
+
# QUERY_OPTIMIZER_API_KEY=your_api_key_here
|
23
|
+
# QUERY_OPTIMIZER_ENABLED=true
|
24
|
+
# QUERY_OPTIMIZER_THRESHOLD=80
|
25
|
+
ENV
|
26
|
+
|
27
|
+
# Create or append to .env.example
|
28
|
+
if File.exist?('.env.example')
|
29
|
+
append_to_file '.env.example', environment_template
|
30
|
+
else
|
31
|
+
create_file '.env.example', environment_template
|
32
|
+
end
|
33
|
+
|
34
|
+
# Create or append to .env
|
35
|
+
if File.exist?('.env')
|
36
|
+
append_to_file '.env', environment_template
|
37
|
+
else
|
38
|
+
create_file '.env', environment_template
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def show_readme
|
43
|
+
readme 'README'
|
44
|
+
end
|
45
|
+
end
|
@@ -25,9 +25,15 @@ module QueryWise
|
|
25
25
|
# QUERY_OPTIMIZER_ENABLED=true
|
26
26
|
# QUERY_OPTIMIZER_THRESHOLD=80
|
27
27
|
ENV
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
|
29
|
+
# Create or append to .env.example
|
30
|
+
if File.exist?('.env.example')
|
31
|
+
append_to_file '.env.example', environment_template
|
32
|
+
else
|
33
|
+
create_file '.env.example', environment_template
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create or append to .env
|
31
37
|
if File.exist?('.env')
|
32
38
|
append_to_file '.env', environment_template
|
33
39
|
else
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module QueryOptimizerClient
|
4
|
+
class Install
|
5
|
+
def self.run
|
6
|
+
new.run
|
7
|
+
end
|
8
|
+
|
9
|
+
def run
|
10
|
+
puts "Installing QueryWise..."
|
11
|
+
|
12
|
+
create_initializer
|
13
|
+
create_job
|
14
|
+
create_environment_files
|
15
|
+
|
16
|
+
puts "\n✅ QueryWise installation complete!"
|
17
|
+
puts "\nNext steps:"
|
18
|
+
puts "1. Update your .env file with your API credentials"
|
19
|
+
puts "2. Configure the initializer in config/initializers/query_optimizer_client.rb"
|
20
|
+
puts "3. Restart your Rails server"
|
21
|
+
puts "\nFor more information, visit: https://github.com/your-username/QueryWise"
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def create_initializer
|
27
|
+
initializer_path = 'config/initializers/query_optimizer_client.rb'
|
28
|
+
|
29
|
+
if File.exist?(initializer_path)
|
30
|
+
puts "⚠️ Initializer already exists at #{initializer_path}"
|
31
|
+
return
|
32
|
+
end
|
33
|
+
|
34
|
+
initializer_content = <<~RUBY
|
35
|
+
# frozen_string_literal: true
|
36
|
+
|
37
|
+
QueryOptimizerClient.configure do |config|
|
38
|
+
# API Configuration
|
39
|
+
config.api_url = ENV.fetch('QUERY_OPTIMIZER_API_URL', 'https://your-api-url.com/api/v1')
|
40
|
+
config.api_key = ENV.fetch('QUERY_OPTIMIZER_API_KEY', nil)
|
41
|
+
|
42
|
+
# Feature toggles
|
43
|
+
config.enabled = ENV.fetch('QUERY_OPTIMIZER_ENABLED', 'true') == 'true'
|
44
|
+
config.auto_analyze = ENV.fetch('QUERY_OPTIMIZER_AUTO_ANALYZE', 'false') == 'true'
|
45
|
+
|
46
|
+
# Performance thresholds
|
47
|
+
config.slow_query_threshold = ENV.fetch('QUERY_OPTIMIZER_THRESHOLD', '100').to_i
|
48
|
+
|
49
|
+
# Logging
|
50
|
+
config.log_level = ENV.fetch('QUERY_OPTIMIZER_LOG_LEVEL', 'info').to_sym
|
51
|
+
|
52
|
+
# Analysis settings
|
53
|
+
config.batch_size = ENV.fetch('QUERY_OPTIMIZER_BATCH_SIZE', '10').to_i
|
54
|
+
config.analysis_interval = ENV.fetch('QUERY_OPTIMIZER_ANALYSIS_INTERVAL', '300').to_i
|
55
|
+
end
|
56
|
+
RUBY
|
57
|
+
|
58
|
+
File.write(initializer_path, initializer_content)
|
59
|
+
puts "✅ Created initializer: #{initializer_path}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_job
|
63
|
+
job_dir = 'app/jobs/query_optimizer_client'
|
64
|
+
job_path = File.join(job_dir, 'analysis_job.rb')
|
65
|
+
|
66
|
+
if File.exist?(job_path)
|
67
|
+
puts "⚠️ Job already exists at #{job_path}"
|
68
|
+
return
|
69
|
+
end
|
70
|
+
|
71
|
+
FileUtils.mkdir_p(job_dir)
|
72
|
+
|
73
|
+
job_content = <<~RUBY
|
74
|
+
# frozen_string_literal: true
|
75
|
+
|
76
|
+
module QueryOptimizerClient
|
77
|
+
class AnalysisJob < ApplicationJob
|
78
|
+
queue_as :default
|
79
|
+
|
80
|
+
def perform(queries)
|
81
|
+
return unless QueryOptimizerClient.configuration.enabled?
|
82
|
+
|
83
|
+
client = QueryOptimizerClient.client
|
84
|
+
|
85
|
+
begin
|
86
|
+
result = client.analyze_queries(queries)
|
87
|
+
Rails.logger.info "Query analysis completed: \#{result.inspect}"
|
88
|
+
rescue => e
|
89
|
+
Rails.logger.error "Query analysis failed: \#{e.message}"
|
90
|
+
raise e
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
RUBY
|
96
|
+
|
97
|
+
File.write(job_path, job_content)
|
98
|
+
puts "✅ Created job: #{job_path}"
|
99
|
+
end
|
100
|
+
|
101
|
+
def create_environment_files
|
102
|
+
env_content = <<~ENV
|
103
|
+
# Query Optimizer Client Configuration
|
104
|
+
QUERY_OPTIMIZER_API_URL=https://your-api-url.com/api/v1
|
105
|
+
QUERY_OPTIMIZER_API_KEY=your_api_key_here
|
106
|
+
QUERY_OPTIMIZER_ENABLED=true
|
107
|
+
QUERY_OPTIMIZER_AUTO_ANALYZE=false
|
108
|
+
QUERY_OPTIMIZER_THRESHOLD=100
|
109
|
+
QUERY_OPTIMIZER_LOG_LEVEL=info
|
110
|
+
QUERY_OPTIMIZER_BATCH_SIZE=10
|
111
|
+
QUERY_OPTIMIZER_ANALYSIS_INTERVAL=300
|
112
|
+
ENV
|
113
|
+
|
114
|
+
# Create .env.example
|
115
|
+
if File.exist?('.env.example')
|
116
|
+
File.write('.env.example', File.read('.env.example') + "\n" + env_content)
|
117
|
+
puts "✅ Updated .env.example"
|
118
|
+
else
|
119
|
+
File.write('.env.example', env_content)
|
120
|
+
puts "✅ Created .env.example"
|
121
|
+
end
|
122
|
+
|
123
|
+
# Create .env if it doesn't exist
|
124
|
+
unless File.exist?('.env')
|
125
|
+
File.write('.env', env_content)
|
126
|
+
puts "✅ Created .env"
|
127
|
+
else
|
128
|
+
puts "⚠️ .env already exists - please add the configuration manually"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -1,6 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'install'
|
4
|
+
|
3
5
|
namespace :query_optimizer do
|
6
|
+
desc "Install QueryWise configuration files"
|
7
|
+
task :install do
|
8
|
+
QueryOptimizerClient::Install.run
|
9
|
+
end
|
4
10
|
desc "Check configuration and connectivity"
|
5
11
|
task check: :environment do
|
6
12
|
puts "🔍 Query Optimizer Client Configuration Check"
|
@@ -4,8 +4,8 @@ require_relative "query_optimizer_client/version"
|
|
4
4
|
require_relative "query_optimizer_client/client"
|
5
5
|
require_relative "query_optimizer_client/configuration"
|
6
6
|
require_relative "query_optimizer_client/middleware"
|
7
|
+
require_relative "query_optimizer_client/install"
|
7
8
|
require_relative "query_optimizer_client/railtie" if defined?(Rails)
|
8
|
-
require_relative "query_optimizer_client/generators/install_generator" if defined?(Rails)
|
9
9
|
|
10
10
|
module QueryOptimizerClient
|
11
11
|
class Error < StandardError; end
|
@@ -54,6 +54,7 @@ Gem::Specification.new do |spec|
|
|
54
54
|
spec.add_development_dependency "vcr", "~> 6.1"
|
55
55
|
spec.add_development_dependency "rails", "~> 8.0"
|
56
56
|
spec.add_development_dependency "sqlite3", "~> 1.4"
|
57
|
+
spec.add_development_dependency "generator_spec", "~> 0.10"
|
57
58
|
|
58
59
|
# For more information and examples about making a new gem, check out our
|
59
60
|
# guide at: https://bundler.io/guides/creating_gem.html
|
metadata
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: QueryWise
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Blair Lane
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
11
|
date: 2025-08-30 00:00:00.000000000 Z
|
@@ -142,6 +142,20 @@ dependencies:
|
|
142
142
|
- - "~>"
|
143
143
|
- !ruby/object:Gem::Version
|
144
144
|
version: '1.4'
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: generator_spec
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0.10'
|
152
|
+
type: :development
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0.10'
|
145
159
|
description: QueryWise is a lightweight, developer-friendly tool that helps Ruby on
|
146
160
|
Rails teams detect, analyze, and fix inefficient database queries. Automatically
|
147
161
|
detect N+1 queries, slow queries, and missing indexes without needing heavy, expensive
|
@@ -162,6 +176,7 @@ files:
|
|
162
176
|
- GEM_README.md
|
163
177
|
- GEM_Rakefile
|
164
178
|
- GEM_gitignore
|
179
|
+
- INSTALLATION.md
|
165
180
|
- LICENSE.txt
|
166
181
|
- PUBLISHING_GUIDE.md
|
167
182
|
- QUERYWISE_INSTALL.md
|
@@ -222,6 +237,11 @@ files:
|
|
222
237
|
- db/schema.rb
|
223
238
|
- db/seeds.rb
|
224
239
|
- init.sql
|
240
|
+
- lib/generators/query_wise/install_generator.rb
|
241
|
+
- lib/generators/query_wise/templates/README
|
242
|
+
- lib/generators/query_wise/templates/analysis_job.rb
|
243
|
+
- lib/generators/query_wise/templates/initializer.rb
|
244
|
+
- lib/generators/query_wise_generator.rb
|
225
245
|
- lib/query_optimizer_client.rb
|
226
246
|
- lib/query_optimizer_client/client.rb
|
227
247
|
- lib/query_optimizer_client/configuration.rb
|
@@ -229,6 +249,7 @@ files:
|
|
229
249
|
- lib/query_optimizer_client/generators/templates/README
|
230
250
|
- lib/query_optimizer_client/generators/templates/analysis_job.rb
|
231
251
|
- lib/query_optimizer_client/generators/templates/initializer.rb
|
252
|
+
- lib/query_optimizer_client/install.rb
|
232
253
|
- lib/query_optimizer_client/middleware.rb
|
233
254
|
- lib/query_optimizer_client/railtie.rb
|
234
255
|
- lib/query_optimizer_client/tasks.rake
|
@@ -250,7 +271,7 @@ metadata:
|
|
250
271
|
source_code_uri: https://github.com/BlairLane22/QueryWise
|
251
272
|
changelog_uri: https://github.com/BlairLane22/QueryWise/blob/main/CHANGELOG.md
|
252
273
|
documentation_uri: https://github.com/BlairLane22/QueryWise/blob/main/README.md
|
253
|
-
post_install_message:
|
274
|
+
post_install_message:
|
254
275
|
rdoc_options: []
|
255
276
|
require_paths:
|
256
277
|
- lib
|
@@ -265,8 +286,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
265
286
|
- !ruby/object:Gem::Version
|
266
287
|
version: '0'
|
267
288
|
requirements: []
|
268
|
-
rubygems_version: 3.
|
269
|
-
signing_key:
|
289
|
+
rubygems_version: 3.4.10
|
290
|
+
signing_key:
|
270
291
|
specification_version: 4
|
271
292
|
summary: QueryWise - Rails Database Query Optimizer
|
272
293
|
test_files: []
|