better_model 2.1.0 → 3.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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +96 -13
  3. data/lib/better_model/archivable.rb +203 -91
  4. data/lib/better_model/errors/archivable/already_archived_error.rb +11 -0
  5. data/lib/better_model/errors/archivable/archivable_error.rb +13 -0
  6. data/lib/better_model/errors/archivable/configuration_error.rb +10 -0
  7. data/lib/better_model/errors/archivable/not_archived_error.rb +11 -0
  8. data/lib/better_model/errors/archivable/not_enabled_error.rb +11 -0
  9. data/lib/better_model/errors/better_model_error.rb +9 -0
  10. data/lib/better_model/errors/permissible/configuration_error.rb +9 -0
  11. data/lib/better_model/errors/permissible/permissible_error.rb +13 -0
  12. data/lib/better_model/errors/predicable/configuration_error.rb +9 -0
  13. data/lib/better_model/errors/predicable/predicable_error.rb +13 -0
  14. data/lib/better_model/errors/searchable/configuration_error.rb +9 -0
  15. data/lib/better_model/errors/searchable/invalid_order_error.rb +11 -0
  16. data/lib/better_model/errors/searchable/invalid_pagination_error.rb +11 -0
  17. data/lib/better_model/errors/searchable/invalid_predicate_error.rb +11 -0
  18. data/lib/better_model/errors/searchable/invalid_security_error.rb +11 -0
  19. data/lib/better_model/errors/searchable/searchable_error.rb +13 -0
  20. data/lib/better_model/errors/sortable/configuration_error.rb +10 -0
  21. data/lib/better_model/errors/sortable/sortable_error.rb +13 -0
  22. data/lib/better_model/errors/stateable/check_failed_error.rb +14 -0
  23. data/lib/better_model/errors/stateable/configuration_error.rb +10 -0
  24. data/lib/better_model/errors/stateable/invalid_state_error.rb +11 -0
  25. data/lib/better_model/errors/stateable/invalid_transition_error.rb +11 -0
  26. data/lib/better_model/errors/stateable/not_enabled_error.rb +11 -0
  27. data/lib/better_model/errors/stateable/stateable_error.rb +13 -0
  28. data/lib/better_model/errors/stateable/validation_failed_error.rb +11 -0
  29. data/lib/better_model/errors/statusable/configuration_error.rb +9 -0
  30. data/lib/better_model/errors/statusable/statusable_error.rb +13 -0
  31. data/lib/better_model/errors/taggable/configuration_error.rb +10 -0
  32. data/lib/better_model/errors/taggable/taggable_error.rb +13 -0
  33. data/lib/better_model/errors/traceable/configuration_error.rb +10 -0
  34. data/lib/better_model/errors/traceable/not_enabled_error.rb +11 -0
  35. data/lib/better_model/errors/traceable/traceable_error.rb +13 -0
  36. data/lib/better_model/errors/validatable/configuration_error.rb +10 -0
  37. data/lib/better_model/errors/validatable/not_enabled_error.rb +11 -0
  38. data/lib/better_model/errors/validatable/validatable_error.rb +13 -0
  39. data/lib/better_model/models/state_transition.rb +122 -0
  40. data/lib/better_model/models/version.rb +68 -0
  41. data/lib/better_model/permissible.rb +103 -52
  42. data/lib/better_model/predicable.rb +114 -63
  43. data/lib/better_model/repositable/base_repository.rb +232 -0
  44. data/lib/better_model/repositable.rb +32 -0
  45. data/lib/better_model/searchable.rb +92 -92
  46. data/lib/better_model/sortable.rb +137 -41
  47. data/lib/better_model/stateable/configurator.rb +71 -53
  48. data/lib/better_model/stateable/guard.rb +35 -15
  49. data/lib/better_model/stateable/transition.rb +59 -30
  50. data/lib/better_model/stateable.rb +33 -15
  51. data/lib/better_model/statusable.rb +84 -52
  52. data/lib/better_model/taggable.rb +120 -75
  53. data/lib/better_model/traceable.rb +56 -48
  54. data/lib/better_model/validatable/configurator.rb +49 -172
  55. data/lib/better_model/validatable.rb +88 -113
  56. data/lib/better_model/version.rb +1 -1
  57. data/lib/better_model.rb +42 -5
  58. data/lib/generators/better_model/repository/repository_generator.rb +141 -0
  59. data/lib/generators/better_model/repository/templates/application_repository.rb.tt +21 -0
  60. data/lib/generators/better_model/repository/templates/repository.rb.tt +71 -0
  61. data/lib/generators/better_model/stateable/templates/README +1 -1
  62. metadata +44 -7
  63. data/lib/better_model/state_transition.rb +0 -106
  64. data/lib/better_model/stateable/errors.rb +0 -48
  65. data/lib/better_model/validatable/business_rule_validator.rb +0 -47
  66. data/lib/better_model/validatable/order_validator.rb +0 -77
  67. data/lib/better_model/version_record.rb +0 -66
@@ -1,11 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Permissible - Sistema di permessi dichiarativi per modelli Rails
3
+ require_relative "errors/permissible/permissible_error"
4
+ require_relative "errors/permissible/configuration_error"
5
+
6
+ # Permissible - Declarative permissions system for Rails models.
4
7
  #
5
- # Questo concern permette di definire permessi/capacità sui modelli utilizzando un DSL
6
- # semplice e dichiarativo, simile al pattern Statusable ma per le operazioni.
8
+ # This concern enables defining permissions/capabilities on models using a simple,
9
+ # declarative DSL, similar to the Statusable pattern but for operations.
7
10
  #
8
- # Esempio di utilizzo:
11
+ # @example Basic Usage
9
12
  # class Article < ApplicationRecord
10
13
  # include BetterModel::Permissible
11
14
  #
@@ -15,7 +18,7 @@
15
18
  # permit :archive, -> { is?(:published) && created_at < 1.year.ago }
16
19
  # end
17
20
  #
18
- # Utilizzo:
21
+ # @example Checking Permissions
19
22
  # article.permit?(:delete) # => true/false
20
23
  # article.permit_delete? # => true/false
21
24
  # article.permit_edit? # => true/false
@@ -26,58 +29,85 @@ module BetterModel
26
29
  extend ActiveSupport::Concern
27
30
 
28
31
  included do
29
- # Registry dei permessi definiti per questa classe
32
+ # Registry of permissions defined for this class
30
33
  class_attribute :permit_definitions
31
34
  self.permit_definitions = {}
32
35
  end
33
36
 
34
37
  class_methods do
35
- # DSL per definire permessi
38
+ # DSL to define permissions.
39
+ #
40
+ # Defines a permission check that can be evaluated against model instances.
41
+ # Automatically creates a convenience method permit_<permission_name>? for each permission.
36
42
  #
37
- # Parametri:
38
- # - permission_name: simbolo che rappresenta il permesso (es. :delete, :edit)
39
- # - condition_proc: lambda o proc che definisce la condizione
40
- # - block: blocco alternativo alla condition_proc
43
+ # @param permission_name [Symbol, String] Permission identifier (e.g., :delete, :edit)
44
+ # @param condition_proc [Proc, nil] Lambda or proc that defines the condition
45
+ # @yield Alternative to condition_proc parameter
46
+ # @raise [BetterModel::Errors::Permissible::ConfigurationError] If parameters are invalid
41
47
  #
42
- # Esempi:
48
+ # @example With lambda parameter
43
49
  # permit :delete, -> { status != "published" }
44
- # permit :edit, -> { is?(:draft) }
50
+ #
51
+ # @example With block
52
+ # permit :edit do
53
+ # is?(:draft)
54
+ # end
55
+ #
56
+ # @example Complex condition
45
57
  # permit :publish do
46
58
  # is?(:draft) && valid?(:publication)
47
59
  # end
48
60
  def permit(permission_name, condition_proc = nil, &block)
49
- # Valida i parametri prima di convertire
50
- raise ArgumentError, "Permission name cannot be blank" if permission_name.blank?
61
+ # Validate parameters before converting
62
+ if permission_name.blank?
63
+ raise BetterModel::Errors::Permissible::ConfigurationError, "Permission name cannot be blank"
64
+ end
51
65
 
52
66
  permission_name = permission_name.to_sym
53
67
  condition = condition_proc || block
54
- raise ArgumentError, "Condition proc or block is required" unless condition
55
- raise ArgumentError, "Condition must respond to call" unless condition.respond_to?(:call)
56
68
 
