优化代码,添加getoption函数,添加db查询函数,可返回map[string]any,添加getthememods函数返回不太通用的值

This commit is contained in:
xing 2023-02-21 01:07:32 +08:00
parent cb3d043c90
commit a319e7595f
23 changed files with 417 additions and 138 deletions

View File

@ -2,14 +2,14 @@ package maps
import "strings" import "strings"
func GetStrMapAnyVal[T any](m map[string]any, key string) (r T, o bool) { func GetStrAnyVal[T any](m map[string]any, key string) (r T, o bool) {
k := strings.Split(key, ".") k := strings.Split(key, ".")
if len(k) > 1 { if len(k) > 1 {
val, ok := m[k[0]] val, ok := m[k[0]]
if ok { if ok {
vx, ok := val.(map[string]any) vx, ok := val.(map[string]any)
if ok { if ok {
r, o = GetStrMapAnyVal[T](vx, strings.Join(k[1:], ".")) r, o = GetStrAnyVal[T](vx, strings.Join(k[1:], "."))
} }
} }
} else { } else {
@ -25,6 +25,17 @@ func GetStrMapAnyVal[T any](m map[string]any, key string) (r T, o bool) {
return return
} }
func GetStrAnyValWithDefaults[T any](m map[string]any, key string, defaults T) (r T) {
r = defaults
v, ok := GetStrAnyVal[T](m, key)
if !ok {
return
}
r = v
return
}
// GetStrMapAnyValWithAny 使用"." 分隔层级
func GetStrMapAnyValWithAny(key string, v map[string]any) (r any, o bool) { func GetStrMapAnyValWithAny(key string, v map[string]any) (r any, o bool) {
k := strings.Split(key, ".") k := strings.Split(key, ".")
if len(k) > 1 { if len(k) > 1 {

View File

@ -54,12 +54,12 @@ func TestGetStrMapAnyVal(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
gotR, gotO := GetStrMapAnyVal[int](tt.args.v, tt.args.key) gotR, gotO := GetStrAnyVal[int](tt.args.v, tt.args.key)
if !reflect.DeepEqual(gotR, tt.wantR) { if !reflect.DeepEqual(gotR, tt.wantR) {
t.Errorf("GetStrMapAnyVal() gotR = %v, want %v", gotR, tt.wantR) t.Errorf("GetStrAnyVal() gotR = %v, want %v", gotR, tt.wantR)
} }
if gotO != tt.wantO { if gotO != tt.wantO {
t.Errorf("GetStrMapAnyVal() gotO = %v, want %v", gotO, tt.wantO) t.Errorf("GetStrAnyVal() gotO = %v, want %v", gotO, tt.wantO)
} }
}) })
} }

View File

@ -50,7 +50,7 @@ func PostComment(c *gin.Context) {
} }
defer req.Body.Close() defer req.Body.Close()
req.Header = c.Request.Header.Clone() req.Header = c.Request.Header.Clone()
home, err := url.Parse(wpconfig.Options.Value("siteurl")) home, err := url.Parse(wpconfig.GetOption("siteurl"))
if err != nil { if err != nil {
return return
} }
@ -102,7 +102,7 @@ func PostComment(c *gin.Context) {
logs.ErrPrintln(err, "获取文档", id) logs.ErrPrintln(err, "获取文档", id)
return return
} }
su := fmt.Sprintf("%s: %s[%s]发表了评论对文档[%v]的评论", wpconfig.Options.Value("siteurl"), author, m, post.PostTitle) su := fmt.Sprintf("%s: %s[%s]发表了评论对文档[%v]的评论", wpconfig.GetOption("siteurl"), author, m, post.PostTitle)
err = mail.SendMail([]string{conf.Mail.User}, su, comment) err = mail.SendMail([]string{conf.Mail.User}, su, comment)
logs.ErrPrintln(err, "发送邮件", conf.Mail.User, su, comment) logs.ErrPrintln(err, "发送邮件", conf.Mail.User, su, comment)
}() }()

View File

@ -33,7 +33,7 @@ func Login(c *gin.Context) {
c.Error(err) c.Error(err)
return return
} }
cohash := fmt.Sprintf("wp-postpass_%s", str.Md5(wpconfig.Options.Value("siteurl"))) cohash := fmt.Sprintf("wp-postpass_%s", str.Md5(wpconfig.GetOption("siteurl")))
c.SetCookie(cohash, pass, 24*3600, "/", "", false, false) c.SetCookie(cohash, pass, 24*3600, "/", "", false, false)
c.Redirect(http.StatusFound, ref) c.Redirect(http.StatusFound, ref)

View File

