diff --git a/Template-Rendering.-.md b/Template-Rendering.-.md new file mode 100644 index 0000000..b7ae158 --- /dev/null +++ b/Template-Rendering.-.md @@ -0,0 +1,122 @@ +# Template Rendering + +go-store includes a built-in template engine that renders Go `text/template` strings using key-value pairs from a group as template variables. + +## Render Method + +```go +func (s *Store) Render(tmplStr, group string) (string, error) +``` + +Loads all key-value pairs from the specified group, then executes the Go template string with those values as the data context. + +### Basic Usage + +```go +s, _ := store.New(":memory:") + +_ = s.Set("site", "name", "Core Platform") +_ = s.Set("site", "domain", "core.help") +_ = s.Set("site", "version", "2.1.0") + +output, err := s.Render("Welcome to {{.name}} ({{.domain}}) v{{.version}}", "site") +// output == "Welcome to Core Platform (core.help) v2.1.0" +``` + +### Template Syntax + +The template uses standard Go `text/template` syntax. The data context is a `map[string]string` where keys are the store keys and values are the store values. + +| Syntax | Description | +|--------|-------------| +| `{{.key}}` | Insert the value for `key` | +| `{{if .key}}...{{end}}` | Conditional block | +| `{{range $k, $v := .}}...{{end}}` | Iterate all key-value pairs | +| `{{.key \| printf "%q"}}` | Pipe through a function | + +### Configuration File Generation + +A common use case is generating configuration files from stored settings: + +```go +_ = s.Set("nginx", "server_name", "api.core.help") +_ = s.Set("nginx", "port", "8080") +_ = s.Set("nginx", "root", "/var/www/html") + +tmpl := `server { + listen {{.port}}; + server_name {{.server_name}}; + root {{.root}}; +}` + +output, err := s.Render(tmpl, "nginx") +``` + +### Environment File Generation + +```go +_ = s.Set("env", "APP_NAME", "Core") +_ = s.Set("env", "APP_DEBUG", "false") +_ = s.Set("env", "DB_HOST", "localhost") + +tmpl := `APP_NAME={{.APP_NAME}} +APP_DEBUG={{.APP_DEBUG}} +DB_HOST={{.DB_HOST}}` + +envFile, _ := s.Render(tmpl, "env") +_ = os.WriteFile(".env", []byte(envFile), 0644) +``` + +### Iterating All Values + +Use `range` to iterate over all stored key-value pairs: + +```go +tmpl := `{{range $k, $v := .}}{{$k}}={{$v}} +{{end}}` + +output, _ := s.Render(tmpl, "env") +``` + +Note: map iteration order in Go is not guaranteed, so the output order may vary. + +## How It Works + +Internally, `Render` performs three steps: + +1. **Query**: Fetches all rows from the `kv` table where `grp` matches the group +2. **Parse**: Parses the template string with `template.New("render").Parse(tmplStr)` +3. **Execute**: Executes the template with the `map[string]string` as the data context + +```go +// Equivalent manual implementation +vars, _ := s.GetAll("site") +tmpl, _ := template.New("t").Parse("Hello {{.name}}") +var buf strings.Builder +tmpl.Execute(&buf, vars) +result := buf.String() +``` + +The `Render` method combines these steps with proper error handling for each stage. + +## Error Handling + +`Render` returns errors from three potential failure points: + +| Error | Cause | +|-------|-------| +| `store.Render: query:` | Database query failed | +| `store.Render: scan:` | Row scanning failed | +| `store.Render: parse:` | Invalid Go template syntax | +| `store.Render: exec:` | Template execution failed (e.g. missing function) | + +```go +output, err := s.Render("{{.missing_func | nonexistent}}", "group") +if err != nil { + // err contains "store.Render: parse:" or "store.Render: exec:" +} +``` + +If the group has no keys, the template receives an empty map. Referencing `{{.key}}` for a missing key produces an empty string (Go template default behaviour). + +See also: [[Home]] | [[API-Reference]]