57
- # Registra il permesso nel registry
69
+ unless condition
70
+ raise BetterModel::Errors::Permissible::ConfigurationError, "Condition proc or block is required"
71
+ end
72
+
73
+ unless condition.respond_to?(:call)
74
+ raise BetterModel::Errors::Permissible::ConfigurationError, "Condition must respond to call"
75
+ end
76
+
77
+ # Register permission in registry
58
78
  self.permit_definitions = permit_definitions.merge(permission_name => condition.freeze).freeze
59
79
 
60
- # Genera il metodo dinamico permit_#{permission_name}?
80
+ # Generate dynamic method permit_#{permission_name}?
61
81
  define_permit_method(permission_name)
62
82
  end
63
83
 
64
- # Lista di tutti i permessi definiti per questa classe
65
- def defined_permissions
66
- permit_definitions.keys
67
- end
84
+ # List all permissions defined for this class.
85
+ #
86
+ # @return [Array<Symbol>] Array of defined permission names
87
+ #
88
+ # @example
89
+ # Article.defined_permissions # => [:delete, :edit, :publish]
90
+ def defined_permissions = permit_definitions.keys
68
91
 
69
- # Verifica se un permesso è definito
70
- def permission_defined?(permission_name)
71
- permit_definitions.key?(permission_name.to_sym)
72
- end
92
+ # Check if a permission is defined.
93
+ #
94
+ # @param permission_name [Symbol, String] Permission name to check
95
+ # @return [Boolean] true if permission is defined
96
+ #
97
+ # @example
98
+ # Article.permission_defined?(:delete) # => true
99
+ def permission_defined?(permission_name) = permit_definitions.key?(permission_name.to_sym)
73
100
 
74
101
  private
75
102
 
76
- # Genera dinamicamente il metodo permit_#{permission_name}? per ogni permesso definito
103
+ # Generate dynamic method permit_#{permission_name}? for each defined permission.
104
+ #
105
+ # @param permission_name [Symbol] Permission name
106
+ # @api private
77
107
  def define_permit_method(permission_name)
78
108
  method_name = "permit_#{permission_name}?"
79
109
 
80
- # Evita di ridefinire metodi se già esistono
110
+ # Avoid redefining methods if they already exist
81
111
  return if method_defined?(method_name)
82
112
 
83
113
  define_method(method_name) do
@@ -86,35 +116,33 @@ module BetterModel
86
116
  end
87
117
  end
88
118
 
89
- # Metodo generico per verificare se un permesso è garantito
119
+ # Generic method to check if a permission is granted.
90
120
  #
91
- # Parametri:
92
- # - permission_name: simbolo del permesso da verificare
121
+ # Evaluates the permission condition in the context of the model instance.
122
+ # Returns false if permission is not defined (secure by default).
93
123
  #
94
- # Ritorna:
95
- # - true se il permesso è garantito
96
- # - false se il permesso non è garantito o non è definito
124
+ # @param permission_name [Symbol, String] Permission name to check
125
+ # @return [Boolean] true if permission is granted, false otherwise
97
126
  #
98
- # Esempio:
99
- # article.permit?(:delete)
127
+ # @example
128
+ # article.permit?(:delete) # => true
100
129
  def permit?(permission_name)
101
130
  permission_name = permission_name.to_sym
102
131
  condition = self.class.permit_definitions[permission_name]
103
132
 
104
- # Se il permesso non è definito, ritorna false (secure by default)
133
+ # If permission is not defined, return false (secure by default)
105
134
  return false unless condition
106
135
 
107
- # Valuta la condizione nel contesto dell'istanza del modello
108
- # Gli errori si propagano naturalmente - fail fast
136
+ # Evaluate condition in context of model instance
137
+ # Errors propagate naturally - fail fast
109
138
  instance_exec(&condition)
110
139
  end
111
140
 
112
- # Ritorna tutti i permessi disponibili per questa istanza con i loro valori
141
+ # Returns all available permissions for this instance with their values.
113
142
  #
114
- # Ritorna:
115
- # - Hash con chiavi simbolo (permessi) e valori booleani (garantiti/negati)
143
+ # @return [Hash{Symbol => Boolean}] Hash with permission names and their granted status
116
144
  #
117
- # Esempio:
145
+ # @example
118
146
  # article.permissions
