mysql_article.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. package dao
  2. import (
  3. "context"
  4. "database/sql"
  5. "fmt"
  6. "strconv"
  7. "strings"
  8. "sync"
  9. "time"
  10. artmdl "go-common/app/interface/openplatform/article/model"
  11. xsql "go-common/library/database/sql"
  12. "go-common/library/log"
  13. xtime "go-common/library/time"
  14. "go-common/library/xstr"
  15. "go-common/library/sync/errgroup"
  16. )
  17. // Article gets article's meta and content.
  18. func (d *Dao) Article(c context.Context, aid int64) (res *artmdl.Article, err error) {
  19. res = &artmdl.Article{}
  20. if res.Meta, err = d.ArticleMeta(c, aid); err != nil {
  21. PromError("article:获取文章meta")
  22. return
  23. }
  24. if res.Meta == nil {
  25. res = nil
  26. return
  27. }
  28. if res.Content, err = d.ArticleContent(c, aid); err != nil {
  29. PromError("article:获取文章content")
  30. }
  31. if res.Keywords, err = d.ArticleKeywords(c, aid); err != nil {
  32. PromError("article:获取文章keywords")
  33. }
  34. res.Strong()
  35. return
  36. }
  37. // ArticleContent get article content
  38. func (d *Dao) ArticleContent(c context.Context, id int64) (res string, err error) {
  39. contentSQL := fmt.Sprintf(_articleContentSQL, d.hit(id))
  40. if err = d.articleDB.QueryRow(c, contentSQL, id).Scan(&res); err != nil {
  41. if err == sql.ErrNoRows {
  42. err = nil
  43. return
  44. }
  45. PromError("db:ArticleContent")
  46. log.Error("dao.ArticleContent(%s) error(%+v)", contentSQL, err)
  47. }
  48. return
  49. }
  50. // ArticleKeywords get article keywords
  51. func (d *Dao) ArticleKeywords(c context.Context, id int64) (res string, err error) {
  52. keywordsSQL := fmt.Sprintf(_articleKeywordsSQL, d.hit(id))
  53. if err = d.articleDB.QueryRow(c, keywordsSQL, id).Scan(&res); err != nil {
  54. if err == sql.ErrNoRows {
  55. err = nil
  56. return
  57. }
  58. PromError("db:ArticleKeywords")
  59. log.Error("dao.ArticleKeywords(%s) error(%+v)", keywordsSQL, err)
  60. }
  61. res = strings.Replace(res, "\001", ",", -1)
  62. return
  63. }
  64. // ArticleMeta get article meta
  65. func (d *Dao) ArticleMeta(c context.Context, id int64) (res *artmdl.Meta, err error) {
  66. var (
  67. row *xsql.Row
  68. imageURLs, originImageURLs string
  69. category = &artmdl.Category{}
  70. author = &artmdl.Author{}
  71. t int64
  72. ct time.Time
  73. )
  74. res = &artmdl.Meta{Media: &artmdl.Media{}}
  75. row = d.articleMetaStmt.QueryRow(c, id)
  76. if err = row.Scan(&res.ID, &category.ID, &res.Title, &res.Summary, &res.BannerURL, &res.TemplateID, &res.State, &author.Mid, &res.Reprint, &imageURLs, &t, &ct, &res.Attributes, &res.Words, &res.Dynamic, &originImageURLs, &res.Media.MediaID, &res.Media.Spoiler); err != nil {
  77. if err == sql.ErrNoRows {
  78. res = nil
  79. err = nil
  80. return
  81. }
  82. PromError("db:ArticleMeta")
  83. log.Error("dao.ArticleMeta.Scan error(%+v)", err)
  84. return
  85. }
  86. res.PublishTime = xtime.Time(t)
  87. res.Category = category
  88. res.Author = author
  89. res.Ctime = xtime.Time(ct.Unix())
  90. res.ImageURLs = strings.Split(imageURLs, ",")
  91. res.OriginImageURLs = strings.Split(originImageURLs, ",")
  92. res.BannerURL = artmdl.CompleteURL(res.BannerURL)
  93. res.ImageURLs = artmdl.CompleteURLs(res.ImageURLs)
  94. res.OriginImageURLs = artmdl.CompleteURLs(res.OriginImageURLs)
  95. res.Strong()
  96. return
  97. }
  98. // ArticleMetas get article metats
  99. func (d *Dao) ArticleMetas(c context.Context, aids []int64) (res map[int64]*artmdl.Meta, err error) {
  100. var (
  101. group, errCtx = errgroup.WithContext(c)
  102. mutex = &sync.Mutex{}
  103. )
  104. if len(aids) == 0 {
  105. return
  106. }
  107. res = make(map[int64]*artmdl.Meta)
  108. keysLen := len(aids)
  109. for i := 0; i < keysLen; i += _mysqlBulkSize {
  110. var keys []int64
  111. if (i + _mysqlBulkSize) > keysLen {
  112. keys = aids[i:]
  113. } else {
  114. keys = aids[i : i+_mysqlBulkSize]
  115. }
  116. group.Go(func() (err error) {
  117. var rows *xsql.Rows
  118. metasSQL := fmt.Sprintf(_articlesMetaSQL, xstr.JoinInts(keys))
  119. if rows, err = d.articleDB.Query(errCtx, metasSQL); err != nil {
  120. PromError("db:ArticleMetas")
  121. return
  122. }
  123. defer rows.Close()
  124. for rows.Next() {
  125. var (
  126. imageURLs, originImageURLs string
  127. t int64
  128. ct time.Time
  129. a = &artmdl.Meta{Category: &artmdl.Category{}, Author: &artmdl.Author{}, Media: &artmdl.Media{}}
  130. )
  131. err = rows.Scan(&a.ID, &a.Category.ID, &a.Title, &a.Summary, &a.BannerURL, &a.TemplateID, &a.State, &a.Author.Mid, &a.Reprint, &imageURLs, &t, &ct, &a.Attributes, &a.Words, &a.Dynamic, &originImageURLs, &a.Media.MediaID, &a.Media.Spoiler)
  132. if err != nil {
  133. return
  134. }
  135. a.ImageURLs = strings.Split(imageURLs, ",")
  136. a.OriginImageURLs = strings.Split(originImageURLs, ",")
  137. a.PublishTime = xtime.Time(t)
  138. a.Ctime = xtime.Time(ct.Unix())
  139. a.BannerURL = artmdl.CompleteURL(a.BannerURL)
  140. a.ImageURLs = artmdl.CompleteURLs(a.ImageURLs)
  141. a.OriginImageURLs = artmdl.CompleteURLs(a.OriginImageURLs)
  142. a.Strong()
  143. mutex.Lock()
  144. res[a.ID] = a
  145. mutex.Unlock()
  146. }
  147. err = rows.Err()
  148. return err
  149. })
  150. }
  151. if err = group.Wait(); err != nil {
  152. PromError("db:ArticleMetas")
  153. log.Error("dao.ArticleMetas error(%+v)", err)
  154. return
  155. }
  156. if len(res) == 0 {
  157. res = nil
  158. }
  159. return
  160. }
  161. // AllArticleMeta 所有状态/删除 的文章
  162. func (d *Dao) AllArticleMeta(c context.Context, id int64) (res *artmdl.Meta, err error) {
  163. var (
  164. row *xsql.Row
  165. imageURLs, originImageURLs string
  166. category = &artmdl.Category{}
  167. author = &artmdl.Author{}
  168. t int64
  169. ct time.Time
  170. )
  171. res = &artmdl.Meta{Media: &artmdl.Media{}}
  172. row = d.allArticleMetaStmt.QueryRow(c, id)
  173. if err = row.Scan(&res.ID, &category.ID, &res.Title, &res.Summary, &res.BannerURL, &res.TemplateID, &res.State, &author.Mid, &res.Reprint, &imageURLs, &t, &ct, &res.Attributes, &res.Words, &res.Dynamic, &originImageURLs, &res.Media.MediaID, &res.Media.Spoiler); err != nil {
  174. if err == sql.ErrNoRows {
  175. res = nil
  176. err = nil
  177. return
  178. }
  179. PromError("db:AllArticleMeta")
  180. log.Error("row.AllArticleMeta.Scan error(%+v)", err)
  181. return
  182. }
  183. res.PublishTime = xtime.Time(t)
  184. res.Category = category
  185. res.Author = author
  186. res.Ctime = xtime.Time(ct.Unix())
  187. res.ImageURLs = strings.Split(imageURLs, ",")
  188. res.OriginImageURLs = strings.Split(originImageURLs, ",")
  189. res.BannerURL = artmdl.CompleteURL(res.BannerURL)
  190. res.ImageURLs = artmdl.CompleteURLs(res.ImageURLs)
  191. res.OriginImageURLs = artmdl.CompleteURLs(res.OriginImageURLs)
  192. res.Strong()
  193. return
  194. }
  195. // UpperArticleCount get upper article count
  196. func (d *Dao) UpperArticleCount(c context.Context, mid int64) (res int, err error) {
  197. row := d.articleUpperCountStmt.QueryRow(c, mid)
  198. if err = row.Scan(&res); err != nil {
  199. if err == sql.ErrNoRows {
  200. err = nil
  201. return
  202. }
  203. PromError("db:UpperArticleCount")
  204. log.Error("dao.UpperArticleCount error(%+v)", err)
  205. }
  206. return
  207. }
  208. // ArticleRemainCount returns the number that user could be use to posting new articles.
  209. func (d *Dao) ArticleRemainCount(c context.Context, mid int64) (count int, err error) {
  210. beginTime := time.Now().Format("2006-01-02") + " 00:00:00"
  211. if err = d.articleUpCntTodayStmt.QueryRow(c, mid, beginTime).Scan(&count); err != nil {
  212. if err == sql.ErrNoRows {
  213. err = nil
  214. return
  215. }
  216. PromError("db:ArticleRemainCount")
  217. log.Error("dao.ArticleRemainCount(%d,%s) error(%+v)", mid, beginTime, err)
  218. }
  219. return
  220. }
  221. // TagArticles .
  222. func (d *Dao) TagArticles(c context.Context, tags []int64) (aids []int64, err error) {
  223. var (
  224. rows *xsql.Rows
  225. query string
  226. tmps = make(map[int64]bool)
  227. )
  228. query = fmt.Sprintf(_tagArticlesSQL, xstr.JoinInts(tags))
  229. if rows, err = d.articleDB.Query(c, query); err != nil {
  230. PromError("dao:TagArticles")
  231. log.Error("dao.TagArticles(%s) error(%+v)", query, err)
  232. return
  233. }
  234. defer rows.Close()
  235. for rows.Next() {
  236. var (
  237. tid int64
  238. oid string
  239. logDate xtime.Time
  240. ts []int64
  241. aid int64
  242. now = time.Now()
  243. )
  244. rows.Scan(&tid, &oid, &logDate)
  245. if now.Sub(logDate.Time()) > time.Hour*60 {
  246. continue
  247. }
  248. ids := strings.Split(oid, ",")
  249. for _, id := range ids {
  250. if aid, err = strconv.ParseInt(id, 10, 64); err != nil {
  251. log.Error("dao.TagArticles.ParseInt(%s) error(%+v)", id, err)
  252. return
  253. }
  254. if !tmps[aid] {
  255. aids = append(aids, aid)
  256. tmps[aid] = true
  257. }
  258. ts = append(ts, aid)
  259. }
  260. d.AddCacheAidsByTag(c, tid, &artmdl.TagArts{Tid: tid, Aids: ts})
  261. }
  262. return
  263. }
  264. // MediaArticle .
  265. func (d *Dao) MediaArticle(c context.Context, mediaID int64, mid int64) (id int64, err error) {
  266. var rows *xsql.Rows
  267. if rows, err = d.articleDB.Query(c, _mediaArticleSQL, mid, mediaID); err != nil {
  268. log.Error("dao.MediaArticle.Query error(%v)", err)
  269. return
  270. }
  271. defer rows.Close()
  272. for rows.Next() {
  273. if err = rows.Scan(&id); err != nil {
  274. log.Error("dao.MediaArticle.Scan error(%v)", err)
  275. return
  276. }
  277. if id > 0 {
  278. return
  279. }
  280. }
  281. return
  282. }
  283. // MediaIDByID .
  284. func (d *Dao) MediaIDByID(c context.Context, aid int64) (id int64, err error) {
  285. row := d.articleDB.QueryRow(c, _mediaByIDSQL, aid)
  286. if err = row.Scan(&id); err != nil {
  287. log.Error("dao.MediaIDByID.Scan error(%v)", err)
  288. }
  289. return
  290. }