CQRS: Commands and Queries
Relevant source files
The following files were used as context for generating this wiki page:
The Command Query Responsibility Segregation (CQRS) implementation in FLEXT-Core provides a structured foundation for building clean architecture applications. It separates the domain's write operations (Commands) from its read operations (Queries) using strongly-typed models built on Pydantic v2. This separation allows for distinct data paths, optimized scaling, and enhanced validation within the dispatcher-driven application layer.
The CQRS module defines a common language through FlextMessage, which acts as a discriminated union of Commands, Queries, and Events. These messages are designed to be consumed by specialized handlers that enforce domain invariants and manage state transitions.
Sources: src/flext_core/models.py:12-25, src/flext_core/_models/_cqrs_parts/flextmodelscqrs_part_02.py:84-84
Core Message Types
FLEXT-Core categorizes CQRS interactions into three primary message types, each serving a specific role in the system lifecycle.
| Message Type | Description | Key Identifier |
|---|---|---|
| Command | Represents an intent to change system state. | command_id (prefixed cmd_) |
| Query | Represents a request for data without side effects. | query_id (prefixed query_) |
| Event | An immutable record of a state change that has occurred. | event_id (prefixed evt_) |
Sources: src/flext_core/_models/_cqrs_parts/flextmodelscqrs_part_01.py:61-90, src/flext_core/_models/_cqrs_parts/flextmodelscqrs_part_02.py:53-82
Messaging Hierarchy
The following diagram illustrates the relationship between the base CQRS models and their specialized implementations.
Command Implementation
Commands are used to encapsulate all information needed to perform an action. They include metadata for tracing and idempotency.
- Identity: Each command is assigned a unique
command_idgenerated via a prefixed ULID/UUID (e.g.,cmd_01HZX...) to facilitate tracking through the system. - Immutability: The
message_typeis frozen to ensure the command cannot be reclassified during its lifecycle. - Issuer Tracking: Commands can optionally include an
issuer_idto identify the principal (user or system) that initiated the request.
Sources: src/flext_core/_models/_cqrs_parts/flextmodelscqrs_part_01.py:65-82, tests/unit/_models/test_cqrs.py:27-44
Query and Pagination
Queries are designed for read-only operations and include built-in support for filtering and pagination.
Pagination Model
The Pagination model (exposed via FlextModels.Cqrs.Pagination) provides standardized controls for result sets.
| Field | Type | Default | Description |
|---|---|---|---|
page | PositiveInt | 1 | 1-based index for the current page. |
size | PositiveInt | 10 | Number of items per page (Max: 1000). |
limit | int | (Computed) | Alias for size. |
offset | int | (Computed) | Calculated as (page - 1) * size. |
Sources: src/flext_core/_models/_cqrs_parts/flextmodelscqrs_part_01.py:31-56, src/flext_core/_constants/cqrs.py:19-20
Query Structure
Queries contain a filters mapping and a pagination object. The framework includes a validate_pagination field validator that coerces raw dictionaries or None values into valid Pagination instances, falling back to defaults if input is invalid.
Handlers and Configuration
Handlers are the execution units for CQRS messages. The Handler model configures how the dispatcher routes and executes these messages.
Handler Constants
The HandlerType enum defines the supported operational categories:
COMMAND: Standard state-change operations.QUERY: Data retrieval operations.EVENT: Reactive logic triggered by domain events.OPERATIONandSAGA: Orchestration and long-running processes.
Sources: src/flext_core/_constants/cqrs.py:26-34
Handler Metadata
Handlers track timeout settings and retry logic through the following fields:
handler_idandhandler_name: Identification.command_timeout: Execution duration limit.max_command_retries: Permitted retry attempts (Default: 0, Max: 5).metadata: Optional Pydantic model for handler-specific extensions.
Sources: src/flext_core/_models/_cqrs_parts/flextmodelscqrs_part_02.py:24-51, src/flext_core/_constants/cqrs.py:16-18
Data Flow and Message Discrimination
The FlextMessage type union allows the dispatcher to handle various message types polymorphically while maintaining strict type safety using the message_type discriminator.
Summary
The CQRS implementation in flext-core provides a robust, Pydantic-backed infrastructure for separating message intent from execution. By standardizing Command, Query, and Event shapes, the framework ensures consistent tracing via generated IDs, reliable result sets via integrated Pagination, and clear routing through defined Handler configurations. This structure supports the project's goal of maintaining a "Clean Architecture" by enforcing clear boundaries between data input and domain processing.