@@ -113,26 +113,23 @@ def _implemenmt_query(self, repository_type: Type[CrudRepository]) -> None:
113113 def _create_parameter_field_mapping (self , param_names : list [str ], field_names : list [str ]) -> dict [str , str ]:
114114 """
115115 Create a mapping between parameter names and field names.
116- This allows for more readable API design where parameter names can be plural
117- while still mapping to singular field names.
118116
119- The method validates that parameter names correspond to field names and provides
120- clear error messages for mismatches.
117+ Supports exact matching and common plural-to-singular mapping:
118+ - Exact match: 'name' -> 'name'
119+ - Plural to singular: 'names' -> 'name', 'ages' -> 'age'
120+
121+ Rules:
122+ 1. Parameter names must match field names exactly, OR
123+ 2. Parameter names can be plural forms of field names (add 's')
124+ 3. No ambiguity allowed (e.g., can't have both 'name' and 'names' as fields)
121125
122126 Examples:
123- - param_names: ['names'], field_names: ['name'] -> {'names': 'name'}
124- - param_names: ['ages'], field_names: ['age'] -> {'ages': 'age'}
125127 - param_names: ['name', 'age'], field_names: ['name', 'age'] -> {'name': 'name', 'age': 'age'}
128+ - param_names: ['names', 'ages'], field_names: ['name', 'age'] -> {'names': 'name', 'ages': 'age'}
129+ - param_names: ['name', 'ages'], field_names: ['name', 'age'] -> {'name': 'name', 'ages': 'age'}
126130 """
127- if len (param_names ) != len (field_names ):
128- raise ValueError (
129- f"Parameter count mismatch. Expected { len (field_names )} parameters for fields { field_names } , "
130- f"but got { len (param_names )} parameters: { param_names } "
131- )
132-
133131 mapping = {}
134132 unmatched_params = []
135- unmatched_fields = []
136133
137134 # Create a set of field names for efficient lookup
138135 field_set = set (field_names )
@@ -143,69 +140,53 @@ def _create_parameter_field_mapping(self, param_names: list[str], field_names: l
143140 mapping [param_name ] = param_name
144141 continue
145142
146- # Try singular/plural variations
147- singular_match = None
148- plural_match = None
149-
150- # Check if param_name is plural and field_name is singular
143+ # Try plural-to-singular mapping (only if param ends with 's' and is longer than 1 char)
151144 if param_name .endswith ('s' ) and len (param_name ) > 1 :
152- singular_candidate = param_name [:- 1 ]
145+ # Handle special cases for words ending with 's'
146+ if param_name .endswith ('ies' ):
147+ # words ending with 'ies' -> 'y' (e.g., 'categories' -> 'category')
148+ singular_candidate = param_name [:- 3 ] + 'y'
149+ elif param_name .endswith ('ses' ):
150+ # words ending with 'ses' -> 's' (e.g., 'statuses' -> 'status')
151+ singular_candidate = param_name [:- 2 ]
152+ else :
153+ # regular plural: remove 's'
154+ singular_candidate = param_name [:- 1 ]
155+
153156 if singular_candidate in field_set :
154- singular_match = singular_candidate
155-
156- # Check if param_name is singular and field_name is plural
157- elif not param_name .endswith ('s' ):
158- plural_candidate = param_name + 's'
159- if plural_candidate in field_set :
160- plural_match = plural_candidate
157+ # Check for ambiguity: make sure we don't have both singular and plural forms as fields
158+ plural_candidate = singular_candidate + 's'
159+ if plural_candidate not in field_set :
160+ mapping [param_name ] = singular_candidate
161+ continue
161162
162- # Use the best match found
163- if singular_match :
164- mapping [param_name ] = singular_match
165- elif plural_match :
166- mapping [param_name ] = plural_match
167- else :
168- unmatched_params .append (param_name )
163+ # No match found
164+ unmatched_params .append (param_name )
169165
170- # Check for unmatched fields
171- mapped_fields = set (mapping .values ())
172- for field_name in field_names :
173- if field_name not in mapped_fields :
174- unmatched_fields .append (field_name )
175-
176- # Report any mismatches
177- if unmatched_params or unmatched_fields :
166+ # Check if all parameters were mapped
167+ if unmatched_params :
178168 error_msg = "Parameter to field mapping failed:\n "
179- if unmatched_params :
180- error_msg += f" Unmatched parameters: { unmatched_params } \n "
181- if unmatched_fields :
182- error_msg += f" Unmatched fields: { unmatched_fields } \n "
169+ error_msg += f" Unmatched parameters: { unmatched_params } \n "
183170 error_msg += f" Available fields: { field_names } \n "
184- error_msg += f" Provided parameters: { param_names } "
171+ error_msg += f" Provided parameters: { param_names } \n "
172+ error_msg += " Note: Parameters must exactly match field names or be plural forms (add 's')"
185173 raise ValueError (error_msg )
186174
187175 return mapping
188176
189177 def create_implementation_wrapper (self , query : _Query , model_type : Type [PySpringModel ], original_func_annotations : dict [str , Any ], param_to_field_mapping : dict [str , str ]) -> Callable [..., Any ]:
190178 def wrapper (* args , ** kwargs ) -> Any :
191179 if len (query .required_fields ) > 0 :
192- # Map parameter names to field names
180+ # Simple mapping: parameter names must match field names exactly
193181 field_kwargs = {}
194182 for param_name , value in kwargs .items ():
195183 if param_name in param_to_field_mapping :
196184 field_name = param_to_field_mapping [param_name ]
197185 field_kwargs [field_name ] = value
198186 else :
199- # Fallback: use parameter name as field name
200- field_kwargs [param_name ] = value
201-
202- # Check if all required fields are present
203- if set (query .required_fields ) != set (field_kwargs .keys ()):
204- raise ValueError (
205- f"Invalid number of keyword arguments. Expected { query .required_fields } , received { list (kwargs .keys ())} ."
206- )
187+ raise ValueError (f"Unknown parameter '{ param_name } '. Expected parameters: { list (param_to_field_mapping .keys ())} " )
207188
208- # Execute the query with mapped field names
189+ # Execute the query
209190 sql_statement = self ._get_sql_statement (model_type , query , field_kwargs )
210191 result = self ._session_execute (sql_statement , query .is_one_result )
211192 logger .info (f"Executing query with params: { kwargs } " )
0 commit comments