Centralize generated text template catalog
This commit is contained in:
155
internal/generatedtext/catalog.go
Normal file
155
internal/generatedtext/catalog.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package generatedtext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/briefing"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/facts"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/module"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/report"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/reporttemplate"
|
||||
)
|
||||
|
||||
const (
|
||||
schemaIDHourly = "hourly"
|
||||
schemaIDTomorrow = "tomorrow"
|
||||
|
||||
templateIDHourly = "hourly"
|
||||
templateIDTomorrow = "tomorrow"
|
||||
)
|
||||
|
||||
type validator func([]byte) (any, []byte, error)
|
||||
|
||||
type renderContextBuilder func(report.ID, string, briefing.Metadata, module.Snapshot, facts.CollectedFacts, facts.DerivedFacts, any) (any, error)
|
||||
|
||||
type catalogEntry struct {
|
||||
schemaID string
|
||||
templateID string
|
||||
validate validator
|
||||
buildRenderContext renderContextBuilder
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
reportID report.ID
|
||||
schemaID string
|
||||
templateID string
|
||||
validate validator
|
||||
buildRenderContext renderContextBuilder
|
||||
}
|
||||
|
||||
var catalog = []catalogEntry{
|
||||
{
|
||||
schemaID: schemaIDHourly,
|
||||
templateID: templateIDHourly,
|
||||
validate: validateHourly,
|
||||
buildRenderContext: buildHourlyContext,
|
||||
},
|
||||
{
|
||||
schemaID: schemaIDTomorrow,
|
||||
templateID: templateIDTomorrow,
|
||||
validate: validateTomorrow,
|
||||
buildRenderContext: buildTomorrowContext,
|
||||
},
|
||||
}
|
||||
|
||||
func LookupDefinition(definition report.Definition) (Handler, error) {
|
||||
if definition.GenerationMode != report.GenerationModeGeneratedTextTemplate {
|
||||
return Handler{}, fmt.Errorf("report %q uses generation mode %q, not %q", definition.ID, definition.GenerationMode, report.GenerationModeGeneratedTextTemplate)
|
||||
}
|
||||
|
||||
var schemaKnown, templateKnown bool
|
||||
for _, entry := range catalog {
|
||||
if entry.schemaID == definition.GeneratedTextSchemaID {
|
||||
schemaKnown = true
|
||||
}
|
||||
if entry.templateID == definition.TemplateID {
|
||||
templateKnown = true
|
||||
}
|
||||
if entry.schemaID == definition.GeneratedTextSchemaID && entry.templateID == definition.TemplateID {
|
||||
return Handler{
|
||||
reportID: definition.ID,
|
||||
schemaID: entry.schemaID,
|
||||
templateID: entry.templateID,
|
||||
validate: entry.validate,
|
||||
buildRenderContext: entry.buildRenderContext,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
if !schemaKnown {
|
||||
return Handler{}, fmt.Errorf("generated text schema %q is not supported for report %q", definition.GeneratedTextSchemaID, definition.ID)
|
||||
}
|
||||
if !templateKnown {
|
||||
return Handler{}, fmt.Errorf("report template %q is not supported for report %q", definition.TemplateID, definition.ID)
|
||||
}
|
||||
return Handler{}, fmt.Errorf("generated text schema %q and report template %q are not supported together for report %q", definition.GeneratedTextSchemaID, definition.TemplateID, definition.ID)
|
||||
}
|
||||
|
||||
func (h Handler) SchemaID() string {
|
||||
return h.schemaID
|
||||
}
|
||||
|
||||
func (h Handler) TemplateID() string {
|
||||
return h.templateID
|
||||
}
|
||||
|
||||
func (h Handler) Schema() ([]byte, error) {
|
||||
data, err := reporttemplate.Schema(h.schemaID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load generated text schema %q for report %q: %w", h.schemaID, h.reportID, err)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (h Handler) Template() (string, error) {
|
||||
source, err := reporttemplate.Template(h.templateID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("load report template %q for report %q: %w", h.templateID, h.reportID, err)
|
||||
}
|
||||
return source, nil
|
||||
}
|
||||
|
||||
func (h Handler) Validate(data []byte) (any, []byte, error) {
|
||||
if h.validate == nil {
|
||||
return nil, nil, fmt.Errorf("generated text validator is not registered for schema %q on report %q", h.schemaID, h.reportID)
|
||||
}
|
||||
return h.validate(data)
|
||||
}
|
||||
|
||||
func (h Handler) BuildRenderContext(metadata briefing.Metadata, snapshot module.Snapshot, collected facts.CollectedFacts, derived facts.DerivedFacts, generated any) (any, error) {
|
||||
if h.buildRenderContext == nil {
|
||||
return nil, fmt.Errorf("render-context builder is not registered for template %q on report %q", h.templateID, h.reportID)
|
||||
}
|
||||
return h.buildRenderContext(h.reportID, h.templateID, metadata, snapshot, collected, derived, generated)
|
||||
}
|
||||
|
||||
func (h Handler) Render(data any) ([]byte, error) {
|
||||
rendered, err := reporttemplate.Render(h.templateID, data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("render report template %q for report %q: %w", h.templateID, h.reportID, err)
|
||||
}
|
||||
return rendered, nil
|
||||
}
|
||||
|
||||
func validateHourly(data []byte) (any, []byte, error) {
|
||||
return ValidateHourly(data)
|
||||
}
|
||||
|
||||
func validateTomorrow(data []byte) (any, []byte, error) {
|
||||
return ValidateTomorrow(data)
|
||||
}
|
||||
|
||||
func buildHourlyContext(reportID report.ID, templateID string, metadata briefing.Metadata, snapshot module.Snapshot, collected facts.CollectedFacts, derived facts.DerivedFacts, generated any) (any, error) {
|
||||
hourly, ok := generated.(Hourly)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("report template %q requires hourly generated text for report %q", templateID, reportID)
|
||||
}
|
||||
return BuildHourlyRenderContext(metadata, snapshot, hourly, collected, derived)
|
||||
}
|
||||
|
||||
func buildTomorrowContext(reportID report.ID, templateID string, metadata briefing.Metadata, snapshot module.Snapshot, collected facts.CollectedFacts, derived facts.DerivedFacts, generated any) (any, error) {
|
||||
tomorrow, ok := generated.(Tomorrow)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("report template %q requires tomorrow generated text for report %q", templateID, reportID)
|
||||
}
|
||||
return BuildTomorrowRenderContext(metadata, snapshot, tomorrow, collected, derived)
|
||||
}
|
||||
Reference in New Issue
Block a user