@ -45,7 +45,7 @@ func RecoverAndSendMail(w io.Writer) func(ctx *gin.Context) {
er := mail.SendMail( er := mail.SendMail(
[]string{config.GetConfig().Mail.User}, []string{config.GetConfig().Mail.User},
fmt.Sprintf("%s%s %s 发生错误", fmt.Sprintf(wpconfig.Options.Value("siteurl")), c.FullPath(), time.Now().Format(time.RFC1123Z)), content) fmt.Sprintf("%s%s %s 发生错误", fmt.Sprintf(wpconfig.GetOption("siteurl")), c.FullPath(), time.Now().Format(time.RFC1123Z)), content)
if er != nil { if er != nil {
logs.ErrPrintln(er, "recover send mail fail", fmt.Sprintf("%v", err)) logs.ErrPrintln(er, "recover send mail fail", fmt.Sprintf("%v", err))

View File

@ -5,7 +5,8 @@ import (
"github.com/fthvgb1/wp-go/helper/maps" "github.com/fthvgb1/wp-go/helper/maps"
) )
func UnPHPSerialize[T any](s string) (r T, err error) { // UnPHPSerializeToStruct 使用 json tag
func UnPHPSerializeToStruct[T any](s string) (r T, err error) {
var rr map[any]any var rr map[any]any
err = phpserialize.Unmarshal([]byte(s), &rr) err = phpserialize.Unmarshal([]byte(s), &rr)
if err == nil { if err == nil {
@ -14,3 +15,15 @@ func UnPHPSerialize[T any](s string) (r T, err error) {
} }
return return
} }
func UnPHPSerializeToAnyMap(s string) (map[string]any, error) {
m := map[string]any{}
var r map[any]any
err := phpserialize.Unmarshal([]byte(s), &r)
if err != nil {
return nil, err
}
m = maps.AnyAnyToStrAny(r)
return m, err
}

View File

@ -21,14 +21,14 @@ var templateRss rss2.Rss2
func InitFeed() { func InitFeed() {
templateRss = rss2.Rss2{ templateRss = rss2.Rss2{
Title: wpconfig.Options.Value("blogname"), Title: wpconfig.GetOption("blogname"),
AtomLink: fmt.Sprintf("%s/feed", wpconfig.Options.Value("home")), AtomLink: fmt.Sprintf("%s/feed", wpconfig.GetOption("home")),
Link: wpconfig.Options.Value("siteurl"), Link: wpconfig.GetOption("siteurl"),
Description: wpconfig.Options.Value("blogdescription"), Description: wpconfig.GetOption("blogdescription"),
Language: wpconfig.GetLang(), Language: wpconfig.GetLang(),
UpdatePeriod: "hourly", UpdatePeriod: "hourly",
UpdateFrequency: 1, UpdateFrequency: 1,
Generator: wpconfig.Options.Value("home"), Generator: wpconfig.GetOption("home"),
} }
} }
@ -54,7 +54,7 @@ func feed(arg ...any) (xml []string, err error) {
if err != nil { if err != nil {
return return
} }
site := wpconfig.Options.Value("siteurl") site := wpconfig.GetOption("siteurl")
rs := templateRss rs := templateRss
rs.LastBuildDate = time.Now().Format(timeFormat) rs.LastBuildDate = time.Now().Format(timeFormat)
rs.Items = slice.Map(posts, func(t models.Posts) rss2.Item { rs.Items = slice.Map(posts, func(t models.Posts) rss2.Item {
@ -109,7 +109,7 @@ func postFeed(arg ...any) (x string, err error) {
return return
} }
rs := templateRss rs := templateRss
site := wpconfig.Options.Value("siteurl") site := wpconfig.GetOption("siteurl")
rs.Title = fmt.Sprintf("《%s》的评论", post.PostTitle) rs.Title = fmt.Sprintf("《%s》的评论", post.PostTitle)
rs.AtomLink = fmt.Sprintf("%s/p/%d/feed", site, post.Id) rs.AtomLink = fmt.Sprintf("%s/p/%d/feed", site, post.Id)
@ -153,9 +153,9 @@ func commentsFeed(args ...any) (r []string, err error) {
c := args[0].(*gin.Context) c := args[0].(*gin.Context)
commens := RecentComments(c, 10) commens := RecentComments(c, 10)
rs := templateRss rs := templateRss
rs.Title = fmt.Sprintf("\"%s\"的评论", wpconfig.Options.Value("blogname")) rs.Title = fmt.Sprintf("\"%s\"的评论", wpconfig.GetOption("blogname"))
rs.LastBuildDate = time.Now().Format(timeFormat) rs.LastBuildDate = time.Now().Format(timeFormat)
site := wpconfig.Options.Value("siteurl") site := wpconfig.GetOption("siteurl")
rs.AtomLink = fmt.Sprintf("%s/comments/feed", site) rs.AtomLink = fmt.Sprintf("%s/comments/feed", site)
com, err := GetCommentByIds(c, slice.Map(commens, func(t models.Comments) uint64 { com, err := GetCommentByIds(c, slice.Map(commens, func(t models.Comments) uint64 {
return t.CommentId return t.CommentId

View File

@ -20,40 +20,10 @@ func getHeaderImages(a ...any) (r []models.PostThumbnail, err error) {
ctx := a[0].(context.Context) ctx := a[0].(context.Context)
theme := a[1].(string) theme := a[1].(string)
meta, err := wpconfig.GetThemeMods(theme) meta, err := wpconfig.GetThemeMods(theme)
if err == nil && meta.HeaderImage != "" { if err != nil || meta.HeaderImage == "" {
if "random-uploaded-image" == meta.HeaderImage { return
headers, er := model.Finds[models.Posts](ctx, model.Conditions( }
model.Where(model.SqlBuilder{ if "random-uploaded-image" != meta.HeaderImage {
{"post_type", "attachment"},
{"post_status", "inherit"},
{"meta_value", theme},
{"meta_key", "_wp_attachment_is_custom_header"},
}),
model.Fields("a.ID"),
model.Group("a.ID"),
model.Join(model.SqlBuilder{
{" a", "left join", "wp_postmeta b", "a.ID=b.post_id"},
}),
))
if er != nil {
err = er
return
}
if len(headers) > 0 {
posts, er := GetPostsByIds(ctx, slice.Map(headers, func(t models.Posts) uint64 {
return t.Id
}))
if er != nil {
err = er
return
}
r = slice.Map(posts, func(m models.Posts) models.PostThumbnail {
return thumb(m, theme)
})
}
return
}
m, er := GetPostById(ctx, uint64(meta.HeaderImagData.AttachmentId)) m, er := GetPostById(ctx, uint64(meta.HeaderImagData.AttachmentId))
if er != nil { if er != nil {
err = er err = er
@ -61,8 +31,41 @@ func getHeaderImages(a ...any) (r []models.PostThumbnail, err error) {
} }
m.Thumbnail = thumb(m, theme) m.Thumbnail = thumb(m, theme)
r = []models.PostThumbnail{m.Thumbnail} r = []models.PostThumbnail{m.Thumbnail}
return
}
headers, er := model.Finds[models.Posts](ctx, model.Conditions(
model.Where(model.SqlBuilder{
{"post_type", "attachment"},
{"post_status", "inherit"},
{"meta_value", theme},
{"meta_key", "_wp_attachment_is_custom_header"},
}),
model.Fields("a.ID"),
model.Group("a.ID"),
model.Join(model.SqlBuilder{
{" a", "left join", "wp_postmeta b", "a.ID=b.post_id"},
}),
))
if er != nil {
err = er
return
}
if len(headers) > 0 {
posts, er := GetPostsByIds(ctx, slice.Map(headers, func(t models.Posts) uint64 {
return t.Id
}))
if er != nil {
err = er
return
}
r = slice.Map(posts, func(m models.Posts) models.PostThumbnail {
return thumb(m, theme)
})
} }
return return
} }
func thumb(m models.Posts, theme string) models.PostThumbnail { func thumb(m models.Posts, theme string) models.PostThumbnail {

View File

@ -28,7 +28,7 @@ func GetPostMetaByPostIds(args ...any) (r map[uint64]map[string]any, err error)
} }
r[postmeta.PostId][postmeta.MetaKey] = postmeta.MetaValue r[postmeta.PostId][postmeta.MetaKey] = postmeta.MetaValue
if postmeta.MetaKey == "_wp_attachment_metadata" { if postmeta.MetaKey == "_wp_attachment_metadata" {
metadata, err := phphelper.UnPHPSerialize[models.WpAttachmentMetadata](postmeta.MetaValue) metadata, err := phphelper.UnPHPSerializeToStruct[models.WpAttachmentMetadata](postmeta.MetaValue)
if err != nil { if err != nil {
logs.ErrPrintln(err, "解析postmeta失败", postmeta.MetaId, postmeta.MetaValue) logs.ErrPrintln(err, "解析postmeta失败", postmeta.MetaId, postmeta.MetaValue)
continue continue

View File

@ -34,22 +34,22 @@ func InitDb() (*sqlx.DB, error) {
return db, err return db, err
} }
func QueryDb(db *sqlx.DB) model.UniversalDb { func QueryDb(db *sqlx.DB) *model.SqlxQuery {
query := model.NewUniversalDb( query := model.NewSqlxQuery(db, model.NewUniversalDb(
nil,
func(ctx context.Context, a any, s string, args ...any) error { nil))
if config.GetConfig().ShowQuerySql {
go log.Println(model.FormatSql(s, args...))
}
return db.Select(a, s, args...)
},
func(ctx context.Context, a any, s string, args ...any) error {
if config.GetConfig().ShowQuerySql {
go log.Println(model.FormatSql(s, args...))
}
return db.Get(a, s, args...)
})
model.SetSelect(query, func(ctx context.Context, a any, s string, args ...any) error {
if config.GetConfig().ShowQuerySql {
go log.Println(model.FormatSql(s, args...))
}
return query.Selects(ctx, a, s, args...)
})
model.SetGet(query, func(ctx context.Context, a any, s string, args ...any) error {
if config.GetConfig().ShowQuerySql {
go log.Println(model.FormatSql(s, args...))
}
return query.Gets(ctx, a, s, args...)
})
return query return query
} }

View File

@ -25,7 +25,7 @@ func Gravatar(email string, isTls bool) (u string) {
q := url.Values{} q := url.Values{}
q.Add("s", "112") q.Add("s", "112")
q.Add("d", "mm") q.Add("d", "mm")
q.Add("r", strings.ToLower(wpconfig.Options.Value("avatar_rating"))) q.Add("r", strings.ToLower(wpconfig.GetOption("avatar_rating")))
u = fmt.Sprintf("%s?%s", u, q.Encode()) u = fmt.Sprintf("%s?%s", u, q.Encode())
return return
} }

View File

@ -11,7 +11,7 @@ import (
func (h *Handle) CalCustomLogo() (r string) { func (h *Handle) CalCustomLogo() (r string) {
id := uint64(h.ThemeMods.CustomLogo) id := uint64(h.ThemeMods.CustomLogo)
if id < 1 { if id < 1 {
id = str.ToInteger[uint64](wpconfig.Options.Value("site_logo"), 0) id = str.ToInteger[uint64](wpconfig.GetOption("site_logo"), 0)
if id < 1 { if id < 1 {
return return
} }
@ -22,7 +22,7 @@ func (h *Handle) CalCustomLogo() (r string) {
} }
siz := "full" siz := "full"
meta, _ := cache.GetPostMetaByPostId(h.C, id) meta, _ := cache.GetPostMetaByPostId(h.C, id)
alt := maps.WithDefaultVal(meta, "_wp_attachment_image_alt", any(wpconfig.Options.Value("blogname"))) alt := maps.WithDefaultVal(meta, "_wp_attachment_image_alt", any(wpconfig.GetOption("blogname")))
desc := alt.(string) desc := alt.(string)
imgx := map[string]string{ imgx := map[string]string{
"class": "custom-logo", "class": "custom-logo",

View File

@ -24,7 +24,7 @@ func NewDetailHandle(handle *Handle) *DetailHandle {
} }
func (d *DetailHandle) BuildDetailData() (err error) { func (d *DetailHandle) BuildDetailData() (err error) {
d.GinH["title"] = wpconfig.Options.Value("blogname") d.GinH["title"] = wpconfig.GetOption("blogname")
err = d.CheckAndGetPost() err = d.CheckAndGetPost()
if err != nil { if err != nil {
return return
@ -51,7 +51,7 @@ func (d *DetailHandle) CheckAndGetPost() (err error) {
d.GinH["post"] = post d.GinH["post"] = post
d.Post = post d.Post = post
d.GinH["user"] = cache.GetUserById(d.C, post.PostAuthor) d.GinH["user"] = cache.GetUserById(d.C, post.PostAuthor)
d.GinH["title"] = fmt.Sprintf("%s-%s", post.PostTitle, wpconfig.Options.Value("blogname")) d.GinH["title"] = fmt.Sprintf("%s-%s", post.PostTitle, wpconfig.GetOption("blogname"))
return return
} }
@ -80,7 +80,7 @@ func (d *DetailHandle) RenderComment() {
} }
d.GinH["showComment"] = ableComment d.GinH["showComment"] = ableComment
if len(d.Comments) > 0 && ableComment { if len(d.Comments) > 0 && ableComment {
dep := str.ToInteger(wpconfig.Options.Value("thread_comments_depth"), 5) dep := str.ToInteger(wpconfig.GetOption("thread_comments_depth"), 5)
d.GinH["comments"] = plugins.FormatComments(d.C, d.CommentRender, d.Comments, dep) d.GinH["comments"] = plugins.FormatComments(d.C, d.CommentRender, d.Comments, dep)
} }
} }

View File

@ -89,15 +89,15 @@ func (i *IndexParams) getSearchKey() string {
} }
func NewIndexParams(ctx *gin.Context) *IndexParams { func NewIndexParams(ctx *gin.Context) *IndexParams {
blogName := wpconfig.Options.Value("blogname") blogName := wpconfig.GetOption("blogname")
size := str.ToInteger(wpconfig.Options.Value("posts_per_page"), 10) size := str.ToInteger(wpconfig.GetOption("posts_per_page"), 10)
i := &IndexParams{ i := &IndexParams{
Ctx: ctx, Ctx: ctx,
Page: 1, Page: 1,
PageSize: size, PageSize: size,
PaginationStep: number.Max(1, config.GetConfig().PaginationStep), PaginationStep: number.Max(1, config.GetConfig().PaginationStep),
TitleL: blogName, TitleL: blogName,
TitleR: wpconfig.Options.Value("blogdescription"), TitleR: wpconfig.GetOption("blogdescription"),
Where: model.SqlBuilder{ Where: model.SqlBuilder{
{"post_type", "in", ""}, {"post_type", "in", ""},
{"post_status", "in", ""}, {"post_status", "in", ""},
@ -106,7 +106,7 @@ func NewIndexParams(ctx *gin.Context) *IndexParams {
Join: model.SqlBuilder{}, Join: model.SqlBuilder{},
PostType: []any{"post"}, PostType: []any{"post"},
PostStatus: []any{"publish"}, PostStatus: []any{"publish"},
BlogName: wpconfig.Options.Value("blogname"), BlogName: wpconfig.GetOption("blogname"),
} }
i.ParseSearch = i.parseSearch i.ParseSearch = i.parseSearch
i.ParseArchive = i.parseArchive i.ParseArchive = i.parseArchive

View File

@ -12,7 +12,7 @@ import (
var sizes = []string{"site_icon-270", "site_icon-32", "site_icon-192", "site_icon-180"} var sizes = []string{"site_icon-270", "site_icon-32", "site_icon-192", "site_icon-180"}
func (h *Handle) CalSiteIcon() (r string) { func (h *Handle) CalSiteIcon() (r string) {
id := str.ToInteger[uint64](wpconfig.Options.Value("site_icon"), 0) id := str.ToInteger[uint64](wpconfig.GetOption("site_icon"), 0)
if id < 1 { if id < 1 {
return return
} }

View File

@ -14,7 +14,7 @@ var comFn = template.FuncMap{
return t.Format("2006年 01月 02日") return t.Format("2006年 01月 02日")
}, },
"getOption": func(k string) string { "getOption": func(k string) string {
return wpconfig.Options.Value(k) return wpconfig.GetOption(k)
}, },
"getLang": wpconfig.GetLang, "getLang": wpconfig.GetLang,
} }

View File

@ -16,7 +16,7 @@ func InitTheme() {
func GetTemplateName() string { func GetTemplateName() string {
tmlp := config.GetConfig().Theme tmlp := config.GetConfig().Theme
if tmlp == "" { if tmlp == "" {
tmlp = wpconfig.Options.Value("template") tmlp = wpconfig.GetOption("template")
} }
if !IsTemplateDirExists(tmlp) { if !IsTemplateDirExists(tmlp) {
tmlp = "twentyfifteen" tmlp = "twentyfifteen"

View File

@ -8,10 +8,15 @@ import (
"strings" "strings"
) )
var Options safety.Map[string, string] var options safety.Map[string, string]
var ctx context.Context
func InitOptions() error { func InitOptions() error {
ctx := context.Background() options.Flush()
if ctx == nil {
ctx = context.Background()
}
ops, err := model.SimpleFind[models.Options](ctx, model.SqlBuilder{{"autoload", "yes"}}, "option_name, option_value") ops, err := model.SimpleFind[models.Options](ctx, model.SqlBuilder{{"autoload", "yes"}}, "option_name, option_value")
if err != nil { if err != nil {
return err return err
@ -22,14 +27,27 @@ func InitOptions() error {
return err return err
} }
} }
for _, options := range ops { for _, option := range ops {
Options.Store(options.OptionName, options.OptionValue) options.Store(option.OptionName, option.OptionValue)
} }
return nil return nil
} }
func GetOption(k string) string {
v, ok := options.Load(k)
if ok {
return v
}
vv, err := model.GetField[models.Options, string](ctx, "option_value", model.Conditions(model.Where(model.SqlBuilder{{"option_name", k}})))
options.Store(k, vv)
if err != nil {
return ""
}
return vv
}
func GetLang() string { func GetLang() string {
s, ok := Options.Load("WPLANG") s, ok := options.Load("WPLANG")
if !ok { if !ok {
s = "zh-CN" s = "zh-CN"
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/fthvgb1/wp-go/helper/maps" "github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/internal/cmd/reload" "github.com/fthvgb1/wp-go/internal/cmd/reload"
"github.com/fthvgb1/wp-go/internal/phphelper" "github.com/fthvgb1/wp-go/internal/phphelper"
"github.com/fthvgb1/wp-go/internal/pkg/logs"
"github.com/fthvgb1/wp-go/internal/pkg/models" "github.com/fthvgb1/wp-go/internal/pkg/models"
"github.com/fthvgb1/wp-go/safety" "github.com/fthvgb1/wp-go/safety"
"path/filepath" "path/filepath"
@ -19,6 +20,7 @@ func SetTemplateFs(fs embed.FS) {
templateFs = fs templateFs = fs
} }
// ThemeMods 只有部分公共的参数,其它的参数调用 GetThemeModsVal 函数获取
type ThemeMods struct { type ThemeMods struct {
CustomCssPostId int `json:"custom_css_post_id,omitempty"` CustomCssPostId int `json:"custom_css_post_id,omitempty"`
NavMenuLocations map[string]int `json:"nav_menu_locations,omitempty"` NavMenuLocations map[string]int `json:"nav_menu_locations,omitempty"`
@ -36,6 +38,8 @@ type ThemeMods struct {
SidebarTextcolor string `json:"sidebar_textcolor,omitempty"` SidebarTextcolor string `json:"sidebar_textcolor,omitempty"`
HeaderBackgroundColor string `json:"header_background_color,omitempty"` HeaderBackgroundColor string `json:"header_background_color,omitempty"`
HeaderTextcolor string `json:"header_textcolor,omitempty"` HeaderTextcolor string `json:"header_textcolor,omitempty"`
HeaderVideo int `json:"header_video,omitempty"`
ExternalHeaderVideo string `json:"external_header_video,omitempty"`
HeaderImagData ImageData `json:"header_image_data,omitempty"` HeaderImagData ImageData `json:"header_image_data,omitempty"`
SidebarsWidgets Sidebars `json:"sidebars_widgets,omitempty"` SidebarsWidgets Sidebars `json:"sidebars_widgets,omitempty"`
ThemeSupport ThemeSupport ThemeSupport ThemeSupport
@ -106,23 +110,47 @@ func Thumbnail(metadata models.WpAttachmentMetadata, Type, host string, except .
var themeModes = func() *safety.Map[string, ThemeMods] { var themeModes = func() *safety.Map[string, ThemeMods] {
m := safety.NewMap[string, ThemeMods]() m := safety.NewMap[string, ThemeMods]()
themeModsRaw = safety.NewMap[string, map[string]any]()
reload.Push(func() { reload.Push(func() {
m.Flush() m.Flush()
themeModsRaw.Flush()
}) })
return m return m
}() }()
var themeModsRaw *safety.Map[string, map[string]any]
func GetThemeModsVal[T any](theme, k string, defaults T) (r T) {
m, ok := themeModsRaw.Load(theme)
if !ok {
r = defaults
return
}
r = maps.GetStrAnyValWithDefaults(m, k, defaults)
return
}
func GetThemeMods(theme string) (r ThemeMods, err error) { func GetThemeMods(theme string) (r ThemeMods, err error) {
r, ok := themeModes.Load(theme) r, ok := themeModes.Load(theme)
if ok { if ok {
return return
} }
mods, ok := Options.Load(fmt.Sprintf("theme_mods_%s", theme)) mods := GetOption(fmt.Sprintf("theme_mods_%s", theme))
if !ok || mods == "" { if mods == "" {
return return
} }
m, err := phphelper.UnPHPSerializeToAnyMap(mods)
if err != nil {
return
}
themeModsRaw.Store(theme, m)
//这里在的err可以不用处理因为php的默认值和有设置过的类型可能不一样直接按有设置的类型处理就行 //这里在的err可以不用处理因为php的默认值和有设置过的类型可能不一样直接按有设置的类型处理就行
r, err = phphelper.UnPHPSerialize[ThemeMods](mods) r, err = maps.StrAnyMapToStruct[ThemeMods](m)
if err != nil {
logs.ErrPrintln(err, "解析thememods错误")
err = nil
}
r.setThemeSupport(theme) r.setThemeSupport(theme)
themeModes.Store(theme, r) themeModes.Store(theme, r)
return return

View File

@ -105,7 +105,7 @@ func init() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
InitDB(NewSqlxQuery(db)) InitDB(NewSqlxQuery(db, NewUniversalDb(nil, nil)))
} }
func TestFind(t *testing.T) { func TestFind(t *testing.T) {
type args struct { type args struct {

View File

@ -3,7 +3,9 @@ package model
import ( import (
"context" "context"
"database/sql" "database/sql"
"errors"
"fmt" "fmt"
"github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/helper/slice" "github.com/fthvgb1/wp-go/helper/slice"
"strings" "strings"
) )
@ -25,43 +27,10 @@ func FindFromDB[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r
} }
func finds[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r []T, err error) { func finds[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r []T, err error) {
var rr T sq, args, err := FindRawSql[T](q)
w := "" if err != nil {
var args []any return
if q.where != nil {
w, args, err = q.where.ParseWhere(&q.in)
if err != nil {
return r, err
}
} }
h := ""
if q.having != nil {
hh, arg, err := q.having.ParseWhere(&q.in)
if err != nil {
return r, err
}
args = append(args, arg...)
h = strings.Replace(hh, " where", " having", 1)
}
j := q.join.parseJoin()
groupBy := ""
if q.group != "" {
g := strings.Builder{}
g.WriteString(" group by ")
g.WriteString(q.group)
groupBy = g.String()
}
tp := "select %s from %s %s %s %s %s %s %s"
l := ""
if q.limit > 0 {
l = fmt.Sprintf(" limit %d", q.limit)
}
if q.offset > 0 {
l = fmt.Sprintf(" %s offset %d", l, q.offset)
}
sq := fmt.Sprintf(tp, q.fields, rr.Table(), j, w, groupBy, h, q.order.parseOrderBy(), l)
err = db.Select(ctx, &r, sq, args...) err = db.Select(ctx, &r, sq, args...)
return return
} }
@ -186,3 +155,92 @@ func column[V Model, T any](db dbQuery, ctx context.Context, fn func(V) (T, bool
r = slice.FilterAndMap(res, fn) r = slice.FilterAndMap(res, fn)
return return
} }
func GetField[T Model, V any](ctx context.Context, field string, q *QueryCondition) (r V, err error) {
r, err = getField[T, V](globalBb, ctx, field, q)
return
}
func getField[T Model, V any](db dbQuery, ctx context.Context, field string, q *QueryCondition) (r V, err error) {
res, err := getToAnyMap[T](globalBb, ctx, q)
if err != nil {
return
}
r, ok := maps.GetStrAnyVal[V](res, field)
if !ok {
err = errors.New("not exists")
}
return
}
func GetFieldFromDB[T Model, V any](db dbQuery, ctx context.Context, field string, q *QueryCondition) (r V, err error) {
return getField[T, V](db, ctx, field, q)
}
func findToAnyMap[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r []map[string]any, err error) {
rawSql, in, err := FindRawSql[T](q)
if err != nil {
return nil, err
}
ctx = context.WithValue(ctx, "toMap", true)
err = db.Select(ctx, &r, rawSql, in...)
return
}
func FindToAnyMap[T Model](ctx context.Context, q *QueryCondition) (r []map[string]any, err error) {
r, err = findToAnyMap[T](globalBb, ctx, q)
return
}
func FindToAnyMapFromDB[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r []map[string]any, err error) {
r, err = findToAnyMap[T](db, ctx, q)
return
}
func getToAnyMap[T Model](db dbQuery, ctx context.Context, q *QueryCondition) (r map[string]any, err error) {
rawSql, in, err := FindRawSql[T](q)
if err != nil {
return nil, err
}
ctx = context.WithValue(ctx, "toMap", true)
err = db.Get(ctx, &r, rawSql, in...)
return
}
func FindRawSql[T Model](q *QueryCondition) (r string, args []any, err error) {
var rr T
w := ""
if q.where != nil {
w, args, err = q.where.ParseWhere(&q.in)
if err != nil {
return
}
}
h := ""
if q.having != nil {
hh, arg, er := q.having.ParseWhere(&q.in)
if er != nil {
err = er
return
}
args = append(args, arg...)
h = strings.Replace(hh, " where", " having", 1)
}
j := q.join.parseJoin()
groupBy := ""
if q.group != "" {
g := strings.Builder{}
g.WriteString(" group by ")
g.WriteString(q.group)
groupBy = g.String()
}
tp := "select %s from %s %s %s %s %s %s %s"
l := ""
if q.limit > 0 {
l = fmt.Sprintf(" limit %d", q.limit)
}
if q.offset > 0 {
l = fmt.Sprintf(" %s offset %d", l, q.offset)
}
r = fmt.Sprintf(tp, q.fields, rr.Table(), j, w, groupBy, h, q.order.parseOrderBy(), l)
return
}

View File

@ -273,3 +273,56 @@ func TestColumn(t *testing.T) {
}) })
} }
} }
func TestGetField(t *testing.T) {
type args struct {
ctx context.Context
field string
q *QueryCondition
}
type testCase[V any] struct {
name string
args args
wantR V
wantErr bool
}
tests := []testCase[string]{
{
name: "t1",
args: args{
ctx: ctx,
field: "option_value",
q: Conditions(Where(SqlBuilder{{"option_name", "blogname"}})),
},
wantR: "记录并见证自己的成长",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotR, err := GetField[options, string](tt.args.ctx, tt.args.field, tt.args.q)
if (err != nil) != tt.wantErr {
t.Errorf("GetField() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotR, tt.wantR) {
t.Errorf("GetField() gotR = %v, want %v", gotR, tt.wantR)
}
})
}
}
type options struct {
OptionId uint64 `gorm:"column:option_id" db:"option_id" json:"option_id" form:"option_id"`
OptionName string `gorm:"column:option_name" db:"option_name" json:"option_name" form:"option_name"`
OptionValue string `gorm:"column:option_value" db:"option_value" json:"option_value" form:"option_value"`
Autoload string `gorm:"column:autoload" db:"autoload" json:"autoload" form:"autoload"`
}
func (w options) PrimaryKey() string {
return "option_id"
}
func (w options) Table() string {
return "wp_options"
}

View File

@ -4,34 +4,129 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"log"
"os"
"strconv" "strconv"
"strings" "strings"
) )
type SqlxQuery struct { type SqlxQuery struct {
sqlx *sqlx.DB sqlx *sqlx.DB
UniversalDb
} }
func NewSqlxQuery(sqlx *sqlx.DB) SqlxQuery { func NewSqlxQuery(sqlx *sqlx.DB, u UniversalDb) *SqlxQuery {
return SqlxQuery{sqlx: sqlx}
s := &SqlxQuery{sqlx: sqlx, UniversalDb: u}
if u.selects == nil {
s.UniversalDb.selects = s.Selects
}
if u.gets == nil {
s.UniversalDb.gets = s.Gets
}
return s
} }
func (r SqlxQuery) Select(ctx context.Context, dest any, sql string, params ...any) error { func SetSelect(db *SqlxQuery, fn func(context.Context, any, string, ...any) error) {
if os.Getenv("SHOW_SQL") == "true" { db.selects = fn
go log.Println(FormatSql(sql, params...)) }
func SetGet(db *SqlxQuery, fn func(context.Context, any, string, ...any) error) {
db.gets = fn
}
func (r *SqlxQuery) Selects(ctx context.Context, dest any, sql string, params ...any) error {
v := ctx.Value("toMap")
if v != nil {
vv, ok := v.(bool)
if ok && vv {
d, ok := dest.(*[]map[string]any)
if ok {
return r.toMapSlice(d, sql, params...)
}
}
} }
return r.sqlx.Select(dest, sql, params...) return r.sqlx.Select(dest, sql, params...)
} }
func (r SqlxQuery) Get(ctx context.Context, dest any, sql string, params ...any) error { func (r *SqlxQuery) Gets(ctx context.Context, dest any, sql string, params ...any) error {
if os.Getenv("SHOW_SQL") == "true" { v := ctx.Value("toMap")
go log.Println(FormatSql(sql, params...)) if v != nil {
vv, ok := v.(bool)
if ok && vv {
d, ok := dest.(*map[string]any)
if ok {
return r.toMap(d, sql, params...)
}
}
} }
return r.sqlx.Get(dest, sql, params...) return r.sqlx.Get(dest, sql, params...)
} }
func (r *SqlxQuery) toMap(dest *map[string]any, sql string, params ...any) (err error) {
rows := r.sqlx.QueryRowx(sql, params...)
columns, err := rows.Columns()
if err != nil {
return err
}
columnLen := len(columns)
c := make([]any, columnLen)
for i, _ := range c {
var a any
c[i] = &a
}
err = rows.Scan(c...)
if err != nil {
return
}
v := make(map[string]any)
for i, data := range c {
s, ok := data.(*any)
if ok {
ss, ok := (*s).([]uint8)
if ok {
data = string(ss)
}
}
v[columns[i]] = data
}
*dest = v
return
}
func (r *SqlxQuery) toMapSlice(dest *[]map[string]any, sql string, params ...any) (err error) {
rows, err := r.sqlx.Query(sql, params...)
columns, err := rows.Columns()
if err != nil {
return err
}
defer rows.Close()
columnLen := len(columns)
c := make([]any, columnLen)
for i, _ := range c {
var a any
c[i] = &a
}
var m []map[string]any
for rows.Next() {
err = rows.Scan(c...)
if err != nil {
return
}
v := make(map[string]any)
for i, data := range c {
s, ok := data.(*any)
if ok {
ss, ok := (*s).([]uint8)
if ok {
data = string(ss)
}
}
v[columns[i]] = data
}
m = append(m, v)
}
*dest = m
return
}
func FormatSql(sql string, params ...any) string { func FormatSql(sql string, params ...any) string {
for _, param := range params { for _, param := range params {
switch param.(type) { switch param.(type) {