inquery 1.0.11 → 1.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rubocop.yml +1 -1
  3. data/.github/workflows/ruby.yml +24 -8
  4. data/.gitignore +2 -2
  5. data/.rubocop.yml +4 -0
  6. data/Appraisals +24 -4
  7. data/CHANGELOG.md +55 -0
  8. data/Gemfile +17 -1
  9. data/Gemfile.lock +125 -0
  10. data/LICENSE +1 -1
  11. data/MIGRATION.md +260 -0
  12. data/README.md +19 -10
  13. data/RUBY_VERSION +1 -1
  14. data/Rakefile +4 -11
  15. data/VERSION +1 -1
  16. data/doc/Inquery/Exceptions/Base.html +4 -4
  17. data/doc/Inquery/Exceptions/InvalidRelation.html +4 -4
  18. data/doc/Inquery/Exceptions/UnknownCallSignature.html +4 -4
  19. data/doc/Inquery/Exceptions.html +4 -4
  20. data/doc/Inquery/MethodAccessibleHash.html +849 -0
  21. data/doc/Inquery/Mixins/RawSqlUtils.html +17 -4
  22. data/doc/Inquery/Mixins/RelationValidation/ClassMethods.html +8 -7
  23. data/doc/Inquery/Mixins/RelationValidation.html +9 -8
  24. data/doc/Inquery/Mixins/SchemaValidation/ClassMethods.html +4 -4
  25. data/doc/Inquery/Mixins/SchemaValidation.html +4 -4
  26. data/doc/Inquery/Mixins.html +4 -4
  27. data/doc/Inquery/Query/Chainable.html +207 -90
  28. data/doc/Inquery/Query.html +401 -73
  29. data/doc/Inquery.html +12 -9
  30. data/doc/_index.html +12 -5
  31. data/doc/class_list.html +6 -3
  32. data/doc/css/full_list.css +3 -3
  33. data/doc/css/style.css +6 -0
  34. data/doc/file.README.html +107 -18
  35. data/doc/file_list.html +5 -2
  36. data/doc/frames.html +10 -5
  37. data/doc/index.html +107 -18
  38. data/doc/js/app.js +294 -264
  39. data/doc/js/full_list.js +30 -4
  40. data/doc/method_list.html +95 -20
  41. data/doc/top-level-namespace.html +4 -4
  42. data/gemfiles/rails_5.2.gemfile +1 -0
  43. data/gemfiles/rails_6.0.gemfile +1 -0
  44. data/gemfiles/rails_6.1.gemfile +1 -0
  45. data/gemfiles/rails_7.0.gemfile +1 -0
  46. data/gemfiles/{rails_5.1.gemfile → rails_7.1.gemfile} +2 -1
  47. data/gemfiles/rails_7.2.gemfile +8 -0
  48. data/gemfiles/rails_8.0.gemfile +8 -0
  49. data/gemfiles/rails_8.1.gemfile +8 -0
  50. data/inquery.gemspec +11 -34
  51. data/lib/inquery/method_accessible_hash.rb +130 -0
  52. data/lib/inquery/mixins/raw_sql_utils.rb +32 -6
  53. data/lib/inquery/mixins/relation_validation.rb +1 -1
  54. data/lib/inquery/query/chainable.rb +69 -27
  55. data/lib/inquery/query.rb +67 -14
  56. data/lib/inquery.rb +2 -0
  57. data/test/inquery/error_handling_test.rb +117 -0
  58. data/test/inquery/method_accessible_hash_test.rb +213 -0
  59. data/test/inquery/mixins/raw_sql_utils_test.rb +67 -0
  60. data/test/inquery/query/chainable_test.rb +78 -0
  61. data/test/inquery/query_test.rb +86 -0
  62. data/test/test_helper.rb +11 -0
  63. metadata +30 -129
  64. data/.yardopts +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1196c966133abae58b4ba672eebc7fadf0852f4de0ff879673322bf6bfb4a285