119
147
  # # => { delete: true, edit: false, publish: false, archive: false }
120
148
  def permissions
@@ -123,26 +151,49 @@ module BetterModel
123
151
  end
124
152
  end
125
153
 
126
- # Verifica se l'istanza ha almeno un permesso garantito
127
- def has_any_permission?
128
- permissions.values.any?
129
- end
154
+ # Check if instance has at least one granted permission.
155
+ #
156
+ # @return [Boolean] true if any permission is granted
157
+ #
158
+ # @example
159
+ # article.has_any_permission? # => true
160
+ def has_any_permission? = permissions.values.any?
130
161
 
131
- # Verifica se l'istanza ha tutti i permessi specificati garantiti
162
+ # Check if instance has all specified permissions granted.
163
+ #
164
+ # @param permission_names [Array<Symbol>] Permission names to check
165
+ # @return [Boolean] true if all permissions are granted
166
+ #
167
+ # @example
168
+ # article.has_all_permissions?([:edit, :publish]) # => false
132
169
  def has_all_permissions?(permission_names)
133
170
  Array(permission_names).all? { |permission_name| permit?(permission_name) }
134
171
  end
135
172
 
136
- # Filtra una lista di permessi restituendo solo quelli garantiti
173
+ # Filter a list of permissions returning only granted ones.
174
+ #
175
+ # @param permission_names [Array<Symbol>] Permission names to filter
176
+ # @return [Array<Symbol>] Granted permissions
177
+ #
178
+ # @example
179
+ # article.granted_permissions([:edit, :delete, :publish]) # => [:edit]
137
180
  def granted_permissions(permission_names)
138
181
  Array(permission_names).select { |permission_name| permit?(permission_name) }
139
182
  end
140
183
 
141
- # Override di as_json per includere automaticamente i permessi se richiesto
184
+ # Override as_json to automatically include permissions if requested.
185
+ #
186
+ # @param options [Hash] Options for as_json
187
+ # @option options [Boolean] :include_permissions Include permissions in JSON output
188
+ # @return [Hash] JSON representation
189
+ #
190
+ # @example
191
+ # article.as_json(include_permissions: true)
192
+ # # => { ..., "permissions" => { "delete" => true, "edit" => false } }
142
193
  def as_json(options = {})
143
194
  result = super
144
195
 
145
- # Include i permessi se esplicitamente richiesto, converting symbol keys to strings
196
+ # Include permissions if explicitly requested, converting symbol keys to strings
146
197
  result["permissions"] = permissions.transform_keys(&:to_s) if options[:include_permissions]
147
198
 
148
199
  result
@@ -1,18 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Predicable - Sistema di filtri/predicati dichiarativo per modelli Rails
3
+ require_relative "errors/predicable/predicable_error"
4
+ require_relative "errors/predicable/configuration_error"
5
+
6
+ # Predicable - Declarative filters/predicates system for Rails models.
4
7
  #
5
- # Questo concern permette di definire predicati di ricerca sui modelli utilizzando un DSL
6
- # semplice e dichiarativo che genera automaticamente scope basati sul tipo di colonna.
8
+ # This concern enables defining search predicates on models using a simple, declarative DSL
9
+ # that automatically generates scopes based on column type.
7
10
  #
8
- # Esempio di utilizzo:
11
+ # @example Basic Usage
9
12
  # class Article < ApplicationRecord
10
13
  # include BetterModel::Predicable
11
14
  #
12
15
  # predicates :title, :status, :view_count, :published_at, :featured
13
16
  # end
14
17
  #
15
- # Utilizzo:
18
+ # @example Generated Scopes
16
19
  # Article.title_eq("Ruby on Rails") # WHERE title = 'Ruby on Rails'
17
20
  # Article.title_i_cont("rails") # WHERE LOWER(title) LIKE '%rails%'
18
21
  # Article.view_count_gt(100) # WHERE view_count > 100
@@ -25,38 +28,40 @@ module BetterModel
25
28
  extend ActiveSupport::Concern
26
29
 
27
30
  included do
28
- # Valida che sia incluso solo in modelli ActiveRecord
31
+ # Validate ActiveRecord inheritance
29
32
  unless ancestors.include?(ActiveRecord::Base)
