Three-Layer Architecture Diagram
Architecture Layers
This library follows a three-layer architecture:Layer 1: StashClient (GraphQL Transport)
Located instash_graphql_client/client/, the client provides direct access to Stash’s GraphQL API through typed mixin methods.
Responsibilities:
- Execute GraphQL queries and mutations
- Handle HTTP/WebSocket transports
- Manage retries and connection pooling
- Deserialize responses to Pydantic models
Layer 2: Pydantic Types (Schema/ORM Layer)
Located instash_graphql_client/types/, all Stash entities are Pydantic v2 models with:
Features:
- UNSET Pattern - Three-state fields distinguish “set to value”, “set to null”, and “never touched”
- UUID4 Auto-generation - New objects get temporary IDs replaced with server IDs on save
- Bidirectional Relationships - Automatic sync between related entities
- Tracked Fields -
__tracked_fields__and__field_conversions__for change detection - Relationship Metadata -
__relationships__documents query strategies and inverse fields
Layer 3: StashEntityStore (Identity Map & Caching)
Located instash_graphql_client/store.py, provides SQLAlchemy/ActiveRecord-style data access with:
Features:
- Identity Map - Same entity ID → same object reference
- Read-Through Caching - Fetch from cache or query on miss
- TTL Support - Optional cache expiration
- Field-Aware Population - Load missing fields on demand
- Django-Style Filtering -
field__modifierkwargs - Lazy Iteration - Paginate large result sets efficiently
- Thread-Safe - Uses
RLockfor concurrent access
When to Use Each Layer
Use StashClient when:
- ✅ Making one-off queries
- ✅ Need direct control over GraphQL queries
- ✅ Working with entity types that don’t need caching
- ✅ Executing mutations that return complex results
Use Pydantic Types when:
- ✅ Creating new entities with validation
- ✅ Need ORM-like
.save()/.delete()methods - ✅ Working with entity relationships
- ✅ Need change tracking for partial updates
Use StashEntityStore when:
- ✅ Need object identity across queries
- ✅ Making repeated queries for same entities
- ✅ Using Django-style filtering
- ✅ Need field-aware population
- ✅ Processing large result sets with pagination
Related Documentation
- Identity Map Architecture - Deep dive on wrap validators and caching
- Library Comparisons - How this compares to alternatives
- Bidirectional Relationships - Relationship sync implementation
- Overview Guide - General overview and design philosophy