This document outlines a comprehensive plan to improve Ommi's module structure, making it cleaner and reducing dependencies between modules. The refactoring will maintain backward compatibility while improving maintainability and code organization.
- Good separation between abstract driver interfaces (
ommi/drivers/) and concrete implementations (ommi/ext/drivers/) - Proper use of
TYPE_CHECKINGto avoid circular imports - Clean database result handling with separate modules for different result types
- Effective lazy loading in main
__init__.py
- Over-sized
models/models.py(894 lines) - Contains too many responsibilities - Models directory lacks clear organization - Query functionality, metadata, and core model logic are mixed
- Repeated patterns across drivers - Each driver reimplements similar patterns without shared base classes
- Potential for better abstraction - Missing interface layer for better decoupling
Current State: Single large file with multiple responsibilities Target State: Multiple focused modules
models/
├── __init__.py # Public API exports
├── core/
│ ├── __init__.py
│ ├── base.py # OmmiModel base class only
│ ├── decorators.py # @ommi_model decorator logic
│ ├── registry.py # Model registration and collection utilities
│ └── metadata.py # Model metadata management
├── fields/
│ ├── __init__.py
│ ├── metadata.py # Field metadata processing (from field_metadata.py)
│ ├── descriptors.py # Queryable descriptors (from queryable_descriptors.py)
│ ├── query_fields.py # Query field types (existing)
│ └── types.py # Field type definitions
├── queries/
│ ├── __init__.py
│ ├── references.py # Reference handling (existing)
│ └── builders.py # Query building utilities
└── collections.py # Collection management (existing)
Files to Create/Modify:
- Extract from
models/models.py:models/core/base.py-OmmiModelclass definitionmodels/core/decorators.py-ommi_modeldecorator and related logicmodels/core/registry.py- Model registration utilitiesmodels/core/metadata.py- Model metadata processing
- Rename
models/field_metadata.py→models/fields/metadata.py - Rename
models/queryable_descriptors.py→models/fields/descriptors.py - Update imports across the codebase
Current State: Each driver reimplements similar patterns Target State: Shared base classes and utilities
drivers/
├── __init__.py # Existing driver interfaces
├── base/
│ ├── __init__.py
│ ├── query_builders.py # Base query builder classes
│ ├── transactions.py # Base transaction classes
│ └── utils.py # Shared utilities across all drivers
└── sql/
├── __init__.py
├── base.py # SQL-specific base classes
└── utils.py # SQL-specific utilities
Benefits:
- Reduce code duplication across SQLite and PostgreSQL drivers
- Easier to add new SQL-based drivers
- Consistent behavior across similar database types
Current State: Query logic scattered across multiple modules Target State: Dedicated query subsystem
ommi/
├── query/
│ ├── __init__.py
│ ├── ast/
│ │ ├── __init__.py
│ │ ├── nodes.py # AST node definitions (from query_ast.py)
│ │ ├── builders.py # Query building logic (from query_ast.py)
│ │ └── operators.py # Operator definitions (from query_ast.py)
│ ├── fields/
│ │ ├── __init__.py
│ │ ├── descriptors.py # Moved from models/fields/
│ │ └── references.py # Moved from models/queries/
│ └── execution/
│ ├── __init__.py
│ └── context.py # Query execution context
Files to Modify:
- Split
query_ast.pyinto multiple focused modules - Move query-specific logic from models package
- Update imports throughout codebase
Current State: Protocols scattered across modules Target State: Centralized interface definitions
ommi/
├── interfaces/
│ ├── __init__.py
│ ├── model.py # Model protocol definitions
│ ├── queryable.py # Queryable protocol definitions
│ ├── driver.py # Driver protocol (moved from drivers/)
│ ├── result.py # Result protocol definitions
│ └── transaction.py # Transaction protocol definitions
Benefits:
- Clear contracts between modules
- Easier testing with mock implementations
- Better type checking and IDE support
- Reduced circular dependency risks
Current State: Good organization but could be enhanced Target State: More explicit operation categories
database/
├── __init__.py
├── ommi.py # Main database interface (existing)
├── transaction.py # Transaction management (existing)
├── results/
│ ├── __init__.py
│ ├── single.py # Single value results (from results.py)
│ ├── collections.py # Collection results (from query_results.py)
│ └── builders.py # Result builder utilities
└── operations/
├── __init__.py
├── crud.py # CRUD operation wrappers
└── schema.py # Schema management operations
Current State: Utilities scattered across modules Target State: Centralized utility functions
ommi/
├── utils/
│ ├── __init__.py
│ ├── imports.py # Import utilities and lazy loading
│ ├── annotations.py # Annotation processing utilities
│ ├── validation.py # Field validation utilities
│ └── collections.py # Collection manipulation utilities
- Maintain all existing public APIs during refactoring
- Use
__init__.pyfiles to re-export moved functionality - Add deprecation warnings for any changed import paths
- Provide migration guide for users importing internal modules
- Create new directory structures
- Set up
__init__.pyfiles with proper exports - Create base classes and interfaces
- Extract code to new locations
- Update internal imports
- Add compatibility imports in old locations
- Run full test suite after each major move
- Update API documentation
- Create migration guide
- Update examples in documentation
- Remove compatibility imports after deprecation period
- Remove empty modules
- Final documentation updates
- Run existing test suite after each phase
- Add integration tests for new module boundaries
- Test import paths for backward compatibility
- Performance testing to ensure no regressions
- Circular Import Risk: Use interfaces package and maintain
TYPE_CHECKINGpatterns - Performance Risk: Profile import times and lazy loading behavior
- API Breakage Risk: Comprehensive compatibility testing and gradual migration
- Smaller, more focused modules (target <300 lines per file)
- Clear separation of concerns
- Reduced cognitive load when reading code
- Easier unit testing of individual components
- Easier to locate relevant code
- Reduced risk of circular dependencies
- Clear module boundaries and responsibilities
- Better IDE support and navigation
- Easier to add new database drivers
- Clear extension points for new functionality
- Better plugin architecture potential
- Simplified contribution process for new developers
- Phase 1: 2-3 weeks (models restructuring and driver utilities)
- Phase 2: 1-2 weeks (query system extraction and interfaces)
- Phase 3: 1 week (advanced reorganization)
- Total: 4-6 weeks for complete implementation
- All existing tests pass
- No circular import warnings
- Improved code coverage due to better testability
- Documentation builds successfully
- Performance benchmarks show no regression
- Developer feedback on improved code navigation
This refactoring plan addresses the main structural issues in Ommi while maintaining stability and backward compatibility. The phased approach allows for incremental progress and validation at each step, minimizing risk while achieving significant improvements in code organization and maintainability.