30
- raise ArgumentError, "BetterModel::Predicable can only be included in ActiveRecord models"
33
+ raise BetterModel::Errors::Predicable::ConfigurationError, "BetterModel::Predicable can only be included in ActiveRecord models"
31
34
  end
32
35
 
33
- # Registry dei campi predicable definiti per questa classe
36
+ # Registry of predicable fields defined for this class
34
37
  class_attribute :predicable_fields, default: Set.new
35
- # Registry degli scope predicable generati
38
+ # Registry of generated predicable scopes
36
39
  class_attribute :predicable_scopes, default: Set.new
37
- # Registry dei predicati complessi custom
40
+ # Registry of custom complex predicates
38
41
  class_attribute :complex_predicates_registry, default: {}.freeze
39
42
  end
40
43
 
41
44
  class_methods do
42
- # DSL per definire campi predicable
45
+ # DSL to define predicable fields.
43
46
  #
44
- # Genera automaticamente scope di filtro basati sul tipo di colonna:
47
+ # Automatically generates filter scopes based on column type:
45
48
  # - String: _eq, _not_eq, _matches, _start, _end, _cont, _not_cont, _i_cont, _not_i_cont, _in, _not_in, _present(bool), _blank(bool), _null(bool)
46
49
  # - Numeric: _eq, _not_eq, _lt, _lteq, _gt, _gteq, _between, _not_between, _in, _not_in, _present(bool)
47
50
  # - Boolean: _eq, _not_eq, _present(bool)
48
51
  # - Date: _eq, _not_eq, _lt, _lteq, _gt, _gteq, _between, _not_between, _in, _not_in, _within(duration), _blank(bool), _null(bool)
49
52
  #
50
- # Nota: Tutti i predicati richiedono parametri espliciti. Use _eq(true)/_eq(false) per booleani.
53
+ # @param field_names [Array<Symbol>] Field names to make predicable
54
+ #
55
+ # @note All predicates require explicit parameters. Use _eq(true)/_eq(false) for booleans.
51
56
  #
52
- # Esempio:
57
+ # @example
53
58
  # predicates :title, :view_count, :published_at, :featured
54
59
  def predicates(*field_names)
55
60
  field_names.each do |field_name|
56
61
  validate_predicable_field!(field_name)
57
62
  register_predicable_field(field_name)
58
63
 
59
- # Auto-rileva tipo e genera scope appropriati
64
+ # Auto-detect type and generate appropriate scopes
60
65
  column = columns_hash[field_name.to_s]
61
66
  next unless column
62
67
 
@@ -85,65 +90,88 @@ module BetterModel
85
90
  end
86
91
  end
87
92
 
88
- # Registra un predicato complesso custom
93
+ # Register a custom complex predicate.
89
94
  #
90
- # Permette di definire filtri complessi che combinano più condizioni
91
- # o utilizzano logica custom non coperta dai predicati standard.
95
+ # Allows defining complex filters that combine multiple conditions
96
+ # or use custom logic not covered by standard predicates.
92
97
  #
93
- # Esempio:
98
+ # @param name [Symbol] Predicate name
99
+ # @yield Predicate implementation block
100
+ # @raise [BetterModel::Errors::Predicable::ConfigurationError] If block is not provided
101
+ #
102
+ # @example
94
103
  # register_complex_predicate :recent_popular do |days = 7, min_views = 100|
95
104
  # where("published_at >= ? AND view_count >= ?", days.days.ago, min_views)
96
105
  # end
97
106
  #
98
107
  # Article.recent_popular(7, 100)
99
108
  def register_complex_predicate(name, &block)
100
- raise ArgumentError, "Block required for complex predicate" unless block_given?
109
+ unless block_given?
110
+ raise BetterModel::Errors::Predicable::ConfigurationError, "Block required for complex predicate"
111
+ end
101
112
 
102
- # Registra nel registry
113
+ # Register in registry
103
114
  self.complex_predicates_registry = complex_predicates_registry.merge(name.to_sym => block).freeze
104
115
 
105
- # Definisce lo scope
116
+ # Define scope
106
117
  scope name, block
107
118
 
108
- # Registra lo scope
119
+ # Register scope
109
120
  register_predicable_scopes(name)
110
121
  end
111
122
 
