Files
webp/api/image.go
2024-12-02 07:11:06 +08:00

612 lines
24 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package api
import (
"context"
"database/sql/driver"
"encoding/json"
"fmt"
"log"
"regexp"
"strconv"
"strings"
"time"
"git.satori.love/gameui/webp/models"
"github.com/doug-martin/goqu/v9"
"github.com/graphql-go/graphql"
"github.com/zhenghaoz/gorse/client"
)
type Image struct {
ID int `json:"id" gorm:"primaryKey"`
Width int `json:"width"`
Height int `json:"height"`
Content string `json:"content"`
Remark string `json:"remark"`
Description string `json:"description"`
Tags string `json:"tags"`
Rank string `json:"rank"`
CommentNum int `json:"comment_num"`
PraiseCount int `json:"praise_count" gorm:"column:praise"`
CollectCount int `json:"collect_count"`
ArticleID int `json:"article_id"`
UserID int `json:"user_id"`
CreateTime time.Time `json:"create_time"`
UpdateTime time.Time `json:"update_time"`
Text TextList `json:"text" gorm:"type:json"`
User User `json:"user" gorm:"foreignKey:UserID"`
Article Article `json:"article" gorm:"foreignKey:ArticleID"`
Activity bool `json:"activity"`
}
func (Image) TableName() string {
return "web_images"
}
type TextList []struct {
Text string `json:"text"`
Confidence float64 `json:"confidence"`
Coordinate [][]float64 `json:"coordinate"`
}
func (a *TextList) Scan(value interface{}) error {
// 如果数据库中的值为NULL则返回nil
if value == nil || len(value.([]byte)) == 0 {
*a = TextList{}
return nil
}
return json.Unmarshal(value.([]byte), a)
}
func (a TextList) Value() (driver.Value, error) {
return json.Marshal(a)
}
// 图像的可选字段
var imageType = graphql.NewObject(graphql.ObjectConfig{
Name: "Image",
Description: "图像",
Fields: graphql.Fields{
"id": &graphql.Field{Type: graphql.Int, Description: "图像ID"},
"width": &graphql.Field{Type: graphql.Int, Description: "图像宽度"},
"height": &graphql.Field{Type: graphql.Int, Description: "图像高度"},
"content": &graphql.Field{Type: graphql.String, Description: "图像内容"},
"remark": &graphql.Field{Type: graphql.String, Description: "图像备注"},
"description": &graphql.Field{Type: graphql.String, Description: "图像描述"},
"tags": &graphql.Field{Type: graphql.String, Description: "图像标签"},
"rank": &graphql.Field{Type: graphql.String, Description: "图像等级"},
"comment_num": &graphql.Field{Type: graphql.Int, Description: "评论数"},
"article_category_top_id": &graphql.Field{Type: graphql.Int, Description: "文章分类顶级ID"},
"praise_count": &graphql.Field{Type: graphql.Int, Description: "点赞数"},
"collect_count": &graphql.Field{Type: graphql.Int, Description: "收藏数"},
"create_time": &graphql.Field{Type: graphql.DateTime, Description: "图像创建时间"},
"update_time": &graphql.Field{Type: graphql.DateTime, Description: "图像更新时间"},
"activity": &graphql.Field{Type: graphql.Boolean, Description: "图像活动"},
"article": &graphql.Field{Type: articleType, Description: "图像所属文章"},
"praise": &graphql.Field{Type: graphql.Boolean, Description: "当前用户是否点赞", Resolve: func(p graphql.ResolveParams) (interface{}, error) {
var user_id = p.Context.Value("user_id").(int)
if user_id != 0 {
var praise int64
if err := db.Table("web_praise").Where("user_id = ?", user_id).Where("praise_id = ?", p.Source.(Image).ID).Where("type = ?", 4).Count(&praise); err != nil {
return false, nil
}
if praise > 0 {
return true, nil
}
}
return false, nil
}},
"collect": &graphql.Field{Type: graphql.Boolean, Description: "当前用户是否收藏", Resolve: func(p graphql.ResolveParams) (interface{}, error) {
var user_id = p.Context.Value("user_id").(int)
if user_id != 0 {
var collect int64
if err := db.Table("web_collect").Where("user_id = ?", user_id).Where("image_id = ?", p.Source.(Image).ID).Count(&collect); err != nil {
return false, nil
}
if collect > 0 {
return true, nil
}
}
return false, nil
}},
"collect_id": &graphql.Field{Type: graphql.Int, Description: "当前用户收藏ID", Resolve: func(p graphql.ResolveParams) (interface{}, error) {
var user_id = p.Context.Value("user_id").(int)
if user_id != 0 {
var collect_id int
if err := db.Table("web_collect").Where("user_id = ?", user_id).Where("image_id = ?", p.Source.(Image).ID).First(&collect_id); err != nil {
return nil, nil
}
return collect_id, nil
}
return nil, nil
}},
"text": &graphql.Field{
Type: graphql.NewList(graphql.NewObject(graphql.ObjectConfig{
Name: "Text",
Description: "图像中的文字提取",
Fields: graphql.Fields{
"text": &graphql.Field{Type: graphql.String, Description: "文字内容"},
"confidence": &graphql.Field{Type: graphql.Float, Description: "置信度"},
"coordinate": &graphql.Field{Type: &graphql.List{OfType: graphql.NewList(graphql.Float)}, Description: "文字坐标"},
},
})),
Description: "图像中的文字",
Args: graphql.FieldConfigArgument{
"text": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选含有指定文字的列"},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
if p.Args["text"] != nil {
var texts TextList
for _, text := range p.Source.(Image).Text {
if strings.Contains(text.Text, p.Args["text"].(string)) {
texts = append(texts, text)
}
}
return texts, nil
}
return p.Source.(Image).Text, nil
},
},
"user": &graphql.Field{Type: userType, Description: "图像所属用户"},
},
})
//image.AddFieldConfig("user", &graphql.Field{Type: userType, Description: "图像所属用户"})
//image.AddFieldConfig("similars", &graphql.Field{Type: graphql.NewList(image), Description: "相似的图像", Resolve: func(p graphql.ResolveParams) (interface{}, error) {
// return []Image{}, nil
//}})
var ImageItem = &graphql.Field{
Name: "image",
Description: "单张图片",
Type: imageType,
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "根据ID获取图片"},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
img := Image{ID: p.Args["id"].(int)}
query := db.Limit(1)
for index, item := range LoadItem(p.Info.FieldASTs[0].SelectionSet.Selections) {
fmt.Println(index, item)
query = query.Preload(item)
}
if err := query.First(&img).Error; err != nil {
log.Println("获取图片失败", err)
return nil, err
}
return img, nil
},
}
var ImageItems = &graphql.Field{
Name: "images",
Description: "图像列表",
Type: graphql.NewObject(graphql.ObjectConfig{
Name: "ImageConnection",
Description: "条件筛选图像列表",
Fields: graphql.Fields{
"list": &graphql.Field{Type: graphql.NewList(imageType), Description: "图像列表"},
"total": &graphql.Field{Type: graphql.Int, Description: "图像总数"},
},
}),
Args: graphql.FieldConfigArgument{
"activity": &graphql.ArgumentConfig{Type: graphql.Boolean, Description: "按是否活动筛选图像"},
"style": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏风格筛选图像"},
"device": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏平台筛选图像"},
"orientation": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏版式筛选图像"},
"era": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏年份筛选图像"},
"category_id": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏类型筛选图像(支持多选)"},
"tags": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏标签筛选图像(支持多选)"},
"images_desc": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏归类筛选图像(支持多选)"},
"article_tags": &graphql.ArgumentConfig{Type: graphql.String, Description: "按文章标签筛选图像(支持多选)"},
"color": &graphql.ArgumentConfig{Type: graphql.String, Description: "按主色调筛选图像, 使用十六进制颜色代码(#FF1414)"},
"explorer_id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定收藏夹的"},
"collect_id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定收藏夹的"},
"collect": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定用户收藏过的"},
"praise": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定用户点赞过的"},
"follower": &graphql.ArgumentConfig{Type: graphql.Int, Description: "获取指定ID用户的关注列表发布的图像"},
"interest": &graphql.ArgumentConfig{Type: graphql.Int, Description: "获取指定ID用户的兴趣推荐图像"},
"similar": &graphql.ArgumentConfig{Type: graphql.Int, Description: "获取与指定ID图像相似的图像"},
"id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "获取指定ID的图像"},
"width": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定宽度的"},
"height": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定高度的"},
"comment_num": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中评论数等于指定值的"},
"praise_count": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中点赞数等于指定值的"},
"collect_count": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中收藏数等于指定值的"},
"article_id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中属于指定文章ID的"},
"user_id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中属于指定用户ID的"},
"sort": &graphql.ArgumentConfig{Type: graphql.String, Description: "排序方法", DefaultValue: "id"},
"content": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中含有指定内容的"},
"remark": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中含有指定备注的"},
"description": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中含有指定描述的"},
"rank": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中含有指定排名的"},
"text": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中含有指定文字的"},
"create_time": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中创建时间等于指定值的"},
"update_time": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中更新时间等于指定值的"},
"first": &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的前n個元素)"},
"last": &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的最後n個元素)"},
"after": &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中指定遊標之後的元素)"},
"before": &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中指定遊標之前的元素)"},
"order": &graphql.ArgumentConfig{Type: orderType, Description: "排序方向", DefaultValue: "ASC"},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
var total int
var images []Image
var query = goqu.Dialect("mysql").From("web_images")
// 参数映射
var argFormat = []string{"id", "width", "height", "content", "remark", "description", "rank", "comment_num", "praise_count", "collect_count", "article_id", "user_id"}
// 筛选条件
for _, format := range argFormat {
if p.Args[format] != nil {
fmt.Println(format, p.Args[format])
query = query.Where(goqu.Ex{fmt.Sprintf("web_images.%s", format): p.Args[format]})
}
}
// 筛选:提取文字
if p.Args["text"] != nil {
resp, err := models.ZincSearch(map[string]interface{}{
"query": map[string]interface{}{
"bool": map[string]interface{}{
"must": []map[string]interface{}{
{
"match_phrase": map[string]string{"text": p.Args["text"].(string)},
},
},
},
},
"_source": false,
"sort": []string{"_score"},
"size": 200000,
})
if err != nil {
fmt.Println("ZincSearch 获取图像列表失败", err)
return nil, err
}
var item []int
for _, hit := range resp.Hits.Hits {
num, _ := strconv.Atoi(hit.ID)
item = append(item, num)
}
if len(item) == 0 {
return map[string]interface{}{"list": []Image{}, "total": 0}, nil
}
query = query.Where(goqu.Ex{"web_images.id": goqu.Op{"in": item}})
total = len(item)
}
// 筛选:相似图像
if p.Args["similar"] != nil {
var item []int
for _, id := range models.GetSimilarImagesIdList(p.Args["similar"].(int), 200) {
item = append(item, int(id))
}
if len(item) == 0 {
return map[string]interface{}{"list": []Image{}, "total": 0}, nil
}
query = query.Where(goqu.Ex{"web_images.id": goqu.Op{"in": item}}).Select("web_images.id", goqu.L(
fmt.Sprintf("ROW_NUMBER() OVER(ORDER BY FIELD(%s, %s))", "web_images.id", regexp.MustCompile(`[\[\]]`).ReplaceAllString(strings.Join(strings.Fields(fmt.Sprint(item)), ", "), "")),
).As("row_num"))
total = len(item)
// 收集阅读行为
if p.Context.Value("user_id") != nil && p.Args["after"] == nil {
ctx := context.Background()
user_id := p.Context.Value("user_id").(int)
feedbacks := []client.Feedback{{
FeedbackType: "read",
UserId: fmt.Sprintf("%s", user_id),
ItemId: fmt.Sprintf("%s", p.Args["Similar"]),
Timestamp: time.Now().Format("2006-01-02 15:04:05"),
}}
if _, err := gorse.InsertFeedback(ctx, feedbacks); err != nil {
fmt.Println("写入阅读记录失败", err)
}
}
}
// 筛选:兴趣推荐
if p.Args["interest"] != nil {
fmt.Println("interest:", p.Args["interest"])
user_id := p.Args["interest"].(int)
fmt.Println("interest1:", user_id)
list, err := GetRecommend(user_id, []string{})
fmt.Println("interest2:", list, err)
if err != nil {
fmt.Println("GetRecommend 获取兴趣推荐失败", err)
return map[string]interface{}{"list": []Image{}, "total": 0}, nil
}
if len(list) == 0 {
return map[string]interface{}{"list": []Image{}, "total": 0}, nil
}
fmt.Println("Interest:", user_id, list)
query = query.Where(goqu.Ex{"web_images.id": goqu.Op{"in": list}}).Select("web_images.id", goqu.L(
fmt.Sprintf("ROW_NUMBER() OVER(ORDER BY FIELD(%s, %s))", "web_images.id", regexp.MustCompile(`[\[\]]`).ReplaceAllString(strings.Join(strings.Fields(fmt.Sprint(list)), ", "), "")),
).As("row_num"))
total = len(list)
}
// 筛选:时间段
applyTimeCondition := func(name string, str string) {
parts := strings.Split(str, "-")
query = query.Where(goqu.Ex{fmt.Sprintf("YEAR(%s)", name): parts[0]})
if len(parts) > 1 {
query = query.Where(goqu.Ex{fmt.Sprintf("MONTH(%s)", name): parts[1]})
}
if len(parts) > 2 {
query = query.Where(goqu.Ex{fmt.Sprintf("DAY(%s)", name): parts[2]})
}
}
// 数据库中筛选:创建时间段
if p.Args["create_time"] != nil {
applyTimeCondition("create_time", p.Args["create_time"].(string))
}
// 数据库中筛选:更新时间段
if p.Args["update_time"] != nil {
applyTimeCondition("update_time", p.Args["update_time"].(string))
}
// 数据库中筛选:按是否活动
if activity, ok := p.Args["activity"].(bool); ok {
query = query.Where(goqu.Ex{"web_images.activity": map[bool]string{true: "1", false: "0"}[activity]})
}
// 数据库中筛选:按游戏标签
if p.Args["tags"] != nil {
tags := strings.Split(strings.ReplaceAll(p.Args["tags"].(string), " ", ""), ",")
for _, tag := range tags {
query = query.Where(goqu.L("MATCH(web_images.tags) AGAINST (? IN NATURAL LANGUAGE MODE)", tag))
}
}
// 数据库中筛选:按游戏分类
if p.Args["images_desc"] != nil {
tags := strings.Split(strings.ReplaceAll(p.Args["images_desc"].(string), " ", ""), ",")
for _, tag := range tags {
query = query.Where(goqu.L("MATCH(web_images.images_desc) AGAINST (? IN NATURAL LANGUAGE MODE)", tag))
}
}
// 数据库中筛选:喜欢的截图
if p.Args["praise"] != nil {
query = query.Join(goqu.T("web_praise"), goqu.On(
goqu.I("web_images.id").Eq(goqu.I("web_praise.praise_id")),
goqu.I("web_praise.user_id").Eq(p.Args["praise"]),
goqu.I("web_praise.type").Eq(4),
))
}
var collect_params []goqu.Expression = []goqu.Expression{
goqu.I("web_images.id").Eq(goqu.I("web_collect.image_id")),
}
// 数据库中筛选:用户收藏的截图
if p.Args["collect"] != nil {
collect_params = append(collect_params, goqu.I("web_collect.user_id").Eq(p.Args["collect"]))
}
// 数据库中筛选:收藏夹中的截图
if p.Args["collect_id"] != nil {
collect_params = append(collect_params, goqu.I("web_collect.collect_id").Eq(p.Args["collect_id"]))
}
// 数据库中筛选:收藏夹中的截图
if p.Args["explorer_id"] != nil {
collect_params = append(collect_params, goqu.I("web_collect.explorer_id").Eq(p.Args["explorer_id"]))
}
if len(collect_params) > 1 {
query = query.Join(goqu.T("web_collect"), goqu.On(collect_params...))
}
var conditions []goqu.Expression = []goqu.Expression{
goqu.I("web_images.article_id").Eq(goqu.I("web_article.id")),
}
// 按游戏风格筛选图像
if p.Args["style"] != nil {
conditions = append(conditions, goqu.I("web_article.style").Eq(p.Args["style"]))
}
// 按游戏平台筛选图像
if p.Args["device"] != nil {
conditions = append(conditions, goqu.I("web_article.device").Eq(p.Args["device"]))
}
// 按游戏版式筛选图像
if p.Args["orientation"] != nil {
conditions = append(conditions, goqu.I("web_article.orientation").Eq(p.Args["orientation"]))
}
// 按游戏年份筛选图像
if p.Args["era"] != nil {
conditions = append(conditions, goqu.I("web_article.era").Eq(p.Args["era"]))
}
// 按游戏类型筛选图像(逗号分割且去除空格)
if p.Args["category_id"] != nil {
category_ids := strings.Split(strings.ReplaceAll(p.Args["category_id"].(string), " ", ""), ",")
conditions = append(conditions, goqu.I("web_article.category_id").In(category_ids))
}
// 按游戏标签筛选图像
if p.Args["article_tags"] != nil {
tags := strings.Split(strings.ReplaceAll(p.Args["article_tags"].(string), " ", ""), ", ")
for _, tag := range tags {
conditions = append(conditions, goqu.L("MATCH(web_article.tags) AGAINST (? IN NATURAL LANGUAGE MODE)", tag))
}
}
if len(conditions) > 1 {
query = query.Join(goqu.T("web_article"), goqu.On(conditions...))
}
// 数据库中筛选:按关注列表
if p.Args["follower"] != nil {
query = query.Join(goqu.T("web_fans"), goqu.On(
goqu.I("web_images.user_id").Eq(goqu.I("web_fans.blogger_id")),
goqu.I("web_fans.follower_id").Eq(p.Args["follower"]),
))
}
// 数据库中筛选: 按图像主色调颜色筛选
if p.Args["color"] != nil {
// hexToRGB 将十六进制颜色转换为 RGB
hexToRGB := func(hex string) (int, int, int, error) {
// 去掉 # 号
if strings.HasPrefix(hex, "#") {
hex = hex[1:]
}
// 检查是否是有效的十六进制颜色
if len(hex) != 6 {
return 0, 0, 0, fmt.Errorf("invalid hex color")
}
// 解析红色、绿色、蓝色通道的十六进制值
r, err := strconv.ParseInt(hex[:2], 16, 0)
if err != nil {
return 0, 0, 0, err
}
g, err := strconv.ParseInt(hex[2:4], 16, 0)
if err != nil {
return 0, 0, 0, err
}
b, err := strconv.ParseInt(hex[4:], 16, 0)
if err != nil {
return 0, 0, 0, err
}
return int(r), int(g), int(b), nil
}
// 逗号分割且去除空格
colors := strings.Split(strings.ReplaceAll(p.Args["color"].(string), " ", ""), ",")
for index, color := range colors {
var precision int = 10
if strings.Contains(color, ":") {
re := regexp.MustCompile(`^#([0-9a-fA-F]{6}):(\d+)$`)
matches := re.FindStringSubmatch(color)
num, err := strconv.Atoi(matches[2])
if err != nil {
fmt.Println("数字精度转换失败:", err)
return nil, err
}
color = "#" + matches[1]
precision = num
}
r, g, b, err := hexToRGB(color)
if err != nil {
fmt.Println("hexToRGB", index, err)
return nil, err
}
fmt.Println(color, r, g, b, precision)
query = query.Where(goqu.Or(
goqu.And(
goqu.L(fmt.Sprintf("web_images.color_%d_r", 0)).Gt(r-precision),
goqu.L(fmt.Sprintf("web_images.color_%d_r", 0)).Lt(r+precision),
goqu.L(fmt.Sprintf("web_images.color_%d_g", 0)).Gt(g-precision),
goqu.L(fmt.Sprintf("web_images.color_%d_g", 0)).Lt(g+precision),
goqu.L(fmt.Sprintf("web_images.color_%d_b", 0)).Gt(b-precision),
goqu.L(fmt.Sprintf("web_images.color_%d_b", 0)).Lt(b+precision),
),
goqu.And(
goqu.L(fmt.Sprintf("web_images.color_%d_r", 1)).Gt(r-precision),
goqu.L(fmt.Sprintf("web_images.color_%d_r", 1)).Lt(r+precision),
goqu.L(fmt.Sprintf("web_images.color_%d_g", 1)).Gt(g-precision),
goqu.L(fmt.Sprintf("web_images.color_%d_g", 1)).Lt(g+precision),
goqu.L(fmt.Sprintf("web_images.color_%d_b", 1)).Gt(b-precision),
goqu.L(fmt.Sprintf("web_images.color_%d_b", 1)).Lt(b+precision),
),
))
}
}
// 如果没有外部排序则使用指定排序(正则sort只能是字母数字下划线)
if p.Args["similar"] == nil && p.Args["interest"] == nil && p.Args["praise"] == nil {
// 如果查询了 total 字段
if existField(p.Info.FieldASTs[0].SelectionSet.Selections, "total") {
sql, _, _ := query.ToSQL()
sql = strings.Replace(sql, "SELECT *", "SELECT COUNT(*)", 1)
if err := db.Raw(sql).Scan(&total).Error; err != nil {
return nil, err
}
}
query = query.Select("web_images.id", goqu.L(fmt.Sprintf(
"ROW_NUMBER() OVER(ORDER BY web_images.%s %s)",
regexp.MustCompile(`[^a-zA-Z0-9_]`).ReplaceAllString(p.Args["sort"].(string), ""),
p.Args["order"].(string),
)).As("row_num"))
}
// 图像按点赞顺序排序 p.Args["sort"].(string) == "praise_time"
if p.Args["praise"] != nil {
query = query.Select("web_images.id", goqu.L(
fmt.Sprintf("ROW_NUMBER() OVER(ORDER BY web_praise.%s %s)", "id", p.Args["order"].(string)),
).As("row_num"))
}
// 取所有数据的前N条
sql, _, _ := query.Where(goqu.Ex{"article_category_top_id": 22}).ToSQL()
// 遊標截取篩選結果集的前N条
var cursor string
if p.Args["after"] != nil {
cursor = fmt.Sprintf(`WHERE row_num > (SELECT row_num FROM RankedArticles WHERE RankedArticles.id = %d)`, p.Args["after"].(int))
}
var limit int = 10
if p.Args["first"] != nil {
limit = p.Args["first"].(int)
} else if p.Args["last"] != nil {
limit = p.Args["last"].(int)
}
sql = fmt.Sprintf(`
WITH RankedArticles AS (%s)
SELECT web_images.* FROM web_images INNER JOIN(
SELECT id, row_num FROM RankedArticles %s
) AS LimitedRanked ON LimitedRanked.id = web_images.id
ORDER BY LimitedRanked.row_num ASC LIMIT %d
`, sql, cursor, limit)
fmt.Println(sql)
if err := db.Raw(sql).Scan(&images).Error; err != nil {
fmt.Println("获取图像列表失败", err)
return nil, err
}
var ids []int
for _, item := range images {
ids = append(ids, item.ID)
}
var find = db.Where("web_images.id IN ?", ids).Select("*", "CASE WHEN activity = '1' THEN TRUE ELSE FALSE END")
for _, item := range LoadItem(p.Info.FieldASTs[0].SelectionSet.Selections) {
find = find.Preload(item)
}
if len(ids) == 0 {
return map[string]interface{}{"list": []Image{}, "total": 0}, nil
}
orderClause := fmt.Sprintf("FIELD(id, %s)", regexp.MustCompile(`[\[\]]`).ReplaceAllString(strings.Join(strings.Fields(fmt.Sprint(ids)), ","), ""))
if err := find.Order(orderClause).Find(&images).Error; err != nil {
fmt.Println("获取图像列表失败", err)
return nil, err
}
return map[string]interface{}{
"list": images,
"total": total,
}, nil
},
}