Skip to content

Conversation

@NFUChen
Copy link
Contributor

@NFUChen NFUChen commented Jul 18, 2025

🚀 Add Field Operations Support for Dynamic Query Generation

📋 Summary

This PR introduces comprehensive field operations support to PySpringModel, enabling dynamic query generation similar to Spring Data JPA. Users can now create complex database queries using method naming conventions with various comparison operators and conditions.

✨ New Features

Supported Field Operations

Operation Suffix Description Example
EQUALS (default) Field equals value find_by_name
IN _in Field in list of values find_by_status_in
GREATER_THAN _gt Field greater than value find_by_age_gt
GREATER_EQUAL _gte Field greater than or equal to value find_by_age_gte
LESS_THAN _lt Field less than value find_by_age_lt
LESS_EQUAL _lte Field less than or equal to value find_by_age_lte
LIKE _like Field matches pattern find_by_name_like
NOT_EQUALS _ne Field not equals value find_by_status_ne
NOT_IN _not_in Field not in list of values find_by_category_not_in

Intelligent Parameter Field Mapping

A significant enhancement that improves API quality and developer experience:

  • Exact Matching: Parameter names match field names directly
  • Plural Support: Parameters can use plural forms for better API design
  • Smart Edge Cases: Properly handles words ending with 's' (e.g., statusesstatus)
  • No Ambiguity: Clear rules prevent mapping conflicts
  • Order Independence: Parameter order doesn't need to match field order
# Method: find_by_name_and_age # Fields: ['name', 'age'] # ✅ Exact match def find_by_name_and_age(self, name: str, age: int) -> Optional[User]: ... # ✅ Plural parameters for better API design def find_by_name_and_age(self, names: List[str], ages: List[int]) -> Optional[User]: ... # ✅ Mixed singular and plural def find_by_name_and_age(self, name: str, ages: List[int]) -> Optional[User]: ... # ✅ Handles words ending with 's' correctly def find_by_status(self, statuses: List[str]) -> Optional[User]: ... # statuses → status

Key Capabilities

  • Dynamic Query Generation: Create complex queries using method naming conventions
  • Logical Operators: Combine operations with _and_ and _or_ operators
  • Type Safety: Proper validation for operation-specific parameter types
  • Edge Case Handling: Intelligent handling of empty collections and null values
  • SQL Generation: Automatic SQL generation with proper parameter binding

🔧 Implementation Details

Core Changes

  1. Enhanced Query Builder (method_query_builder.py):

    • Added FieldOperation enum for supported operations
    • Implemented operation detection from method names
    • Added field operation mapping to query parsing
  2. Improved Query Service (crud_repository_implementation_service.py):

    • Refactored SQL statement generation to support field operations
    • Added proper condition building for each operation type
    • Implemented logical operator combination logic
    • Added type validation and edge case handling
  3. Intelligent Parameter Field Mapping:

    • Challenge: Original implementation had order dependency and complex "magic" logic
    • Solution: Implemented clean, predictable mapping with clear rules
    • Key Features:
      • Exact match prioritization (prevents ambiguity)
      • Smart plural-to-singular conversion
      • Special handling for words ending with 's' (statusesstatus)
      • Clear error messages for mapping failures
    • Quality: Balances simplicity with API quality, making methods more intuitive
  4. Comprehensive Testing:

    • Added test_field_operations.py with extensive test coverage
    • Enhanced existing tests to support new field operations
    • Added edge case testing for empty collections and invalid types
    • Added parameter field mapping tests covering all scenarios

Code Example

from py_spring_model import PySpringModel, Field, CrudRepository from typing import List class User(PySpringModel, table=True): id: int = Field(default=None, primary_key=True) name: str age: int status: str = Field(default="active") category: str = Field(default="general") class UserRepository(CrudRepository[int, User]): # Single operations def find_all_by_status_in(self, status: List[str]) -> List[User]: ... def find_by_age_gt(self, age: int) -> User: ... def find_by_name_like(self, name: str) -> List[User]: ... # Combined operations def find_by_age_gt_and_status_in(self, age: int, status: List[str]) -> List[User]: ... def find_by_salary_gte_or_category_in(self, salary: float, category: List[str]) -> List[User]: ... # Usage repo = UserRepository() active_users = repo.find_all_by_status_in(status=["active", "pending"]) adults = repo.find_by_age_gt(age=18) johns = repo.find_by_name_like(name="%John%") senior_active = repo.find_by_age_gt_and_status_in(age=30, status=["active"])

🧪 Testing

  • Unit Tests: Comprehensive test coverage for all field operations
  • Integration Tests: End-to-end testing with actual database operations
  • Edge Cases: Empty collections, invalid types, complex combinations
  • SQL Generation: Verification of generated SQL statements

Test Coverage

  • All 9 supported field operations
  • Logical operator combinations (AND/OR)
  • Type validation and error handling
  • Empty collection edge cases
  • Complex multi-field queries

📚 Documentation