4
- data.tar.gz: 534d1e42f4df591e5cdb1e5e5995c8a3479f1afe03d6bb45d03773ad29c0838f
3
+ metadata.gz: b98dc6fa8124e5d5febb058d644524f392d4ad94a140eebe361811aa92e74d17
4
+ data.tar.gz: 201d38b5fcaa35608c70ec2800685930272d6e9ca5a68f0c3b3d367e3db61382
5
5
  SHA512:
6
- metadata.gz: 31c7638d4a5eb7b32df879028bd01ee612254b1c34ffd2851be7851a5bb72488851748eba904ce6c7967e70e98ba4a85729960a00addd093ea622cdf96f3df30
7
- data.tar.gz: 0fbe2057d13400d67546ee5722eb85b5e04cc794552c85043d3e939bc89cbd55eff247f8c4b28d681297d2e1305be32da61fc47d1c811868822cf2c36e9759ac
6
+ metadata.gz: b6941ca16491c5322fd81976842cda78a35418caf272a2c4e1027fa5d6d9a9713c509ea8d482384c60ba287efa269244530a5e28043517bdd0b02a1a9056d310
7
+ data.tar.gz: 87c4af61b494a8d2e668b81fe884a3ed195fabce4d0b48f8582dcb92889424f96d8154b3bbeb2c03860d33329f177db22d27fc3bf0aaef51774d50ad0094fc00
@@ -11,7 +11,7 @@ jobs:
11
11
  - name: Set up Ruby
12
12
  uses: ruby/setup-ruby@v1
13
13
  with:
14
- ruby-version: 3.0.1
14
+ ruby-version: 3.3.0
15
15
  bundler-cache: true
16
16
  - name: Run rubocop
17
17
  run: bundle exec rubocop
@@ -13,20 +13,12 @@ jobs:
13
13
  fail-fast: false
14
14
  matrix:
15
15
  include:
16
- - rails-version: '5.1'
17
- ruby-version: '2.5.1'
18
- - rails-version: '5.2'
19
- ruby-version: '2.5.1'
20
16
  - rails-version: '5.2'
21
17
  ruby-version: '2.6.2'
22
- - rails-version: '6.0'
23
- ruby-version: '2.5.1'
24
18
  - rails-version: '6.0'
25
19
  ruby-version: '2.6.2'
26
20
  - rails-version: '6.0'
27
21
  ruby-version: '2.7.1'
28
- - rails-version: '6.1'
29
- ruby-version: '2.5.1'
30
22
  - rails-version: '6.1'
31
23
  ruby-version: '2.6.2'
32
24
  - rails-version: '6.1'
@@ -39,6 +31,30 @@ jobs:
39
31
  ruby-version: '3.0.1'
40
32
  - rails-version: '7.0'
41
33
  ruby-version: '3.1.0'
34
+ - rails-version: '7.0'
35
+ ruby-version: '3.2.0'
36
+ - rails-version: '7.0'
37
+ ruby-version: '3.3.0'
38
+ - rails-version: '7.1'
39
+ ruby-version: '3.1.0'
40
+ - rails-version: '7.1'
41
+ ruby-version: '3.2.0'
42
+ - rails-version: '7.1'
43
+ ruby-version: '3.3.0'
44
+ - rails-version: '7.2'
45
+ ruby-version: '3.2.0'
46
+ - rails-version: '7.2'
47
+ ruby-version: '3.3.0'
48
+ - rails-version: '7.2'
49
+ ruby-version: '3.4.1'
50
+ - rails-version: '8.0'
51
+ ruby-version: '3.3.0'
52
+ - rails-version: '8.0'
53
+ ruby-version: '3.4.1'
54
+ - rails-version: '8.1'
55
+ ruby-version: '3.3.0'
56
+ - rails-version: '8.1'
57
+ ruby-version: '3.4.1'
42
58
  name: Test against Ruby ${{ matrix.ruby-version }} / Rails ${{ matrix.rails-version }}
43
59
  env:
44
60
  BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rails_${{ matrix.rails-version }}.gemfile
data/.gitignore CHANGED
@@ -3,7 +3,6 @@
3
3
  .DS_Store
4
4
  *.tmproj
5
5
  tmtags
6
- /Gemfile.lock
7
6
  *~
8
7
  \#*
9
8
  .\#*
@@ -14,4 +13,5 @@ tmtags
14
13
  /.yardoc
15
14
  .idea
16
15
  /*.gem
17
- /gemfiles/*.lock
16
+ /gemfiles/*.lock
17
+ /coverage
data/.rubocop.yml CHANGED
@@ -5,6 +5,7 @@ AllCops:
5
5
  - 'vendor/**/*'
6
6
  - 'tmp/**/*'
7
7
  - 'inquery.gemspec'
8
+ - 'gemfiles/**/*'
8
9
  SuggestExtensions: false
9
10
 
10
11
  DisplayCopNames: true
@@ -105,3 +106,6 @@ Style/CaseLikeIf:
105
106
 
106
107
  Style/OpenStructUse:
107
108
  Enabled: false
109
+
110
+ Style/ArgumentsForwarding:
111
+ Enabled: false
data/Appraisals CHANGED
@@ -1,19 +1,39 @@
1
+ appraise 'rails-8.1' do
2
+ gem 'rails', '~> 8.1.0'
3
+ gem 'sqlite3', '>= 2.5'
4
+ end
5
+
6
+ appraise 'rails-8.0' do
7
+ gem 'rails', '~> 8.0.0'
8
+ gem 'sqlite3', '>= 2.5'
9
+ end
10
+
11
+ appraise 'rails-7.2' do
12
+ gem 'rails', '~> 7.2.0'
13
+ gem 'sqlite3', '>= 2.5'
14
+ end
15
+
16
+ appraise 'rails-7.1' do
17
+ gem 'rails', '~> 7.1.0'
18
+ gem 'sqlite3', '>= 1.4'
19
+ end
20
+
1
21
  appraise 'rails-7.0' do
2
22
  gem 'rails', '~> 7.0.1'
23
+ gem 'sqlite3', '~> 1.4.0'
3
24
  end
4
25
 
5
26
  appraise 'rails-6.1' do
6
27
  gem 'rails', '~> 6.1.4'
28
+ gem 'sqlite3', '~> 1.4.0'
7
29
  end
8
30
 
9
31
  appraise 'rails-6.0' do
10
32
  gem 'rails', '~> 6.0.4'
33
+ gem 'sqlite3', '~> 1.4.0'
11
34
  end
12
35
 
13
36
  appraise 'rails-5.2' do
14
37
  gem 'rails', '~> 5.2.6'
15
- end
16
-
17
- appraise 'rails-5.1' do
18
- gem 'rails', '~> 5.1.7'
38
+ gem 'sqlite3', '~> 1.3.13'
19
39
  end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,60 @@
1
1
  # Change log
2
2
 
3
+ ## 1.1.1 (2026-06-15)
4
+
5
+ * Fix `osparams` returning wrong values for keys that collide with `Hash` /
6
+ `Enumerable` method names (e.g. `group_by`, `count`, `zip`, `select`). Since
7
+ 1.1.0 `MethodAccessibleHash` subclassed `Hash`, so `osparams.group_by` invoked
8
+ `Enumerable#group_by` (returning an `Enumerator`) instead of the stored value.
9
+ `MethodAccessibleHash` no longer subclasses `Hash`; it wraps an internal hash
10
+ and exposes only `[]`, `[]=`, `to_h`, `merge`, `==` and method-based access.
11
+
12
+ Note: as a result, the `Hash` / `Enumerable` API that was briefly available
13
+ in 1.1.0 (e.g. `each`, `keys`, `values`, `dig`, `map`, `**` splat) is no
14
+ longer exposed -- call `to_h` first if you need it. `merge` now takes a
15
+ positional hash (or another `MethodAccessibleHash`) instead of keyword
16
+ arguments.
17
+
18
+ Internal reference: `#150355`.
19
+
20
+ ## 1.1.0 (2026-01-05)
21
+
22
+ * **Drop support for Ruby 2.5.1 and Rails 5.1**: The minimum supported versions
23
+ are now Ruby 2.6.2 and Rails 5.2. Ruby 2.5.1 reached end-of-life in March
24
+ 2021 and is no longer available on modern CI infrastructure (Ubuntu 24.04).
25
+ * Fix Ruby 2.6 compatibility in `MethodAccessibleHash` by converting method
26
+ symbol to string before calling `end_with?` (`Symbol#end_with?` was added
27
+ in Ruby 2.7)
28
+ * Fix Ruby 2.5/2.6 compatibility by replacing argument forwarding syntax (`...`)
29
+ with explicit `*args, &block` in schema validation mixin
30
+ * Add inline documentation to Query, Query::Chainable, and RawSqlUtils classes
31
+ * Add MIGRATION.md guide with examples for migrating from raw ActiveRecord
32
+ queries and upgrading between Inquery versions
33
+ * Refactor argument parsing in `Query::Chainable` for improved readability and
34
+ maintainability while preserving backward compatibility
35
+ * Increase test coverage from 87.1% to 90.97% by adding tests for error
36
+ handling, relation validation edge cases, and schema validation
37
+ * Add integration tests for RawSqlUtils mixin (`san` and `exec_query` methods)
38
+ * Move all development dependencies from gemspec to Gemfile for cleaner
39
+ separation of runtime and development dependencies
40
+ * Remove unused dependencies: `yard`, `haml`, and `redcarpet`
41
+ * Remove YARD documentation files and configuration
42
+ * Update RuboCop from version 1.25 to ~> 1.60 and fix new style violations
43
+ * Replace deprecated `OpenStruct` with `MethodAccessibleHash` to ensure
44
+ compatibility with Ruby 3.5+
45
+ * Remove debug code from `Query::Chainable#call` method
46
+ * Fix Ruby 3.0+ compatibility by explicitly requiring `logger`
47
+ * Constrain `sqlite3` to version `~> 1.4.0` for Rails 6.1 and 7.0 to avoid
48
+ version conflicts
49
+ * Update `RUBY_VERSION` to `ruby-3.3.5`
50
+ * Add support for Rails 7.1, 7.2, 8.0, and 8.1
51
+ * Add support for Ruby 3.2, 3.3, and 3.4
52
+ * Update sqlite3 gem requirement to `>= 2.5` for Rails 7.2+ to ensure Ruby
53
+ 3.4 compatibility
54
+ * Add explicit version constraints for runtime dependencies: `activesupport`
55
+ and `activerecord` now require `>= 5.1`, `schemacop` allows `>= 3.0.8, < 4.0`
56
+ for better dependency resolution and compatibility
57
+
3
58
  ## 1.0.11 (2023-08-24)
4
59
 
5
60
  * Add configuration option `config.default_schema_version` that allows you to
data/Gemfile CHANGED
@@ -1,4 +1,20 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify gem dependencies in the .gemspec file
3
+ # Specify runtime dependencies in the .gemspec file
4
4
  gemspec