112
- # Verifica se un campo è stato registrato come predicable
113
- def predicable_field?(field_name)
114
- predicable_fields.include?(field_name.to_sym)
115
- end
123
+ # Check if a field has been registered as predicable.
124
+ #
125
+ # @param field_name [Symbol] Field name to check
126
+ # @return [Boolean] true if field is predicable
127
+ def predicable_field?(field_name) = predicable_fields.include?(field_name.to_sym)
116
128
 
117
- # Verifica se uno scope predicable è stato generato
118
- def predicable_scope?(scope_name)
119
- predicable_scopes.include?(scope_name.to_sym)
120
- end
129
+ # Check if a predicable scope has been generated.
130
+ #
131
+ # @param scope_name [Symbol] Scope name to check
132
+ # @return [Boolean] true if scope exists
133
+ def predicable_scope?(scope_name) = predicable_scopes.include?(scope_name.to_sym)
121
134
 
122
- # Verifica se un predicato complesso è stato registrato
123
- def complex_predicate?(name)
124
- complex_predicates_registry.key?(name.to_sym)
125
- end
135
+ # Check if a complex predicate has been registered.
136
+ #
137
+ # @param name [Symbol] Predicate name to check
138
+ # @return [Boolean] true if complex predicate exists
139
+ def complex_predicate?(name) = complex_predicates_registry.key?(name.to_sym)
126
140
 
127
141
  private
128
142
 
129
- # Valida che il campo esista nella tabella
143
+ # Validate that field exists in table.
144
+ #
145
+ # @param field_name [Symbol] Field name to validate
146
+ # @raise [BetterModel::Errors::Predicable::ConfigurationError] If field doesn't exist
147
+ # @api private
130
148
  def validate_predicable_field!(field_name)
131
149
  unless column_names.include?(field_name.to_s)
132
- raise ArgumentError, "Invalid field name: #{field_name}. Field does not exist in #{table_name}"
150
+ raise BetterModel::Errors::Predicable::ConfigurationError, "Invalid field name: #{field_name}. Field does not exist in #{table_name}"
133
151
  end
134
152
  end
135
153
 
136
- # Registra un campo nel registry predicable_fields
154
+ # Register a field in predicable_fields registry.
155
+ #
156
+ # @param field_name [Symbol] Field name to register
157
+ # @api private
137
158
  def register_predicable_field(field_name)
138
159
  self.predicable_fields = (predicable_fields + [ field_name.to_sym ]).to_set.freeze
139
160
  end
140
161
 
141
- # Registra scope nel registry predicable_scopes
162
+ # Register scopes in predicable_scopes registry.
163
+ #
164
+ # @param scope_names [Array<Symbol>] Scope names to register
165
+ # @api private
142
166
  def register_predicable_scopes(*scope_names)
143
167
  self.predicable_scopes = (predicable_scopes + scope_names.map(&:to_sym)).to_set.freeze
144
168
  end
145
169
 
146
- # Genera predicati base: _eq, _not_eq, _present
170
+ # Generate base predicates: _eq, _not_eq, _present.
171
+ #
172
+ # @param field_name [Symbol] Field name
173
+ # @param column_type [Symbol, nil] Column type
174
+ # @api private
147
175
  def define_base_predicates(field_name, column_type = nil)
148
176
  table = arel_table
149
177
  field = table[field_name]
@@ -167,9 +195,13 @@ module BetterModel
167
195
  register_predicable_scopes(*scopes_to_register)
168
196
  end
169
197
 
170
- # Genera predicati per campi stringa (14 scope)
171
- # Base predicates (_eq, _not_eq) are defined separately
172
- # _present(bool), _blank(bool), _null(bool) handle presence with parameters
198
+ # Generate predicates for string fields (14 scopes).
199
+ #
200
+ # Base predicates (_eq, _not_eq) are defined separately.
201
+ # _present(bool), _blank(bool), _null(bool) handle presence with parameters.
202
+ #
203
+ # @param field_name [Symbol] Field name
204
+ # @api private
173
205
  def define_string_predicates(field_name)
174
206
  table = arel_table
175
207
  field = table[field_name]
@@ -238,8 +270,12 @@ module BetterModel
238
270
  )
239
271
  end
240
272
 
241
- # Genera predicati per campi numerici (11 scope)
242
- # Base predicates (_eq, _not_eq, _present(bool)) are defined separately
273
+ # Generate predicates for numeric fields (11 scopes).
274
+ #
275
+ # Base predicates (_eq, _not_eq, _present(bool)) are defined separately.
276
+ #
277
+ # @param field_name [Symbol] Field name
278
+ # @api private
243
279
  def define_numeric_predicates(field_name)
244
280
  table = arel_table
245
281
  field = table[field_name]
@@ -271,19 +307,26 @@ module BetterModel
271
307
  )
272
308
  end
273
309
 
274
- # Genera predicati per campi booleani (0 scope)
275
- # Base predicates (_eq, _not_eq, _present) are defined separately
276
- # Use _eq(true) or _eq(false) for boolean filtering
310
+ # Generate predicates for boolean fields (0 scopes).
311
+ #
312
+ # Base predicates (_eq, _not_eq, _present) are defined separately.
313
+ # Use _eq(true) or _eq(false) for boolean filtering.
314
+ #
315
+ # @param field_name [Symbol] Field name
316
+ # @api private
277
317
  def define_boolean_predicates(field_name)
278
318
  # No additional scopes needed for boolean fields
279
319
  # Use field_eq(true) or field_eq(false) instead
280
320
  end
281
321
 
282
- # Genera predicati per campi array PostgreSQL (3 scope)
322
+ # Generate predicates for PostgreSQL array fields (3 scopes).
283
323
  #
284
- # NOTA: Questo metodo non è coperto da test automatici perché richiede
285
- # PostgreSQL. I test vengono eseguiti su SQLite per performance.
286
- # Testare manualmente su PostgreSQL con: rails console RAILS_ENV=test
324
+ # @param field_name [Symbol] Field name
325
+ # @api private
326
+ #
327
+ # @note This method is not covered by automated tests because it requires
328
+ # PostgreSQL. Tests run on SQLite for performance.
329
+ # Test manually on PostgreSQL with: rails console RAILS_ENV=test
287
330
  def define_postgresql_array_predicates(field_name)
288
331
  return unless postgresql_adapter?
289
332
 
@@ -335,11 +378,14 @@ module BetterModel
335
378
  )
336
379
  end
337
380
 
338
- # Genera predicati per campi JSONB PostgreSQL (4 scope)
381
+ # Generate predicates for PostgreSQL JSONB fields (4 scopes).
382
+ #
383
+ # @param field_name [Symbol] Field name
384
+ # @api private
339
385
  #
340
- # NOTA: Questo metodo non è coperto da test automatici perché richiede
341
- # PostgreSQL con supporto JSONB. I test vengono eseguiti su SQLite per performance.
342
- # Testare manualmente su PostgreSQL con: rails console RAILS_ENV=test
386
+ # @note This method is not covered by automated tests because it requires
387
+ # PostgreSQL with JSONB support. Tests run on SQLite for performance.
388
+ # Test manually on PostgreSQL with: rails console RAILS_ENV=test
343
389
  def define_postgresql_jsonb_predicates(field_name)
344
390
  return unless postgresql_adapter?
345
391
 
@@ -388,9 +434,13 @@ module BetterModel
388
434
  )
389
435
  end
390
436
 
391
- # Genera predicati per campi data/datetime (11 scope)
392
- # Base predicates (_eq, _not_eq, _present(bool)) are defined separately
393
- # Date convenience shortcuts removed except _within(duration)
437
+ # Generate predicates for date/datetime fields (11 scopes).
438
+ #
439
+ # Base predicates (_eq, _not_eq, _present(bool)) are defined separately.
440
+ # Date convenience shortcuts removed except _within(duration).
441
+ #
442
+ # @param field_name [Symbol] Field name
443
+ # @api private
394
444
  def define_date_predicates(field_name)
395
445
  table = arel_table
396
446
  field = table[field_name]
@@ -440,10 +490,11 @@ module BetterModel
440
490
  )
441
491
  end
442
492
 
443
- # Verifica se il database adapter è PostgreSQL
444
- def postgresql_adapter?
445
- connection.adapter_name.match?(/PostgreSQL/i)
446
- end
493
+ # Check if database adapter is PostgreSQL.
494
+ #
495
+ # @return [Boolean] true if PostgreSQL adapter
496
+ # @api private
497
+ def postgresql_adapter? = connection.adapter_name.match?(/PostgreSQL/i)
447
498
  end
448
499
  end
449
500
  end