QueryWise 0.2.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.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +45 -0
  3. data/CLOUD_RUN_README.md +263 -0
  4. data/DOCKER_README.md +327 -0
  5. data/Dockerfile +69 -0
  6. data/Dockerfile.cloudrun +76 -0
  7. data/Dockerfile.dev +36 -0
  8. data/GEM_Gemfile +16 -0
  9. data/GEM_README.md +421 -0
  10. data/GEM_Rakefile +10 -0
  11. data/GEM_gitignore +137 -0
  12. data/LICENSE.txt +21 -0
  13. data/PUBLISHING_GUIDE.md +269 -0
  14. data/README.md +392 -0
  15. data/app/controllers/api/v1/analysis_controller.rb +340 -0
  16. data/app/controllers/api/v1/api_keys_controller.rb +83 -0
  17. data/app/controllers/api/v1/base_controller.rb +93 -0
  18. data/app/controllers/api/v1/health_controller.rb +86 -0
  19. data/app/controllers/application_controller.rb +2 -0
  20. data/app/controllers/concerns/.keep +0 -0
  21. data/app/jobs/application_job.rb +7 -0
  22. data/app/mailers/application_mailer.rb +4 -0
  23. data/app/models/app_profile.rb +18 -0
  24. data/app/models/application_record.rb +3 -0
  25. data/app/models/concerns/.keep +0 -0
  26. data/app/models/optimization_suggestion.rb +44 -0
  27. data/app/models/query_analysis.rb +47 -0
  28. data/app/models/query_pattern.rb +55 -0
  29. data/app/services/missing_index_detector_service.rb +244 -0
  30. data/app/services/n_plus_one_detector_service.rb +177 -0
  31. data/app/services/slow_query_analyzer_service.rb +225 -0
  32. data/app/services/sql_parser_service.rb +352 -0
  33. data/app/validators/query_data_validator.rb +96 -0
  34. data/app/views/layouts/mailer.html.erb +13 -0
  35. data/app/views/layouts/mailer.text.erb +1 -0
  36. data/app.yaml +109 -0
  37. data/cloudbuild.yaml +47 -0
  38. data/config/application.rb +32 -0
  39. data/config/boot.rb +4 -0
  40. data/config/cable.yml +17 -0
  41. data/config/cache.yml +16 -0
  42. data/config/credentials.yml.enc +1 -0
  43. data/config/database.yml +69 -0
  44. data/config/deploy.yml +116 -0
  45. data/config/environment.rb +5 -0
  46. data/config/environments/development.rb +70 -0
  47. data/config/environments/production.rb +87 -0
  48. data/config/environments/test.rb +53 -0
  49. data/config/initializers/cors.rb +16 -0
  50. data/config/initializers/filter_parameter_logging.rb +8 -0
  51. data/config/initializers/inflections.rb +16 -0
  52. data/config/locales/en.yml +31 -0
  53. data/config/master.key +1 -0
  54. data/config/puma.rb +41 -0
  55. data/config/puma_cloudrun.rb +48 -0
  56. data/config/queue.yml +18 -0
  57. data/config/recurring.yml +15 -0
  58. data/config/routes.rb +28 -0
  59. data/config/storage.yml +34 -0
  60. data/config.ru +6 -0
  61. data/db/cable_schema.rb +11 -0
  62. data/db/cache_schema.rb +14 -0
  63. data/db/migrate/20250818214709_create_app_profiles.rb +13 -0
  64. data/db/migrate/20250818214731_create_query_analyses.rb +22 -0
  65. data/db/migrate/20250818214740_create_query_patterns.rb +22 -0
  66. data/db/migrate/20250818214805_create_optimization_suggestions.rb +20 -0
  67. data/db/queue_schema.rb +129 -0
  68. data/db/schema.rb +79 -0
  69. data/db/seeds.rb +9 -0
  70. data/init.sql +9 -0
  71. data/lib/query_optimizer_client/client.rb +176 -0
  72. data/lib/query_optimizer_client/configuration.rb +43 -0
  73. data/lib/query_optimizer_client/generators/install_generator.rb +43 -0
  74. data/lib/query_optimizer_client/generators/templates/README +46 -0
  75. data/lib/query_optimizer_client/generators/templates/analysis_job.rb +84 -0
  76. data/lib/query_optimizer_client/generators/templates/initializer.rb +30 -0
  77. data/lib/query_optimizer_client/middleware.rb +126 -0
  78. data/lib/query_optimizer_client/railtie.rb +37 -0
  79. data/lib/query_optimizer_client/tasks.rake +228 -0
  80. data/lib/query_optimizer_client/version.rb +5 -0
  81. data/lib/query_optimizer_client.rb +48 -0
  82. data/lib/tasks/.keep +0 -0
  83. data/public/robots.txt +1 -0
  84. data/query_optimizer_client.gemspec +60 -0
  85. data/script/.keep +0 -0
  86. data/storage/.keep +0 -0
  87. data/storage/development.sqlite3 +0 -0
  88. data/storage/test.sqlite3 +0 -0
  89. data/vendor/.keep +0 -0
  90. metadata +265 -0