5
+
6
+ # Development dependencies
7
+ group :development do
8
+ gem 'appraisal'
9
+ gem 'rake'
10
+ end
11
+
12
+ group :test do
13
+ gem 'minitest'
14
+ gem 'simplecov'
15
+ gem 'sqlite3'
16
+ end
17
+
18
+ group :lint do
19
+ gem 'rubocop', '~> 1.60'
20
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,125 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ inquery (1.1.1)
5
+ activerecord (>= 5.1)
6
+ activesupport (>= 5.1)
7
+ schemacop (>= 3.0.8, < 4.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activemodel (8.1.1)
13
+ activesupport (= 8.1.1)
14
+ activerecord (8.1.1)
15
+ activemodel (= 8.1.1)
16
+ activesupport (= 8.1.1)
17
+ timeout (>= 0.4.0)
18
+ activesupport (8.1.1)
19
+ base64
20
+ bigdecimal
21
+ concurrent-ruby (~> 1.0, >= 1.3.1)
22
+ connection_pool (>= 2.2.5)
23
+ drb
24
+ i18n (>= 1.6, < 2)
25
+ json
26
+ logger (>= 1.4.2)
27
+ minitest (>= 5.1)
28
+ securerandom (>= 0.3)
29
+ tzinfo (~> 2.0, >= 2.0.5)
30
+ uri (>= 0.13.1)
31
+ appraisal (2.5.0)
32
+ bundler
33
+ rake
34
+ thor (>= 0.14.0)
35
+ ast (2.4.3)
36
+ base64 (0.3.0)
37
+ bigdecimal (3.3.1)
38
+ concurrent-ruby (1.3.5)
39
+ connection_pool (2.5.5)
40
+ docile (1.4.1)
41
+ drb (2.2.3)
42
+ i18n (1.14.7)
43
+ concurrent-ruby (~> 1.0)
44
+ json (2.17.1.2)
45
+ language_server-protocol (3.17.0.5)
46
+ lint_roller (1.1.0)
47
+ logger (1.7.0)
48
+ minitest (5.26.2)
49
+ parallel (1.27.0)
50
+ parser (3.3.10.0)
51
+ ast (~> 2.4.1)
52
+ racc
53
+ prism (1.6.0)
54
+ racc (1.8.1)
55
+ rainbow (3.1.1)
56
+ rake (13.3.1)
57
+ regexp_parser (2.11.3)
58
+ rubocop (1.81.7)
59
+ json (~> 2.3)
60
+ language_server-protocol (~> 3.17.0.2)
61
+ lint_roller (~> 1.1.0)
62
+ parallel (~> 1.10)
63
+ parser (>= 3.3.0.2)
64
+ rainbow (>= 2.2.2, < 4.0)
65
+ regexp_parser (>= 2.9.3, < 3.0)
66
+ rubocop-ast (>= 1.47.1, < 2.0)
67
+ ruby-progressbar (~> 1.7)
68
+ unicode-display_width (>= 2.4.0, < 4.0)
69
+ rubocop-ast (1.48.0)
70
+ parser (>= 3.3.7.2)
71
+ prism (~> 1.4)
72
+ ruby-progressbar (1.13.0)
73
+ ruby2_keywords (0.0.5)
74
+ schemacop (3.0.35)
75
+ activesupport (>= 4.0)
76
+ ruby2_keywords (>= 0.0.4)
77
+ securerandom (0.4.1)
78
+ simplecov (0.22.0)
79
+ docile (~> 1.1)
80
+ simplecov-html (~> 0.11)
81
+ simplecov_json_formatter (~> 0.1)
82
+ simplecov-html (0.13.2)
83
+ simplecov_json_formatter (0.1.4)
84
+ sqlite3 (2.8.1-aarch64-linux-gnu)
85
+ sqlite3 (2.8.1-aarch64-linux-musl)
86
+ sqlite3 (2.8.1-arm-linux-gnu)
87
+ sqlite3 (2.8.1-arm-linux-musl)
88
+ sqlite3 (2.8.1-arm64-darwin)
89
+ sqlite3 (2.8.1-x86-linux-gnu)
90
+ sqlite3 (2.8.1-x86-linux-musl)
91
+ sqlite3 (2.8.1-x86_64-darwin)
92
+ sqlite3 (2.8.1-x86_64-linux-gnu)
93
+ sqlite3 (2.8.1-x86_64-linux-musl)
94
+ thor (1.4.0)
95
+ timeout (0.4.4)
96
+ tzinfo (2.0.6)
97
+ concurrent-ruby (~> 1.0)
98
+ unicode-display_width (3.2.0)
99
+ unicode-emoji (~> 4.1)
100
+ unicode-emoji (4.1.0)
101
+ uri (1.1.1)
102
+
103
+ PLATFORMS
104
+ aarch64-linux-gnu
105
+ aarch64-linux-musl
106
+ arm-linux-gnu
107
+ arm-linux-musl
108
+ arm64-darwin
109
+ x86-linux-gnu
110
+ x86-linux-musl
111
+ x86_64-darwin
112
+ x86_64-linux-gnu
113
+ x86_64-linux-musl
114
+
115
+ DEPENDENCIES
116
+ appraisal
117
+ inquery!
118
+ minitest
119
+ rake
120
+ rubocop (~> 1.60)
121
+ simplecov
122
+ sqlite3
123
+
124
+ BUNDLED WITH
125
+ 2.5.18
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright © 2016 - 2023 Sitrox
3
+ Copyright © 2016 - 2026 Sitrox
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/MIGRATION.md ADDED
@@ -0,0 +1,260 @@
1
+ # Migration Guide
2
+
3
+ This guide helps you migrate from raw ActiveRecord queries to Inquery query classes, and between different versions of Inquery.
4
+
5
+ ## Migrating from Raw ActiveRecord Queries
6
+
7
+ ### Simple Query
8
+
9
+ **Before (raw ActiveRecord):**
10
+ ```ruby
11
+ # In controller or service
12
+ def active_users
13
+ User.where(active: true).order(:name)
14
+ end
15
+ ```
16
+
17
+ **After (Inquery):**
18
+ ```ruby
19
+ # app/queries/fetch_active_users.rb
20
+ class FetchActiveUsers < Inquery::Query
21
+ def call
22
+ User.where(active: true).order(:name)
23
+ end
24
+ end
25
+
26
+ # In controller or service
27
+ def active_users
28
+ FetchActiveUsers.run
29
+ end
30
+ ```
31
+
32
+ **Benefits:**
33
+ - Reusable across controllers, services, and background jobs
34
+ - Testable in isolation
35
+ - Named and documented
36
+
37
+ ### Parameterized Query
38
+
39
+ **Before (raw ActiveRecord):**
40
+ ```ruby
41
+ def users_by_status(status)
42
+ User.where(status: status).order(:created_at)
43
+ end
44
+ ```
45
+
46
+ **After (Inquery with schema validation):**
47
+ ```ruby
48
+ class FetchUsersByStatus < Inquery::Query
49
+ schema3 do
50
+ str! :status
51
+ end
52
+
53
+ def call
54
+ User.where(status: osparams.status).order(:created_at)
55
+ end
56
+ end
57
+
58
+ # Usage
59
+ FetchUsersByStatus.run(status: 'active')
60
+ ```
61
+
62
+ **Benefits:**
63
+ - Automatic parameter validation
64
+ - Type checking
65
+ - Clear API documentation through schema
66
+
67
+ ### Complex Query with Post-Processing
68
+
69
+ **Before:**
70
+ ```ruby
71
+ def user_statistics
72
+ users = User.where(active: true)
73
+ {
74
+ total: users.count,
75
+ premium: users.where(plan: 'premium').count
76
+ }
77
+ end
78
+ ```
79
+
80
+ **After:**
81
+ ```ruby
82
+ class FetchUserStatistics < Inquery::Query
83
+ def call
84
+ User.where(active: true)
85
+ end
86
+
87
+ def process(users)
88
+ {
89
+ total: users.count,
90
+ premium: users.where(plan: 'premium').count
91
+ }
92
+ end
93
+ end
94
+ ```
95
+
96
+ **Benefits:**
97
+ - Separation of query logic and data transformation
98
+ - Can call with 'call' to get raw results or 'run' for processed results
99
+
100
+ ### Scope to Chainable Query
101
+
102
+ **Before:**
103
+ ```ruby
104
+ class User < ActiveRecord::Base
105
+ scope :active, -> { where(active: true) }
106
+ scope :premium, -> { where(plan: 'premium') }
107
+ end
108
+
109
+ # Usage
110
+ User.active.premium
111
+ ```
112
+
113
+ **After:**
114
+ ```ruby
115
+ class FetchActiveUsers < Inquery::Query::Chainable
116
+ relation class: 'User'
117
+
118
+ def call
119
+ relation.where(active: true)
120
+ end
121
+ end
122
+
123
+ class FetchPremiumUsers < Inquery::Query::Chainable
124
+ relation class: 'User'
125
+
126
+ def call
127
+ relation.where(plan: 'premium')
128
+ end
129
+ end
130
+
131
+ # Usage as query classes
132
+ FetchPremiumUsers.run(FetchActiveUsers.run)
133
+
134
+ # Or register as scopes
135
+ class User < ActiveRecord::Base
136
+ scope :active, FetchActiveUsers
137
+ scope :premium, FetchPremiumUsers
138
+ end
139
+
140
+ User.active.premium
141
+ ```
142
+
143
+ **Benefits:**
144
+ - Full Ruby classes instead of lambdas
145
+ - Can add tests, documentation, and complex logic
146
+ - Chainable and composable
147
+
148
+ ## Schema Validation: Schemacop v2 vs v3
149
+
150
+ Inquery supports both Schemacop v2 and v3 schemas. The default is v2 for backward compatibility.
151
+
152
+ ### Using Schemacop v2 (default)
153
+
154
+ ```ruby
155
+ class FetchUsers < Inquery::Query
156
+ schema do
157
+ req :status, :string
158
+ opt :limit, :integer
159
+ end
160
+
161
+ def call
162
+ User.where(status: osparams.status)
163
+ .limit(osparams.limit || 10)
164
+ end
165
+ end
166
+ ```
167
+
168
+ ### Using Schemacop v3 (recommended)
169
+
170
+ ```ruby
171
+ class FetchUsers < Inquery::Query
172
+ schema3 do
173
+ str! :status
174
+ int? :limit
175
+ end
176
+
177
+ def call
178
+ User.where(status: osparams.status)
179
+ .limit(osparams.limit || 10)
180
+ end
181
+ end
182
+ ```
183
+
184
+ ### Configuring Default Schema Version
185
+
186
+ To use Schemacop v3 by default for all queries:
187
+
188
+ ```ruby
189
+ # config/initializers/inquery.rb
190
+ Inquery.setup do |config|
191
+ config.default_schema_version = 3
192
+ end
193
+
194
+ # Now you can use 'schema' instead of 'schema3'
195
+ class FetchUsers < Inquery::Query
196
+ schema do
197
+ str! :status
198
+ int? :limit
199
+ end
200
+
201
+ def call
202
+ User.where(status: osparams.status)
203
+ end
204
+ end
205
+ ```
206
+
207
+ ## Best Practices
208
+
209
+ ### Query Organization
210
+
211
+ Organize queries by domain:
212
+
213
+ ```
214
+ app/queries/
215
+ ├── user/
216
+ │ ├── fetch_active.rb
217
+ │ ├── fetch_by_email.rb
218
+ │ └── search.rb
219
+ ├── order/
220
+ │ ├── fetch_recent.rb
221
+ │ └── fetch_by_status.rb
222
+ └── base_query.rb
223
+ ```
224
+
225
+ ### Testing
226
+
227
+ Test queries in isolation:
228
+
229
+ ```ruby
230
+ # test/queries/fetch_active_users_test.rb
231
+ class FetchActiveUsersTest < ActiveSupport::TestCase
232
+ test 'returns only active users' do
233
+ active_user = create(:user, active: true)
234
+ inactive_user = create(:user, active: false)
235
+
236
+ result = FetchActiveUsers.run
237
+
238
+ assert_includes result, active_user
239
+ refute_includes result, inactive_user
240
+ end
241
+ end
242
+ ```
243
+
244
+ ### Naming Conventions
245
+
246
+ - Use descriptive names: `FetchActiveUsers`, not `Users`
247
+ - Prefix with verb: `Fetch`, `Create`, `Update`, `Delete`
248
+ - Organize in modules: `User::FetchActive`, `Order::FetchRecent`
249
+
250
+ ### When to Use Query vs. Chainable
251
+
252
+ **Use `Inquery::Query` when:**
253
+ - Query doesn't need to be chained
254
+ - Result needs post-processing
255
+ - Query uses raw SQL
256
+
257
+ **Use `Inquery::Query::Chainable` when:**
258
+ - Query needs to be chainable
259
+ - Using as ActiveRecord scope
260
+ - Input and output are both relations
data/README.md CHANGED
@@ -23,15 +23,21 @@ gem 'inquery'
23
23
 
24
24
  ## Compatibility
25
25
 
26
- Inquery is tested with the following ruby versions:
26
+ Inquery is tested against multiple Ruby and Rails version combinations. The following table shows the compatibility matrix:
27
27
 
28
- * 2.5.1
29
- * 2.6.2
30
- * 2.7.1
31
- * 3.0.1
32
- * 3.2.1
28
+ | Ruby Version | Rails 5.2 | Rails 6.0 | Rails 6.1 | Rails 7.0 | Rails 7.1 | Rails 7.2 | Rails 8.0 | Rails 8.1 |
29
+ |--------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
30
+ | 2.6.2 | ✓ | ✓ | ✓ | - | - | - | - | - |
31
+ | 2.7.1 | - | ✓ | ✓ | ✓ | - | - | - | - |
32
+ | 3.0.1 | - | - | ✓ | ✓ | - | - | - | - |
33
+ | 3.1.0 | - | - | - | ✓ | ✓ | - | - | - |
34
+ | 3.2.0 | - | - | - | ✓ | ✓ | ✓ | - | - |
35
+ | 3.3.0 | - | - | - | ✓ | ✓ | ✓ | ✓ | ✓ |
36
+ | 3.4.1 | - | - | - | - | - | ✓ | ✓ | ✓ |
33
37
 
34
- Other ruby versions might work but are not covered by our automated tests.
38
+ **Minimum supported versions:** Ruby 2.6.2 and Rails 5.2
39
+
40
+ Other Ruby/Rails version combinations might work but are not covered by our automated tests.
35
41
 
36
42
  ## Basic usage
37
43
 
@@ -283,8 +289,11 @@ raised if the given params do not match the schema specified. See documentation
283
289
  of the Schemacop Gem for more information on how to specify schemas.
284
290
 
285
291
  Parameters can be accessed using either `params` or `osparams`. The method
286
- `osparams` automatically wraps `params` in an `OpenStruct` for more convenient
287
- access.
292
+ `osparams` wraps `params` in a `MethodAccessibleHash`, allowing access to the
293
+ top-level parameters via dot notation (e.g. `osparams.search`) in addition to
294
+ the usual `[]` access. Unlike a plain `Hash`, a `MethodAccessibleHash` does not
295
+ expose the `Hash`/`Enumerable` API, so keys named like Hash methods (e.g.
296
+ `count`, `select`, `zip`) still return their stored value.
288
297
 
289
298
  ```ruby
290
299
  class SomeQueryClass < Inquery::Query
@@ -353,4 +362,4 @@ post](http://craftingruby.com/posts/2015/06/29/query-objects-through-scopes.html
353
362
 
354
363
  ## Copyright
355
364
 
356
- Copyright © 2016 - 2023 Sitrox. See `LICENSE` for further details.
365
+ Copyright © 2016 - 2026 Sitrox. See `LICENSE` for further details.
data/RUBY_VERSION CHANGED
@@ -1 +1 @@
1
- ruby-3.0.1-p64
1
+ ruby-3.3.5