@@ -18,25 +18,106 @@ module Extensions
1818 module Params
1919 def self . included ( klass )
2020 klass . extend ( ClassMethods )
21+ klass . prepend ( InstanceMethods )
22+ end
23+
24+ # Instance methods for params validation
25+ module InstanceMethods
26+ include Dry ::Monads ::Result ::Mixin
27+
28+ # Validates input against the params schema
29+ #
30+ # @param input [Hash] The input to validate
31+ # @return [Dry::Monads::Result] Success with validated params or Failure with errors
32+ # @api private
33+ def validate_params ( input )
34+ schema = self . class . _params_schema
35+
36+ return Success ( input ) unless schema
37+
38+ result = schema . call ( input )
39+
40+ if result . success?
41+ Success ( result . to_h )
42+ else
43+ Failure [ :invalid_params , result . errors . to_h ]
44+ end
45+ end
2146 end
2247
2348 # Class methods added to the operation class
2449 module ClassMethods
2550 # Define a params schema for validating operation inputs
2651 #
27- # The block is passed to `Dry::Schema.Params` to define the validation rules.
52+ # Accepts either a schema class or a block for defining validation rules.
2853 #
54+ # @param schema_class [Class, nil] A dry-schema class to use for validation
2955 # @yield Block for defining the schema using dry-schema DSL
3056 # @return [Dry::Schema::Params] The compiled schema
31- def params ( &block )
32- @_params_schema = Dry ::Schema . Params ( &block )
57+ #
58+ # @example Using a block
59+ # params do
60+ # required(:name).filled(:string)
61+ # end
62+ #
63+ # @example Using a schema class
64+ # class UserSchema < Dry::Schema::Params
65+ # define do
66+ # required(:name).filled(:string)
67+ # end
68+ # end
69+ #
70+ # params UserSchema
71+ def params ( schema_class = nil , &block )
72+ @_params_schema = if schema_class
73+ schema_class . is_a? ( Class ) ? schema_class . new : schema_class
74+ elsif block
75+ Dry ::Schema . Params ( &block )
76+ else
77+ raise ArgumentError , "params requires either a schema class or a block"
78+ end
79+ _apply_params_validation
3380 end
3481
3582 # @api private
3683 def _params_schema
3784 @_params_schema
3885 end
3986
87+ # @api private
88+ def _params_validated_methods
89+ @_params_validated_methods ||= [ ]
90+ end
91+
92+ # @api private
93+ def _apply_params_validation
94+ methods_to_wrap = instance_variable_get ( :@_prepend_manager )
95+ &.instance_variable_get ( :@methods_to_prepend ) || [ ]
96+
97+ methods_to_wrap . each do |method_name |
98+ next if _params_validated_methods . include? ( method_name )
99+ next unless instance_methods . include? ( method_name )
100+
101+ prepend ( Params . create_validator_for ( method_name ) )
102+ _params_validated_methods << method_name
103+ end
104+ end
105+
106+ # @api private
107+ def method_added ( method_name )
108+ if @_params_schema
109+ methods_to_wrap = instance_variable_get ( :@_prepend_manager )
110+ &.instance_variable_get ( :@methods_to_prepend ) || [ ]
111+
112+ if methods_to_wrap . include? ( method_name ) && !_params_validated_methods . include? ( method_name )
113+ prepend ( Params . create_validator_for ( method_name ) )
114+ _params_validated_methods << method_name
115+ end
116+ end
117+
118+ super
119+ end
120+
40121 # @api private
41122 def inherited ( subclass )
42123 super
@@ -45,6 +126,32 @@ def inherited(subclass)
45126 end
46127 end
47128 end
129+
130+ # @api private
131+ # Creates a module that wraps a method to add params validation
132+ def self . create_validator_for ( method_name )
133+ Module . new do
134+ define_method ( method_name ) do |input = { } , *rest , **kwargs , &block |
135+ use_kwargs = input . empty? && !kwargs . empty? && rest . empty?
136+ actual_input = use_kwargs ? kwargs : input
137+
138+ validation_result = validate_params ( actual_input )
139+
140+ case validation_result
141+ when Dry ::Monads ::Success
142+ validated_input = validation_result . value!
143+
144+ if use_kwargs
145+ super ( **validated_input , &block )
146+ else
147+ super ( validated_input , *rest , **kwargs , &block )
148+ end
149+ when Dry ::Monads ::Failure
150+ throw_failure ( validation_result )
151+ end
152+ end
153+ end
154+ end
48155 end
49156 end
50157 end
0 commit comments