@@ -0,0 +1,76 @@
1
+ # Optimized Dockerfile for Google Cloud Run
2
+ FROM ruby:3.2-slim AS base
3
+
4
+ # Install system dependencies
5
+ RUN apt-get update -qq && \
6
+ apt-get install --no-install-recommends -y \
7
+ curl \
8
+ libjemalloc2 \
9
+ libvips \
10
+ postgresql-client \
11
+ && rm -rf /var/lib/apt/lists /var/cache/apt/archives
12
+
13
+ # Rails app lives here
14
+ WORKDIR /rails
15
+
16
+ # Set production environment
17
+ ENV RAILS_ENV="production" \
18
+ BUNDLE_DEPLOYMENT="1" \
19
+ BUNDLE_PATH="/usr/local/bundle" \
20
+ BUNDLE_WITHOUT="development test" \
21
+ RAILS_SERVE_STATIC_FILES="true" \
22
+ RAILS_LOG_TO_STDOUT="true"
23
+
24
+ # Throw-away build stage to reduce size of final image
25
+ FROM base AS build
26
+
27
+ # Install packages needed to build gems
28
+ RUN apt-get update -qq && \
29
+ apt-get install --no-install-recommends -y \
30
+ build-essential \
31
+ git \
32
+ libpq-dev \
33
+ libyaml-dev \
34
+ pkg-config \
35
+ && rm -rf /var/lib/apt/lists /var/cache/apt/archives
36
+
37
+ # Install application gems
38
+ COPY Gemfile Gemfile.lock ./
39
+ RUN bundle install && \
40
+ rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
41
+ bundle exec bootsnap precompile --gemfile
42
+
43
+ # Copy application code
44
+ COPY . .
45
+
46
+ # Precompile bootsnap code for faster boot times
47
+ RUN bundle exec bootsnap precompile app/ lib/
48
+
49
+ # Final stage for app image
50
+ FROM base
51
+
52
+ # Copy built artifacts: gems, application
53
+ COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
54
+ COPY --from=build /rails /rails
55
+
56
+ # Run and own only the runtime files as a non-root user for security
57
+ RUN groupadd --system --gid 1000 rails && \
58
+ useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
59
+ mkdir -p /rails/log /rails/tmp && \
60
+ chown -R rails:rails /rails/log /rails/tmp
61
+
62
+ USER rails:rails
63
+
64
+ # Cloud Run expects the app to listen on $PORT
65
+ ENV PORT=8080
66
+ EXPOSE $PORT
67
+
68
+ # Health check for Cloud Run
69
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
70
+ CMD curl -f http://localhost:$PORT/api/v1/health || exit 1
71
+
72
+ # Entrypoint prepares the database
73
+ ENTRYPOINT ["/rails/bin/docker-entrypoint"]
74
+
75
+ # Start server optimized for Cloud Run
76
+ CMD ["bundle", "exec", "puma", "-C", "config/puma.rb", "-p", "$PORT", "-e", "production"]
data/Dockerfile.dev ADDED
@@ -0,0 +1,36 @@
1
+ FROM ruby:3.2-slim
2
+
3
+ # Install system dependencies
4
+ RUN apt-get update -qq && \
5
+ apt-get install --no-install-recommends -y \
6
+ build-essential \
7
+ curl \
8
+ git \
9
+ libpq-dev \
10
+ libvips \
11
+ pkg-config \
12
+ postgresql-client \
13
+ && rm -rf /var/lib/apt/lists /var/cache/apt/archives
14
+
15
+ # Set working directory
16
+ WORKDIR /rails
17
+
18
+ # Install gems
19
+ COPY Gemfile Gemfile.lock ./
20
+ RUN bundle install
21
+
22
+ # Copy application code
23
+ COPY . .
24
+
25
+ # Create non-root user
26
+ RUN groupadd --system --gid 1000 rails && \
27
+ useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
28
+ chown -R rails:rails /rails
29
+
30
+ USER rails:rails
31
+
32
+ # Expose port
33
+ EXPOSE 3000
34
+
35
+ # Start the server
36
+ CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
data/GEM_Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in query_optimizer_client.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+ gem "rspec", "~> 3.0"
10
+ gem "rubocop", "~> 1.21"
11
+
12
+ # Development dependencies
13
+ gem "webmock", "~> 3.18"
14
+ gem "vcr", "~> 6.1"
15
+ gem "rails", ">= 6.0"
16
+ gem "sqlite3", "~> 1.4"
data/GEM_README.md ADDED
@@ -0,0 +1,421 @@
1
+ # Rails Database Query Optimizer API
2
+
3
+ A powerful Rails API for analyzing and optimizing database queries in real-time. Detect N+1 queries, identify slow queries, suggest missing indexes, and get actionable optimization recommendations.
4
+
5
+ ## Features
6
+
7
+ - 🔍 **N+1 Query Detection**: Automatically detect N+1 query patterns and suggest eager loading solutions
8
+ - 🐌 **Slow Query Analysis**: Identify slow queries with severity levels and optimization suggestions
9
+ - 📊 **Missing Index Detection**: Analyze WHERE clauses and suggest database indexes
10
+ - 🔐 **API Authentication**: Secure API key-based authentication with rate limiting
11
+ - 📈 **CI/CD Integration**: Built-in scoring system for continuous integration
12
+ - 🧪 **Comprehensive Testing**: 200+ test examples with full coverage
13
+
14
+ ## Quick Start
15
+
16
+ ### 1. Requirements
17
+
18
+ - **Ruby**: 3.2.0 or higher
19
+ - **Rails**: 8.0.0 or higher
20
+ - **PostgreSQL**: 13+ (required for JSON support)
21
+
22
+ ### 2. Installation
23
+
24
+ Add to your Gemfile:
25
+
26
+ ```ruby
27
+ gem 'rails', '~> 8.0.0'
28
+ gem 'pg', '~> 1.1'
29
+ gem 'pg_query', '~> 4.2'
30
+ gem 'bcrypt', '~> 3.1.7'
31
+ gem 'rack-cors'
32
+ ```
33
+
34
+ ### 3. Database Setup
35
+
36
+ ```bash
37
+ rails db:create
38
+ rails db:migrate
39
+ ```
40
+
41
+ ### 4. Generate API Key
42
+
43
+ ```bash
44
+ rails console
45
+ ```
46
+
47
+ ```ruby
48
+ # Create an app profile and generate API key
49
+ app_profile = AppProfile.create!(name: 'My Rails App')
50
+ api_key = app_profile.generate_api_key!
51
+ puts "Your API Key: #{api_key}"
52
+ ```
53
+
54
+ ### 5. Basic Usage
55
+
56
+ ```ruby
57
+ require 'net/http'
58
+ require 'json'
59
+
60
+ # Analyze queries
61
+ uri = URI('http://localhost:3000/api/v1/analyze')
62
+ http = Net::HTTP.new(uri.host, uri.port)
63
+
64
+ request = Net::HTTP::Post.new(uri)
65
+ request['Content-Type'] = 'application/json'
66
+ request['X-API-Key'] = 'your_api_key_here'
67
+
68
+ request.body = {
69
+ queries: [
70
+ {
71
+ sql: "SELECT * FROM users WHERE id = 1",
72
+ duration_ms: 50
73
+ },
74
+ {
75
+ sql: "SELECT * FROM posts WHERE user_id = 1",
76
+ duration_ms: 200
77
+ }
78
+ ]
79
+ }.to_json
80
+
81
+ response = http.request(request)
82
+ result = JSON.parse(response.body)
83
+
84
+ puts result['data']['n_plus_one']
85
+ puts result['data']['slow_queries']
86
+ puts result['data']['missing_indexes']
87
+ ```
88
+
89
+ ## API Endpoints
90
+
91
+ ### Authentication
92
+
93
+ All endpoints (except API key creation) require authentication via the `X-API-Key` header.
94
+
95
+ ### POST /api/v1/api_keys
96
+
97
+ Create a new API key.
98
+
99
+ **Request:**
100
+ ```json
101
+ {
102
+ "app_name": "My Rails Application"
103
+ }
104
+ ```
105
+
106
+ **Response:**
107
+ ```json
108
+ {
109
+ "success": true,
110
+ "data": {
111
+ "app_name": "My Rails Application",
112
+ "api_key": "abc123...",
113
+ "created_at": "2024-01-15T10:30:00Z"
114
+ }
115
+ }
116
+ ```
117
+
118
+ ### POST /api/v1/analyze
119
+
120
+ Analyze queries for optimization opportunities.
121
+
122
+ **Headers:**
123
+ - `X-API-Key`: Your API key
124
+ - `Content-Type`: application/json
125
+
126
+ **Request:**
127
+ ```json
128
+ {
129
+ "queries": [
130
+ {
131
+ "sql": "SELECT * FROM users WHERE id = ?",
132
+ "duration_ms": 150
133
+ }
134
+ ]
135
+ }
136
+ ```
137
+
138
+ **Response:**
139
+ ```json
140
+ {
141
+ "success": true,
142
+ "data": {
143
+ "n_plus_one": {
144
+ "detected": true,
145
+ "patterns": [
146
+ {
147
+ "table": "posts",
148
+ "column": "user_id",
149
+ "query_count": 5,
150
+ "suggestion": "Use includes(:posts) to preload associations"
151
+ }
152
+ ]
153
+ },
154
+ "slow_queries": [
155
+ {
156
+ "sql": "SELECT * FROM users WHERE email LIKE '%@gmail.com'",
157
+ "duration_ms": 2000,
158
+ "severity": "very_slow",
159
+ "suggestions": ["Add index on email column", "Avoid leading wildcards"]
160
+ }
161
+ ],
162
+ "missing_indexes": [
163
+ {
164
+ "table": "users",
165
+ "columns": ["email"],
166
+ "sql": "CREATE INDEX idx_users_email ON users (email);",
167
+ "priority": "high"
168
+ }
169
+ ],
170
+ "summary": {
171
+ "total_queries": 10,
172
+ "issues_found": 3,
173
+ "optimization_score": 75
174
+ }
175
+ }
176
+ }
177
+ ```
178
+
179
+ ### POST /api/v1/analyze_ci
180
+
181
+ Analyze queries for CI/CD integration with pass/fail scoring.
182
+
183
+ **Request:**
184
+ ```json
185
+ {
186
+ "queries": [...],
187
+ "threshold_score": 80
188
+ }
189
+ ```
190
+
191
+ **Response:**
192
+ ```json
193
+ {
194
+ "success": true,
195
+ "data": {
196
+ "score": 85,
197
+ "passed": true,
198
+ "threshold": 80,
199
+ "issues": {
200
+ "n_plus_one": 1,
201
+ "slow_queries": 2,
202
+ "missing_indexes": 1,
203
+ "total": 4
204
+ },
205
+ "recommendations": [
206
+ "Add eager loading for user associations",
207
+ "Create index on posts.user_id"
208
+ ]
209
+ }
210
+ }
211
+ ```
212
+
213
+ ### GET /api/v1/health
214
+
215
+ Check API health status.
216
+
217
+ **Response:**
218
+ ```json
219
+ {
220
+ "status": "ok",
221
+ "timestamp": "2024-01-15T10:30:00Z",
222
+ "version": "1.0.0",
223
+ "services": {
224
+ "database": "ok",
225
+ "sql_parser": "ok",
226
+ "analysis_services": "ok"
227
+ }
228
+ }
229
+ ```
230
+
231
+ ## Integration Examples
232
+
233
+ ### Rails Application Integration
234
+
235
+ ```ruby
236
+ # app/services/query_optimizer_service.rb
237
+ class QueryOptimizerService
238
+ API_BASE_URL = 'http://localhost:3000/api/v1'
239
+
240
+ def initialize(api_key)
241
+ @api_key = api_key
242
+ end
243
+
244
+ def analyze_queries(queries)
245
+ uri = URI("#{API_BASE_URL}/analyze")
246
+ http = Net::HTTP.new(uri.host, uri.port)
247
+
248
+ request = Net::HTTP::Post.new(uri)
249
+ request['Content-Type'] = 'application/json'
250
+ request['X-API-Key'] = @api_key
251
+
252
+ request.body = { queries: queries }.to_json
253
+
254
+ response = http.request(request)
255
+ JSON.parse(response.body)
256
+ end
257
+
258
+ def check_ci_quality(queries, threshold = 80)
259
+ uri = URI("#{API_BASE_URL}/analyze_ci")
260
+ http = Net::HTTP.new(uri.host, uri.port)
261
+
262
+ request = Net::HTTP::Post.new(uri)
263
+ request['Content-Type'] = 'application/json'
264
+ request['X-API-Key'] = @api_key
265
+
266
+ request.body = {
267
+ queries: queries,
268
+ threshold_score: threshold
269
+ }.to_json
270
+
271
+ response = http.request(request)
272
+ result = JSON.parse(response.body)
273
+
274
+ result.dig('data', 'passed')
275
+ end
276
+ end
277
+
278
+ # Usage in your Rails app
279
+ optimizer = QueryOptimizerService.new(ENV['QUERY_OPTIMIZER_API_KEY'])
280
+
281
+ # Collect queries from your application
282
+ queries = [
283
+ {
284
+ sql: User.where(active: true).to_sql,
285
+ duration_ms: 45
286
+ }
287
+ ]
288
+
289
+ # Analyze for optimization opportunities
290
+ result = optimizer.analyze_queries(queries)
291
+
292
+ if result['data']['n_plus_one']['detected']
293
+ Rails.logger.warn "N+1 queries detected: #{result['data']['n_plus_one']['patterns']}"
294
+ end
295
+ ```
296
+
297
+ ### CI/CD Integration
298
+
299
+ ```yaml
300
+ # .github/workflows/query_optimization.yml
301
+ name: Query Optimization Check
302
+
303
+ on: [push, pull_request]
304
+
305
+ jobs:
306
+ query-optimization:
307
+ runs-on: ubuntu-latest
308
+
309
+ steps:
310
+ - uses: actions/checkout@v2
311
+
312
+ - name: Setup Ruby
313
+ uses: ruby/setup-ruby@v1
314
+ with:
315
+ ruby-version: 3.2
316
+
317
+ - name: Install dependencies
318
+ run: bundle install
319
+
320
+ - name: Run query optimization check
321
+ run: |
322
+ ruby scripts/check_query_optimization.rb
323
+ env:
324
+ QUERY_OPTIMIZER_API_KEY: ${{ secrets.QUERY_OPTIMIZER_API_KEY }}
325
+ OPTIMIZATION_THRESHOLD: 85
326
+ ```
327
+
328
+ ```ruby
329
+ # scripts/check_query_optimization.rb
330
+ require 'net/http'
331
+ require 'json'
332
+
333
+ # Collect sample queries from your test suite
334
+ queries = [
335
+ { sql: "SELECT * FROM users WHERE active = true", duration_ms: 50 },
336
+ { sql: "SELECT * FROM posts WHERE user_id = 1", duration_ms: 120 }
337
+ ]
338
+
339
+ uri = URI('http://your-optimizer-api.com/api/v1/analyze_ci')
340
+ http = Net::HTTP.new(uri.host, uri.port)
341
+
342
+ request = Net::HTTP::Post.new(uri)
343
+ request['Content-Type'] = 'application/json'
344
+ request['X-API-Key'] = ENV['QUERY_OPTIMIZER_API_KEY']
345
+
346
+ request.body = {
347
+ queries: queries,
348
+ threshold_score: ENV['OPTIMIZATION_THRESHOLD'].to_i
349
+ }.to_json
350
+
351
+ response = http.request(request)
352
+ result = JSON.parse(response.body)
353
+
354
+ if result['data']['passed']
355
+ puts "✅ Query optimization check passed (Score: #{result['data']['score']})"
356
+ exit 0
357
+ else
358
+ puts "❌ Query optimization check failed (Score: #{result['data']['score']})"
359
+ puts "Issues found:"
360
+ result['data']['recommendations'].each { |rec| puts " - #{rec}" }
361
+ exit 1
362
+ end
363
+ ```
364
+
365
+ ## Rate Limits
366
+
367
+ - **1000 requests per hour** per API key
368
+ - Rate limit headers included in responses
369
+ - Contact support for higher limits
370
+
371
+ ## Error Handling
372
+
373
+ All endpoints return consistent error responses:
374
+
375
+ ```json
376
+ {
377
+ "success": false,
378
+ "error": "Error message",
379
+ "errors": ["Detailed error 1", "Detailed error 2"]
380
+ }
381
+ ```
382
+
383
+ Common HTTP status codes:
384
+ - `400` - Bad Request (validation errors)
385
+ - `401` - Unauthorized (invalid/missing API key)
386
+ - `429` - Too Many Requests (rate limit exceeded)
387
+ - `500` - Internal Server Error
388
+
389
+ ## Development
390
+
391
+ ### Running Tests
392
+
393
+ ```bash
394
+ bundle exec rspec
395
+ ```
396
+
397
+ ### Starting the Server
398
+
399
+ ```bash
400
+ rails server
401
+ ```
402
+
403
+ ### Environment Variables
404
+
405
+ ```bash
406
+ # .env
407
+ DATABASE_URL=postgresql://user:password@localhost/query_optimizer_development
408
+ RAILS_ENV=development
409
+ ```
410
+
411
+ ## Contributing
412
+
413
+ 1. Fork the repository
414
+ 2. Create a feature branch
415
+ 3. Add tests for new functionality
416
+ 4. Ensure all tests pass
417
+ 5. Submit a pull request
418
+
419
+ ## License
420
+
421
+ MIT License - see LICENSE file for details.
data/GEM_Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "rubocop/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new
9
+
10
+ task default: %i[spec rubocop]
data/GEM_gitignore ADDED
@@ -0,0 +1,137 @@
1
+ # === SENSITIVE INFORMATION ===
2
+ # Environment files with API keys and secrets
3
+ .env*
4
+ !.env.example
5
+
6
+ # RubyGems credentials and API keys
7
+ .gem/
8
+ ~/.gem/credentials
9
+
10
+ # Any files containing API keys or tokens
11
+ *api_key*
12
+ *secret*
13
+ *token*
14
+ *password*
15
+ !*example*
16
+ !*template*
17
+ !*spec*
18
+
19
+ # === GEM DEVELOPMENT ===
20
+ # Bundler
21
+ .bundle/
22
+ vendor/bundle/
23
+
24
+ # Built gems
25
+ *.gem
26
+
27
+ # Gem build artifacts
28
+ pkg/
29
+
30
+ # === TESTING ===
31
+ # RSpec
32
+ .rspec_status
33
+
34
+ # Test coverage
35
+ coverage/
36
+
37
+ # VCR cassettes (may contain API responses with sensitive data)
38
+ spec/vcr_cassettes/
39
+ spec/fixtures/vcr_cassettes/
40
+
41
+ # Test databases
42
+ test.db
43
+ spec/test.db
44
+
45
+ # === DEVELOPMENT TOOLS ===
46
+ # IDE and editor files
47
+ .vscode/
48
+ .idea/
49
+ *.swp
50
+ *.swo
51
+ *~
52
+
53
+ # Vim
54
+ *.un~
55
+ Session.vim
56
+
57
+ # Emacs
58
+ *~
59
+ \#*\#
60
+ /.emacs.desktop
61
+ /.emacs.desktop.lock
62
+ *.elc
63
+ auto-save-list
64
+ tramp
65
+ .\#*
66
+
67
+ # === OS GENERATED FILES ===
68
+ # macOS
69
+ .DS_Store
70
+ .DS_Store?
71
+ ._*
72
+ .Spotlight-V100
73
+ .Trashes
74
+ .fseventsd
75
+
76
+ # Windows
77
+ ehthumbs.db
78
+ Thumbs.db
79
+ Desktop.ini
80
+
81
+ # Linux
82
+ *~
83
+ .directory
84
+
85
+ # === DOCUMENTATION ===
86
+ # Generated documentation
87
+ doc/
88
+ .yardoc/
89
+ .yard/
90
+
91
+ # === LOGS ===
92
+ # Log files
93
+ *.log
94
+ log/
95
+
96
+ # === TEMPORARY FILES ===
97
+ # Temporary files
98
+ tmp/
99
+ temp/
100
+
101
+ # === BACKUP FILES ===
102
+ *.bak
103
+ *.backup
104
+ *.old
105
+ *.orig
106
+
107
+ # === RUBY SPECIFIC ===
108
+ # IRB history
109
+ .irb_history
110
+
111
+ # Ruby version managers
112
+ .rvmrc
113
+ .ruby-version
114
+ .ruby-gemset
115
+
116
+ # === CI/CD ===
117
+ # GitHub Actions artifacts
118
+ .github/workflows/artifacts/
119
+
120
+ # === DEPLOYMENT ===
121
+ # Deployment configurations
122
+ deploy.rb
123
+ config/deploy/
124
+
125
+ # Docker
126
+ Dockerfile.prod
127
+ docker-compose.prod.yml
128
+
129
+ # === MISC ===
130
+ # Ignore any local configuration overrides
131
+ local_config.rb
132
+ config/local.rb
133
+
134
+ # Ignore any personal notes or TODO files
135
+ TODO.md
136
+ NOTES.md
137
+ personal_notes.txt
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Query Optimizer Client
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.