Added comprehensive documentation in docs/query_operators.md including:

  • Complete feature overview
  • Usage examples and best practices
  • Comparison with Spring Data JPA
  • Edge case handling guidelines
  • Complete working examples

🔄 Backward Compatibility

  • ✅ All existing functionality remains unchanged
  • ✅ Existing method signatures continue to work
  • ✅ No breaking changes to public APIs
  • ✅ Default behavior (equality) preserved for methods without operation suffixes

🎯 Benefits

  1. Developer Experience: Intuitive method naming similar to Spring Data JPA
  2. Type Safety: Compile-time validation of operation parameters
  3. Performance: Efficient SQL generation with proper indexing support
  4. Flexibility: Support for complex query combinations
  5. Maintainability: Clean, readable code with minimal boilerplate
  6. API Quality: Intelligent parameter mapping supports plural forms for better API design
  7. Robustness: Handles edge cases like words ending with 's' and prevents mapping ambiguity

🚦 Migration Guide

No migration required! Existing code continues to work as-is. New field operations are opt-in through method naming conventions.

🔬 Technical Challenges & Solutions

Parameter Field Mapping Complexity

The Challenge: The original parameter-to-field mapping had a critical design flaw - it assumed parameter names and field names would be in the same order, leading to incorrect mappings and silent failures.

The Solution: Implemented a robust, order-independent mapping system with clear rules:

  1. Exact Match Priority: Parameters that exactly match field names are used directly
  2. Plural-to-Singular Mapping: Smart conversion for better API design
  3. Edge Case Handling: Special logic for words ending with 's' (statusesstatus)
  4. Ambiguity Prevention: Clear rules prevent mapping conflicts
  5. Quality Error Messages: Helpful feedback when mapping fails

Result: A system that's both powerful and predictable, supporting high-quality API design while maintaining simplicity.

📝 Checklist

  • Feature implementation complete
  • Comprehensive test coverage
  • Documentation updated
  • Backward compatibility verified
  • Code review completed
  • Performance impact assessed
  • Security considerations reviewed

Related Issues: Closes #[issue_number]

Breaking Changes: None

Dependencies: No new dependencies added

Performance Impact: Minimal - only affects new field operation methods


This PR significantly enhances PySpringModel's query capabilities, making it more powerful and developer-friendly while maintaining full backward compatibility.

- Updated `CrudRepositoryImplementationService` to support IN operations in query filtering, including validation for parameter types and handling of empty lists. - Modified `_Query` class to include `field_operations` for mapping field names to their respective operations. - Enhanced `_MetodQueryBuilder` to parse method names with IN operations and generate appropriate query structures. - Added comprehensive unit tests for IN operator functionality, including cases for single fields, multiple fields with AND/OR conditions, and error handling for invalid types and empty lists. - Updated existing tests to reflect changes in query structure and ensure correct SQL statement generation.
…eries - Added a new documentation file detailing supported field operations for dynamic query generation, including EQUALS, IN, GREATER_THAN, and others. - Enhanced `CrudRepositoryImplementationService` to handle various field operations, including validation and edge case management. - Updated `_Query` and `_MetodQueryBuilder` to incorporate field operation parsing and handling. - Implemented unit tests for field operations, ensuring correct functionality and validation for different query scenarios. - Improved method naming conventions and added examples for better clarity in usage.
@NFUChen NFUChen changed the title Feat/in operator Add Field Operations Support for Dynamic Query Generation Jul 18, 2025
- Refactored `_detect_field_operation` method in `_MetodQueryBuilder` to streamline the detection of field operations. - Ensured that the `_not_in` suffix is prioritized to prevent false positives when matching with `_in`. - Cleaned up unnecessary comments and improved code clarity for better maintainability.
- Added a new method `_create_parameter_field_mapping` to facilitate mapping between parameter names and field names, enhancing API readability. - Updated `create_implementation_wrapper` to utilize the new mapping method, ensuring correct handling of keyword arguments in queries. - Introduced comprehensive unit tests for the new mapping functionality, covering various scenarios including order independence, validation, and edge cases.
…on and support - Refined the `_create_parameter_field_mapping` method to support exact matching and plural-to-singular mapping, improving API design clarity. - Updated error handling to provide clearer messages for unmatched parameters and added rules to prevent ambiguity in parameter names. - Enhanced unit tests to cover various mapping scenarios, including order independence, validation, and edge cases, ensuring robust functionality.
…ethod - Moved the plural-to-singular conversion logic from `_create_parameter_field_mapping` to a new method `_cast_plural_to_singular`, improving code readability and maintainability. - This change enhances the clarity of the mapping process and prepares the code for potential future extensions.
- Introduced new field operations such as IN, GREATER_THAN, LESS_THAN, and LIKE to enhance dynamic query generation capabilities. - Updated the documentation to include detailed descriptions and examples of supported field operations. - Modified the `UserRepository` and `ProductRepository` classes to implement new methods for these operations, ensuring consistent usage across repositories. - Enhanced return types for query methods to use `Optional` for better handling of potential null results.
@NFUChen NFUChen merged commit 97d3119 into main Jul 18, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants