2.9 KiB
2.9 KiB
Query Handler Scaffold Template
Generate a query handler file with a read model interface.
Placeholders
{{Name}}— PascalCase query name (e.g.,AvailableHours){{name}}— camelCase (e.g.,availableHours){{name_snake}}— snake_case (e.g.,available_hours){{module}}— Go module path from go.mod{{Result}}— Result type (e.g.,[]Date,*HourDetails)
File: app/query/{{name_snake}}.go
package query
import (
"context"
"github.com/sirupsen/logrus"
"{{module_common}}/decorator"
)
// Read model — defines what data the query needs
// Implemented by adapters (repository or dedicated read store)
type {{Name}}ReadModel interface {
{{Name}}(ctx context.Context /* TODO: add query params */) ({{Result}}, error)
}
// 1. Query struct — noun phrase, plain data
type {{Name}} struct {
// TODO: Add query parameters
// Example:
// From time.Time
// To time.Time
}
// Result types — optimized for reading, may differ from domain entities
// type Date struct {
// Date time.Time
// Hours []Hour
// }
// 2. Exported handler type alias
type {{Name}}Handler decorator.QueryHandler[{{Name}}, {{Result}}]
// 3. Unexported concrete handler struct
type {{name}}Handler struct {
readModel {{Name}}ReadModel
}
// 4. Constructor with nil-checks + decorator wrapping
func New{{Name}}Handler(
readModel {{Name}}ReadModel,
logger *logrus.Entry,
metricsClient decorator.MetricsClient,
) {{Name}}Handler {
if readModel == nil {
panic("nil readModel")
}
if logger == nil {
panic("nil logger")
}
if metricsClient == nil {
panic("nil metricsClient")
}
return decorator.ApplyQueryDecorators[{{Name}}, {{Result}}](
{{name}}Handler{readModel: readModel},
logger,
metricsClient,
)
}
// Handle — delegates to read model, may add input validation
func (h {{name}}Handler) Handle(ctx context.Context, q {{Name}}) ({{Result}}, error) {
// TODO: Add input validation if needed
// Example:
// if q.From.After(q.To) {
// return nil, errors.NewIncorrectInputError("date-from-after-date-to", "date from is after date to")
// }
return h.readModel.{{Name}}(ctx /* TODO: pass query params */)
}
Update app/app.go
Add to the Queries struct:
type Queries struct {
// ... existing handlers ...
{{Name}} query.{{Name}}Handler
}
Update service/application.go
Wire the handler. The read model is typically implemented by the same repository adapter or a dedicated read adapter:
Queries: app.Queries{
// ... existing handlers ...
{{Name}}: query.New{{Name}}Handler(
{{entity}}Repository, // implements {{Name}}ReadModel
logger,
metricsClient,
),
},
Implement ReadModel on Adapter
Add the read model method to your repository adapter:
// In adapters/
func (r *Memory{{Entity}}Repository) {{Name}}(ctx context.Context /* params */) ({{Result}}, error) {
// TODO: Implement query against storage
}