Query Handler
The QueryHandler interface in comby defines the structure for handling domain-specific queries. It ensures that each query handler is uniquely identifiable, supports specific queries, and provides the necessary logic for processing them.
In comby an QueryHandler
is defined as an interface
as follows:
type DomainQueryHandler struct {
DomainQryPath string // Technical path of the domain query
DomainQryName string // Name of the domain query
DomainQry DomainQry // Runtime instance of the domain query
DomainQueryHandlerFunc DomainQueryHandlerFunc // Function to handle the domain query
}
type QueryHandler interface {
// Identifier is used to uniquely identify the handler (method inherited from Identifier interface).
Identifier
// GetDomainQueryHandler returns a DomainQueryHandler for the specified DomainQry.
GetDomainQueryHandler(domainQry DomainQry) *DomainQueryHandler
// GetDomainQueries returns a slice of supported domain queries.
GetDomainQueries() []DomainQry
}
The QueryHandler
inherits from the Identifier
interface, which assigns a unique domain and name to each handler, ensuring clear identification within the system.
The GetDomainQueryHandler method allows the retrieval of a DomainQueryHandler
, which represents the logic for handling a specific DomainQry
. This enables the framework to dynamically invoke the appropriate query-processing logic based on the type of the domain query.
The GetDomainQueries method provides a list of all domain queries that the handler supports, offering a clear overview of its capabilities. This information is essential for routing queries to the appropriate handler and ensuring compatibility within the comby framework.
Base Query Handler
The BaseQueryHandler is a foundational implementation of the QueryHandler interface in comby, designed to manage domain queries and their associated handler functions. It provides a robust structure for handling queries within a domain, ensuring clear routing and processing of query logic. The structure of BaseQueryHandler
is defined as follows:
type BaseQueryHandler struct {
*BaseIdentifier // Embeds base identifier
domainQryMap map[string]*DomainQueryHandler // Registry of domain query handlers
}
At its core, the BaseQueryHandler
embeds the BaseIdentifier
, assigning a unique domain and name to each query handler instance for identification within the system. It maintains a registry, domainQryMap, which maps domain queries to their metadata and handling logic. Each entry in this registry is represented by the DomainQueryHandler
struct, which includes details such as the query's type path, name, runtime instance, and associated handler function.
The NewBaseQueryHandler function initializes a new BaseQueryHandler
instance, setting default values for its domain and generating a unique name. This ensures the handler is properly configured and ready for use.
The GetDomainQueryHandler method retrieves the handler function for a specific domain query by matching its type path. If no matching handler is found, the method returns nil. The GetDomainQueries method returns a list of all registered domain queries that the handler can process, providing an overview of its supported operations.
The addDomainQueryHandler method is used to register new query handlers. It ensures the provided DomainQry
and DomainQueryHandlerFunc
are valid and prevents duplicate handlers for the same query type. If successful, the new handler is added to the registry, making it available for query processing.
User-Defined Query Handlers
User-defined query handlers in comby are custom implementations of query processing logic tailored to a specific domain. These handlers extend the functionality of the BaseQueryHandler
by integrating domain-specific logic and registering domain query handlers for managing operations on readmodels. A user-defined query handler typically includes the following components:
type qryHandler struct {
*comby.BaseQueryHandler
Readmodel *readmodel.CustomOrderReadmodel
}
func NewCustomQueryHandler(
Readmodel *readmodel.CustomOrderReadmodel,
) *qryHandler {
qh := &qryHandler{}
qh.BaseQueryHandler = comby.NewBaseQueryHandler()
qh.Domain = "Order"
qh.Name = "CustomQueryHandler"
qh.Readmodel = Readmodel
// register custom domain query handlers
comby.AddDomainQueryHandler(qh, qh.GetList)
comby.AddDomainQueryHandler(qh, qh.GetModel)
return qh
}
The qryHandler struct represents a user-defined query handler for the "Order" domain in comby. It extends the functionality of the BaseQueryHandler by embedding it and providing custom logic for handling domain-specific queries related to orders. Additionally, it incorporates a reference to a CustomOrderReadmodel, which serves as the data source for executing queries.
The NewCustomQueryHandler function initializes an instance of qryHandler. During initialization, it configures the base query handler by setting the domain to "Order" and assigning a custom name (CustomQueryHandler). It also associates the CustomOrderReadmodel for accessing the underlying data required for query operations.
Custom domain query handlers are registered using the comby.AddDomainQueryHandler method. In this example, the following query handlers are registered:
- GetList: Handles queries that retrieve a list of orders.
- GetModel: Handles queries that retrieve a specific order model.
Add Domain Query Handler: GetModel
Any domain query handler must fullfill following signature:
type TypedDomainQueryHandlerFunc[T DomainQry, R QueryResponse] func(ctx context.Context, qry Query, domainQry T) (R, error)
The GetModel query handler is part of the custom query handler for the "Order" domain in comby. It processes queries to retrieve a specific order model, leveraging the associated CustomOrderReadmodel for data access and returning a structured response.
type CustomModelRequest struct {
OrderUuid string `json:"orderUuid"`
}
type CustomModelResponse struct {
Item *readmodel.CustomOrderModel `json:"order,omitempty"`
}
func (qh *qryHandler) GetModel(ctx context.Context, qry comby.Query, domainQry *CustomModelRequest) (*CustomModelResponse, error) {
var err error
// validate uuid
err = utils.ValidateUuid(domainQry.OrderUuid)
if err != nil {
return nil, fmt.Errorf("%s failed - orderUuid is invalid", utils.GetTypeName(domainQry))
}
// retrieve item read model
model, err := qh.Readmodel.GetModel(domainQry.OrderUuid)
if err != nil {
return nil, err
}
// generate response
response := &CustomModelResponse{}
response.Item = model
// return response
return response, nil
}
This handler is designed to handle queries encapsulated in the CustomModelRequest struct, which includes the OrderUuid to identify the specific order being queried. The response is returned as a CustomModelResponse, containing the retrieved order model.
The GetModel method begins by validating the OrderUuid provided in the query using utils.ValidateUuid. If the UUID is invalid, an error is returned, ensuring the integrity of the input data. Next, the method interacts with the Readmodel to fetch the order model corresponding to the validated OrderUuid. Any errors during this retrieval process are propagated back to the caller.
Upon successfully retrieving the model, the method constructs a CustomModelResponse object, embedding the retrieved data within the Item field. The response is then returned to the caller, completing the query execution.