add global config support
This commit is contained in:
parent
cd1e1a42f3
commit
34d553a890
23 changed files with 1682 additions and 343 deletions
181
db/operation.go
181
db/operation.go
|
|
@ -1,13 +1,9 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// 用户校验操作
|
||||
|
|
@ -413,92 +409,119 @@ func (cdb *ConfigDB) RangeAllReandered() ([]RenderedConfigEntry, error) {
|
|||
return renderedConfigs, nil
|
||||
}
|
||||
|
||||
// --- GOB 编码/解码辅助函数 ---
|
||||
// --- 全局配置操作 (Global_Configs Table) ---
|
||||
/*
|
||||
_, err = tx.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS global_configs (
|
||||
filename TEXT PRIMARY KEY,
|
||||
params BLOB NOT NULL,
|
||||
tmpl_content BLOB NOT NULL,
|
||||
rendered_content BLOB NOT NULL,
|
||||
updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
|
||||
);`)
|
||||
*/
|
||||
|
||||
// gobEncode 将 Go 值编码为 GOB 格式的字节切片.
|
||||
// 'data' 必须是可被 GOB 编码的值; 例如基本类型, 切片, 映射, 结构体.
|
||||
func gobEncode(data interface{}) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
enc := gob.NewEncoder(&buf)
|
||||
if err := enc.Encode(data); err != nil {
|
||||
return nil, fmt.Errorf("db: failed to GOB encode data: %w", err)
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// gobDecode 将 GOB 格式的字节切片解码到 Go 值.
|
||||
// 'data' 是 GOB 编码的字节切片.
|
||||
// 'valuePtr' 必须是指向目标 Go 值的指针; 其类型必须与编码时的数据类型兼容.
|
||||
func gobDecode(data []byte, valuePtr interface{}) error {
|
||||
buf := bytes.NewBuffer(data)
|
||||
dec := gob.NewDecoder(buf)
|
||||
if err := dec.Decode(valuePtr); err != nil {
|
||||
return fmt.Errorf("db: failed to GOB decode data: %w", err)
|
||||
// SaveGlobalConfig 在 'global_configs' 表中保存或更新全局配置.
|
||||
func (cdb *ConfigDB) SaveGlobalConfig(entry GlobalConfig) error {
|
||||
insertSQL := `
|
||||
INSERT INTO global_configs (filename, params, tmpl_content, rendered_content)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(filename) DO UPDATE SET
|
||||
params = EXCLUDED.params,
|
||||
tmpl_content = EXCLUDED.tmpl_content,
|
||||
rendered_content = EXCLUDED.rendered_content,
|
||||
updated_at = strftime('%s', 'now');
|
||||
`
|
||||
_, err := cdb.DB.Exec(insertSQL, entry.Filename, entry.Params, entry.TmplContent, entry.RenderedContent)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db: failed to save global config for '%s': %w", entry.Filename, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// --- 业务逻辑: 渲染并保存 (由使用者调用) ---
|
||||
// RenderAndSaveConfig 从数据库获取模板和参数; 渲染后保存到 'rendered_configs' 表.
|
||||
// 这是一个组合操作; 通常由应用程序逻辑在需要时调用.
|
||||
// filename: 要渲染的配置文件的唯一标识.
|
||||
// templateParser: 一个实现了 TemplateParser 接口的模板解析器实例.
|
||||
// dynamicParams: 运行时动态提供的参数; 它们会覆盖存储在数据库中的同名参数.
|
||||
func (cdb *ConfigDB) RenderAndSaveConfig(filename string, dynamicParams map[string]interface{}) error {
|
||||
// 1. 获取模板内容.
|
||||
tmplEntry, err := cdb.GetTemplate(filename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db: failed to get template '%s' for rendering: %w", filename, err)
|
||||
}
|
||||
// GetGlobalConfig 从 'global_configs' 表中获取全局配置.
|
||||
func (cdb *ConfigDB) GetGlobalConfig(filename string) (*GlobalConfig, error) {
|
||||
querySQL := `SELECT filename, params, tmpl_content, rendered_content, updated_at FROM global_configs WHERE filename = ?;`
|
||||
row := cdb.DB.QueryRow(querySQL, filename)
|
||||
|
||||
// 2. 获取存储的参数.
|
||||
paramsEntry, err := cdb.GetParams(filename)
|
||||
var storedParams map[string]interface{}
|
||||
entry := &GlobalConfig{}
|
||||
err := row.Scan(&entry.Filename, &entry.Params, &entry.TmplContent, &entry.RenderedContent, &entry.UpdatedAt)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
storedParams = make(map[string]interface{}) // 参数不存在; 使用空 map.
|
||||
} else {
|
||||
return fmt.Errorf("db: failed to get parameters for '%s': %w", filename, err)
|
||||
}
|
||||
} else {
|
||||
// 解码 GOB 参数到 map.
|
||||
if err := gobDecode(paramsEntry.ParamsGOB, &storedParams); err != nil {
|
||||
return fmt.Errorf("db: failed to decode stored parameters for '%s': %w", filename, err)
|
||||
return nil, fmt.Errorf("db: global config '%s' not found: %w", filename, err)
|
||||
}
|
||||
return nil, fmt.Errorf("db: failed to get global config '%s': %w", filename, err)
|
||||
}
|
||||
return entry, nil
|
||||
}
|
||||
|
||||
// 合并参数: 动态传入的参数覆盖存储的参数.
|
||||
if dynamicParams != nil {
|
||||
for k, v := range dynamicParams {
|
||||
storedParams[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 渲染模板.
|
||||
var parsedTmpl *template.Template
|
||||
var parseErr error
|
||||
|
||||
// 使用传入的 templateParser 实例来解析模板内容.
|
||||
// 注意: templateParser.Parse 是在提供的实例上调用; 以解析特定内容.
|
||||
//parsedTmpl, parseErr = templateParser.Parse(string(tmplEntry.Content))
|
||||
parsedTmpl, parseErr = template.New(tmplEntry.Filename).Parse(string(tmplEntry.Content))
|
||||
|
||||
if parseErr != nil {
|
||||
return fmt.Errorf("db: failed to parse template content for '%s': %w", tmplEntry.Filename, parseErr)
|
||||
}
|
||||
|
||||
var renderedContentBuilder strings.Builder
|
||||
if err := parsedTmpl.Execute(&renderedContentBuilder, storedParams); err != nil {
|
||||
return fmt.Errorf("db: failed to render template '%s': %w", tmplEntry.Filename, err)
|
||||
}
|
||||
|
||||
// 4. 保存渲染结果.
|
||||
renderedEntry := RenderedConfigEntry{
|
||||
Filename: filename,
|
||||
RenderedContent: []byte(renderedContentBuilder.String()),
|
||||
}
|
||||
if err := cdb.SaveRenderedConfig(renderedEntry); err != nil {
|
||||
return fmt.Errorf("db: failed to save rendered config for '%s': %w", filename, err)
|
||||
// DeleteGlobalConfig 从 'global_configs' 表中删除全局配置.
|
||||
func (cdb *ConfigDB) DeleteGlobalConfig(filename string) error {
|
||||
_, err := cdb.DB.Exec(`DELETE FROM global_configs WHERE filename = ?;`, filename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db: failed to delete global config for '%s': %w", filename, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveGlobalParams
|
||||
func (cdb *ConfigDB) SaveGlobalParams(filename string, params []byte) error {
|
||||
insertSQL := `
|
||||
INSERT INTO global_configs (filename, params)
|
||||
VALUES (?, ?)
|
||||
ON CONFLICT(filename) DO UPDATE SET
|
||||
params = EXCLUDED.params,
|
||||
updated_at = strftime('%s', 'now');
|
||||
`
|
||||
_, err := cdb.DB.Exec(insertSQL, filename, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db: failed to save global params for '%s': %w", filename, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveGlobalRenderedContent
|
||||
func (cdb *ConfigDB) SaveGlobalRenderedContent(filename string, renderedContent []byte) error {
|
||||
insertSQL := `
|
||||
INSERT INTO global_configs (filename, rendered_content)
|
||||
VALUES (?, ?)
|
||||
ON CONFLICT(filename) DO UPDATE SET
|
||||
rendered_content = EXCLUDED.rendered_content,
|
||||
updated_at = strftime('%s', 'now');
|
||||
`
|
||||
_, err := cdb.DB.Exec(insertSQL, filename, renderedContent)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db: failed to save global rendered content for '%s': %w", filename, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveGlobalTemplate
|
||||
func (cdb *ConfigDB) SaveGlobalTemplate(filename string, tmplContent []byte) error {
|
||||
insertSQL := `
|
||||
INSERT INTO global_configs (filename, tmpl_content)
|
||||
VALUES (?, ?)
|
||||
ON CONFLICT(filename) DO UPDATE SET
|
||||
tmpl_content = EXCLUDED.tmpl_content,
|
||||
updated_at = strftime('%s', 'now');
|
||||
`
|
||||
_, err := cdb.DB.Exec(insertSQL, filename, tmplContent)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db: failed to save global template for '%s': %w", filename, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetGlobalTemplate
|
||||
func (cdb *ConfigDB) GetGlobalTemplate(filename string) ([]byte, error) {
|
||||
querySQL := `SELECT tmpl_content FROM global_configs WHERE filename = ?;`
|
||||
var tmplContent []byte
|
||||
err := cdb.DB.QueryRow(querySQL, filename).Scan(&tmplContent)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, fmt.Errorf("db: global template '%s' not found: %w", filename, err)
|
||||
}
|
||||
return nil, fmt.Errorf("db: failed to get global template '%s': %w", filename, err)
|
||||
}
|
||||
return tmplContent, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue