From a319e7595f84c667f637d3a0b1d0e81bd664409f Mon Sep 17 00:00:00 2001 From: xing Date: Tue, 21 Feb 2023 01:07:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0getoption=E5=87=BD=E6=95=B0=EF=BC=8C=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0db=E6=9F=A5=E8=AF=A2=E5=87=BD=E6=95=B0=EF=BC=8C?= =?UTF-8?q?=E5=8F=AF=E8=BF=94=E5=9B=9Emap[string]any=EF=BC=8C=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0getthememods=E5=87=BD=E6=95=B0=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E4=B8=8D=E5=A4=AA=E9=80=9A=E7=94=A8=E7=9A=84=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helper/maps/function.go | 15 +++- helper/maps/function_test.go | 6 +- internal/actions/comment.go | 4 +- internal/actions/login.go | 2 +- internal/middleware/sendmail.go | 2 +- internal/phphelper/unserialize.go | 15 +++- internal/pkg/cache/feed.go | 18 ++-- internal/pkg/cache/headerImages.go | 71 ++++++++------- internal/pkg/dao/postmeta.go | 2 +- internal/pkg/db/db.go | 32 +++---- internal/plugins/gravatar.go | 2 +- internal/theme/common/customlogo.go | 4 +- internal/theme/common/detail.go | 6 +- internal/theme/common/indexparams.go | 8 +- internal/theme/common/siteicon.go | 2 +- internal/theme/templateFuncs.go | 2 +- internal/theme/theme.go | 2 +- internal/wpconfig/options.go | 28 ++++-- internal/wpconfig/thememods.go | 34 ++++++- model/query_test.go | 2 +- model/querycondition.go | 130 +++++++++++++++++++-------- model/querycondition_test.go | 53 +++++++++++ model/sqxquery.go | 115 +++++++++++++++++++++--- 23 files changed, 417 insertions(+), 138 deletions(-) diff --git a/helper/maps/function.go b/helper/maps/function.go index 4f487c0..8c78f3d 100644 --- a/helper/maps/function.go +++ b/helper/maps/function.go @@ -2,14 +2,14 @@ package maps 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, ".") if len(k) > 1 { val, ok := m[k[0]] if ok { vx, ok := val.(map[string]any) if ok { - r, o = GetStrMapAnyVal[T](vx, strings.Join(k[1:], ".")) + r, o = GetStrAnyVal[T](vx, strings.Join(k[1:], ".")) } } } else { @@ -25,6 +25,17 @@ func GetStrMapAnyVal[T any](m map[string]any, key string) (r T, o bool) { 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) { k := strings.Split(key, ".") if len(k) > 1 { diff --git a/helper/maps/function_test.go b/helper/maps/function_test.go index 79a5c8e..1045272 100644 --- a/helper/maps/function_test.go +++ b/helper/maps/function_test.go @@ -54,12 +54,12 @@ func TestGetStrMapAnyVal(t *testing.T) { } for _, tt := range tests { 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) { - t.Errorf("GetStrMapAnyVal() gotR = %v, want %v", gotR, tt.wantR) + t.Errorf("GetStrAnyVal() gotR = %v, want %v", gotR, tt.wantR) } if gotO != tt.wantO { - t.Errorf("GetStrMapAnyVal() gotO = %v, want %v", gotO, tt.wantO) + t.Errorf("GetStrAnyVal() gotO = %v, want %v", gotO, tt.wantO) } }) } diff --git a/internal/actions/comment.go b/internal/actions/comment.go index 8f6faca..e91283b 100644 --- a/internal/actions/comment.go +++ b/internal/actions/comment.go @@ -50,7 +50,7 @@ func PostComment(c *gin.Context) { } defer req.Body.Close() req.Header = c.Request.Header.Clone() - home, err := url.Parse(wpconfig.Options.Value("siteurl")) + home, err := url.Parse(wpconfig.GetOption("siteurl")) if err != nil { return } @@ -102,7 +102,7 @@ func PostComment(c *gin.Context) { logs.ErrPrintln(err, "获取文档", id) 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) logs.ErrPrintln(err, "发送邮件", conf.Mail.User, su, comment) }() diff --git a/internal/actions/login.go b/internal/actions/login.go index 343184d..4b86317 100644 --- a/internal/actions/login.go +++ b/internal/actions/login.go @@ -33,7 +33,7 @@ func Login(c *gin.Context) { c.Error(err) 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.Redirect(http.StatusFound, ref) diff --git a/internal/middleware/sendmail.go b/internal/middleware/sendmail.go index 427c8c1..c0d6450 100644 --- a/internal/middleware/sendmail.go +++ b/internal/middleware/sendmail.go @@ -45,7 +45,7 @@ func RecoverAndSendMail(w io.Writer) func(ctx *gin.Context) { er := mail.SendMail( []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 { logs.ErrPrintln(er, "recover send mail fail", fmt.Sprintf("%v", err)) diff --git a/internal/phphelper/unserialize.go b/internal/phphelper/unserialize.go index dc35bbf..0fd0036 100644 --- a/internal/phphelper/unserialize.go +++ b/internal/phphelper/unserialize.go @@ -5,7 +5,8 @@ import ( "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 err = phpserialize.Unmarshal([]byte(s), &rr) if err == nil { @@ -14,3 +15,15 @@ func UnPHPSerialize[T any](s string) (r T, err error) { } 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 +} diff --git a/internal/pkg/cache/feed.go b/internal/pkg/cache/feed.go index 1e1bd10..7cded30 100644 --- a/internal/pkg/cache/feed.go +++ b/internal/pkg/cache/feed.go @@ -21,14 +21,14 @@ var templateRss rss2.Rss2 func InitFeed() { templateRss = rss2.Rss2{ - Title: wpconfig.Options.Value("blogname"), - AtomLink: fmt.Sprintf("%s/feed", wpconfig.Options.Value("home")), - Link: wpconfig.Options.Value("siteurl"), - Description: wpconfig.Options.Value("blogdescription"), + Title: wpconfig.GetOption("blogname"), + AtomLink: fmt.Sprintf("%s/feed", wpconfig.GetOption("home")), + Link: wpconfig.GetOption("siteurl"), + Description: wpconfig.GetOption("blogdescription"), Language: wpconfig.GetLang(), UpdatePeriod: "hourly", 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 { return } - site := wpconfig.Options.Value("siteurl") + site := wpconfig.GetOption("siteurl") rs := templateRss rs.LastBuildDate = time.Now().Format(timeFormat) rs.Items = slice.Map(posts, func(t models.Posts) rss2.Item { @@ -109,7 +109,7 @@ func postFeed(arg ...any) (x string, err error) { return } rs := templateRss - site := wpconfig.Options.Value("siteurl") + site := wpconfig.GetOption("siteurl") rs.Title = fmt.Sprintf("《%s》的评论", post.PostTitle) 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) commens := RecentComments(c, 10) 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) - site := wpconfig.Options.Value("siteurl") + site := wpconfig.GetOption("siteurl") rs.AtomLink = fmt.Sprintf("%s/comments/feed", site) com, err := GetCommentByIds(c, slice.Map(commens, func(t models.Comments) uint64 { return t.CommentId diff --git a/internal/pkg/cache/headerImages.go b/internal/pkg/cache/headerImages.go index 078a8bf..aeea387 100644 --- a/internal/pkg/cache/headerImages.go +++ b/internal/pkg/cache/headerImages.go @@ -20,40 +20,10 @@ func getHeaderImages(a ...any) (r []models.PostThumbnail, err error) { ctx := a[0].(context.Context) theme := a[1].(string) meta, err := wpconfig.GetThemeMods(theme) - if err == nil && meta.HeaderImage != "" { - if "random-uploaded-image" == meta.HeaderImage { - 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 - } + if err != nil || meta.HeaderImage == "" { + return + } + if "random-uploaded-image" != meta.HeaderImage { m, er := GetPostById(ctx, uint64(meta.HeaderImagData.AttachmentId)) if er != nil { err = er @@ -61,8 +31,41 @@ func getHeaderImages(a ...any) (r []models.PostThumbnail, err error) { } m.Thumbnail = thumb(m, theme) 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 + } func thumb(m models.Posts, theme string) models.PostThumbnail { diff --git a/internal/pkg/dao/postmeta.go b/internal/pkg/dao/postmeta.go index 195139d..a5288a9 100644 --- a/internal/pkg/dao/postmeta.go +++ b/internal/pkg/dao/postmeta.go @@ -28,7 +28,7 @@ func GetPostMetaByPostIds(args ...any) (r map[uint64]map[string]any, err error) } r[postmeta.PostId][postmeta.MetaKey] = postmeta.MetaValue 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 { logs.ErrPrintln(err, "解析postmeta失败", postmeta.MetaId, postmeta.MetaValue) continue diff --git a/internal/pkg/db/db.go b/internal/pkg/db/db.go index 27e9115..21ddf71 100644 --- a/internal/pkg/db/db.go +++ b/internal/pkg/db/db.go @@ -34,22 +34,22 @@ func InitDb() (*sqlx.DB, error) { return db, err } -func QueryDb(db *sqlx.DB) model.UniversalDb { - query := model.NewUniversalDb( - - func(ctx context.Context, a any, s string, args ...any) error { - 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...) - }) +func QueryDb(db *sqlx.DB) *model.SqlxQuery { + query := model.NewSqlxQuery(db, model.NewUniversalDb( + nil, + nil)) + 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 } diff --git a/internal/plugins/gravatar.go b/internal/plugins/gravatar.go index dbb5cb1..2335118 100644 --- a/internal/plugins/gravatar.go +++ b/internal/plugins/gravatar.go @@ -25,7 +25,7 @@ func Gravatar(email string, isTls bool) (u string) { q := url.Values{} q.Add("s", "112") 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()) return } diff --git a/internal/theme/common/customlogo.go b/internal/theme/common/customlogo.go index 1fd6f99..b731c04 100644 --- a/internal/theme/common/customlogo.go +++ b/internal/theme/common/customlogo.go @@ -11,7 +11,7 @@ import ( func (h *Handle) CalCustomLogo() (r string) { id := uint64(h.ThemeMods.CustomLogo) 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 { return } @@ -22,7 +22,7 @@ func (h *Handle) CalCustomLogo() (r string) { } siz := "full" 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) imgx := map[string]string{ "class": "custom-logo", diff --git a/internal/theme/common/detail.go b/internal/theme/common/detail.go index dc72420..bd578b1 100644 --- a/internal/theme/common/detail.go +++ b/internal/theme/common/detail.go @@ -24,7 +24,7 @@ func NewDetailHandle(handle *Handle) *DetailHandle { } func (d *DetailHandle) BuildDetailData() (err error) { - d.GinH["title"] = wpconfig.Options.Value("blogname") + d.GinH["title"] = wpconfig.GetOption("blogname") err = d.CheckAndGetPost() if err != nil { return @@ -51,7 +51,7 @@ func (d *DetailHandle) CheckAndGetPost() (err error) { d.GinH["post"] = post d.Post = post 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 } @@ -80,7 +80,7 @@ func (d *DetailHandle) RenderComment() { } d.GinH["showComment"] = 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) } } diff --git a/internal/theme/common/indexparams.go b/internal/theme/common/indexparams.go index 24d972b..a5339fb 100644 --- a/internal/theme/common/indexparams.go +++ b/internal/theme/common/indexparams.go @@ -89,15 +89,15 @@ func (i *IndexParams) getSearchKey() string { } func NewIndexParams(ctx *gin.Context) *IndexParams { - blogName := wpconfig.Options.Value("blogname") - size := str.ToInteger(wpconfig.Options.Value("posts_per_page"), 10) + blogName := wpconfig.GetOption("blogname") + size := str.ToInteger(wpconfig.GetOption("posts_per_page"), 10) i := &IndexParams{ Ctx: ctx, Page: 1, PageSize: size, PaginationStep: number.Max(1, config.GetConfig().PaginationStep), TitleL: blogName, - TitleR: wpconfig.Options.Value("blogdescription"), + TitleR: wpconfig.GetOption("blogdescription"), Where: model.SqlBuilder{ {"post_type", "in", ""}, {"post_status", "in", ""}, @@ -106,7 +106,7 @@ func NewIndexParams(ctx *gin.Context) *IndexParams { Join: model.SqlBuilder{}, PostType: []any{"post"}, PostStatus: []any{"publish"}, - BlogName: wpconfig.Options.Value("blogname"), + BlogName: wpconfig.GetOption("blogname"), } i.ParseSearch = i.parseSearch i.ParseArchive = i.parseArchive diff --git a/internal/theme/common/siteicon.go b/internal/theme/common/siteicon.go index 960a9bf..46e79e3 100644 --- a/internal/theme/common/siteicon.go +++ b/internal/theme/common/siteicon.go @@ -12,7 +12,7 @@ import ( var sizes = []string{"site_icon-270", "site_icon-32", "site_icon-192", "site_icon-180"} 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 { return } diff --git a/internal/theme/templateFuncs.go b/internal/theme/templateFuncs.go index b1f17c4..cc31132 100644 --- a/internal/theme/templateFuncs.go +++ b/internal/theme/templateFuncs.go @@ -14,7 +14,7 @@ var comFn = template.FuncMap{ return t.Format("2006年 01月 02日") }, "getOption": func(k string) string { - return wpconfig.Options.Value(k) + return wpconfig.GetOption(k) }, "getLang": wpconfig.GetLang, } diff --git a/internal/theme/theme.go b/internal/theme/theme.go index 44344ac..79ef17f 100644 --- a/internal/theme/theme.go +++ b/internal/theme/theme.go @@ -16,7 +16,7 @@ func InitTheme() { func GetTemplateName() string { tmlp := config.GetConfig().Theme if tmlp == "" { - tmlp = wpconfig.Options.Value("template") + tmlp = wpconfig.GetOption("template") } if !IsTemplateDirExists(tmlp) { tmlp = "twentyfifteen" diff --git a/internal/wpconfig/options.go b/internal/wpconfig/options.go index 3424bbd..84f4fa4 100644 --- a/internal/wpconfig/options.go +++ b/internal/wpconfig/options.go @@ -8,10 +8,15 @@ import ( "strings" ) -var Options safety.Map[string, string] +var options safety.Map[string, string] + +var ctx context.Context 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") if err != nil { return err @@ -22,14 +27,27 @@ func InitOptions() error { return err } } - for _, options := range ops { - Options.Store(options.OptionName, options.OptionValue) + for _, option := range ops { + options.Store(option.OptionName, option.OptionValue) } 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 { - s, ok := Options.Load("WPLANG") + s, ok := options.Load("WPLANG") if !ok { s = "zh-CN" } diff --git a/internal/wpconfig/thememods.go b/internal/wpconfig/thememods.go index 106249a..4fa66e7 100644 --- a/internal/wpconfig/thememods.go +++ b/internal/wpconfig/thememods.go @@ -7,6 +7,7 @@ import ( "github.com/fthvgb1/wp-go/helper/maps" "github.com/fthvgb1/wp-go/internal/cmd/reload" "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/safety" "path/filepath" @@ -19,6 +20,7 @@ func SetTemplateFs(fs embed.FS) { templateFs = fs } +// ThemeMods 只有部分公共的参数,其它的参数调用 GetThemeModsVal 函数获取 type ThemeMods struct { CustomCssPostId int `json:"custom_css_post_id,omitempty"` NavMenuLocations map[string]int `json:"nav_menu_locations,omitempty"` @@ -36,6 +38,8 @@ type ThemeMods struct { SidebarTextcolor string `json:"sidebar_textcolor,omitempty"` HeaderBackgroundColor string `json:"header_background_color,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"` SidebarsWidgets Sidebars `json:"sidebars_widgets,omitempty"` ThemeSupport ThemeSupport @@ -106,23 +110,47 @@ func Thumbnail(metadata models.WpAttachmentMetadata, Type, host string, except . var themeModes = func() *safety.Map[string, ThemeMods] { m := safety.NewMap[string, ThemeMods]() + themeModsRaw = safety.NewMap[string, map[string]any]() reload.Push(func() { m.Flush() + themeModsRaw.Flush() }) + 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) { r, ok := themeModes.Load(theme) if ok { return } - mods, ok := Options.Load(fmt.Sprintf("theme_mods_%s", theme)) - if !ok || mods == "" { + mods := GetOption(fmt.Sprintf("theme_mods_%s", theme)) + if mods == "" { return } + m, err := phphelper.UnPHPSerializeToAnyMap(mods) + if err != nil { + return + } + themeModsRaw.Store(theme, m) //这里在的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) themeModes.Store(theme, r) return diff --git a/model/query_test.go b/model/query_test.go index 1aafe69..7db74fe 100644 --- a/model/query_test.go +++ b/model/query_test.go @@ -105,7 +105,7 @@ func init() { if err != nil { panic(err) } - InitDB(NewSqlxQuery(db)) + InitDB(NewSqlxQuery(db, NewUniversalDb(nil, nil))) } func TestFind(t *testing.T) { type args struct { diff --git a/model/querycondition.go b/model/querycondition.go index 6b02382..7c8160c 100644 --- a/model/querycondition.go +++ b/model/querycondition.go @@ -3,7 +3,9 @@ package model import ( "context" "database/sql" + "errors" "fmt" + "github.com/fthvgb1/wp-go/helper/maps" "github.com/fthvgb1/wp-go/helper/slice" "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) { - var rr T - w := "" - var args []any - if q.where != nil { - w, args, err = q.where.ParseWhere(&q.in) - if err != nil { - return r, err - } + sq, args, err := FindRawSql[T](q) + if err != nil { + return } - 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...) 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) 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 +} diff --git a/model/querycondition_test.go b/model/querycondition_test.go index 1bc7c9b..1718b23 100644 --- a/model/querycondition_test.go +++ b/model/querycondition_test.go @@ -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" +} diff --git a/model/sqxquery.go b/model/sqxquery.go index 1ee944a..ef877cc 100644 --- a/model/sqxquery.go +++ b/model/sqxquery.go @@ -4,34 +4,129 @@ import ( "context" "fmt" "github.com/jmoiron/sqlx" - "log" - "os" "strconv" "strings" ) type SqlxQuery struct { sqlx *sqlx.DB + UniversalDb } -func NewSqlxQuery(sqlx *sqlx.DB) SqlxQuery { - return SqlxQuery{sqlx: sqlx} +func NewSqlxQuery(sqlx *sqlx.DB, u UniversalDb) *SqlxQuery { + + 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 { - if os.Getenv("SHOW_SQL") == "true" { - go log.Println(FormatSql(sql, params...)) +func SetSelect(db *SqlxQuery, fn func(context.Context, any, string, ...any) error) { + db.selects = fn +} +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...) } -func (r SqlxQuery) Get(ctx context.Context, dest any, sql string, params ...any) error { - if os.Getenv("SHOW_SQL") == "true" { - go log.Println(FormatSql(sql, params...)) +func (r *SqlxQuery) Gets(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.toMap(d, 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 { for _, param := range params { switch param.(type) {