GraphQL API and utilities for the rpdata project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

225 lines
4.2 KiB

  1. package mongodb
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/globalsign/mgo/bson"
  6. "time"
  7. "git.aiterp.net/rpdata/api/internal/config"
  8. "git.aiterp.net/rpdata/api/repositories"
  9. "github.com/globalsign/mgo"
  10. )
  11. type MongoDB struct {
  12. session *mgo.Session
  13. changes repositories.ChangeRepository
  14. channels *channelRepository
  15. characters repositories.CharacterRepository
  16. tags repositories.TagRepository
  17. logs *logRepository
  18. posts *postRepository
  19. files *fileRepository
  20. stories repositories.StoryRepository
  21. chapters repositories.ChapterRepository
  22. comments repositories.CommentRepository
  23. }
  24. func (m *MongoDB) Changes() repositories.ChangeRepository {
  25. return m.changes
  26. }
  27. func (m *MongoDB) Characters() repositories.CharacterRepository {
  28. return m.characters
  29. }
  30. func (m *MongoDB) Tags() repositories.TagRepository {
  31. return m.tags
  32. }
  33. func (m *MongoDB) Logs() repositories.LogRepository {
  34. return m.logs
  35. }
  36. func (m *MongoDB) Posts() repositories.PostRepository {
  37. return m.posts
  38. }
  39. func (m *MongoDB) Channels() repositories.ChannelRepository {
  40. return m.channels
  41. }
  42. func (m *MongoDB) Files() repositories.FileRepository {
  43. return m.files
  44. }
  45. func (m *MongoDB) Stories() repositories.StoryRepository {
  46. return m.stories
  47. }
  48. func (m *MongoDB) Chapters() repositories.ChapterRepository {
  49. return m.chapters
  50. }
  51. func (m *MongoDB) Comments() repositories.CommentRepository {
  52. return m.comments
  53. }
  54. func (m *MongoDB) Close(ctx context.Context) error {
  55. m.session.Close()
  56. return nil
  57. }
  58. // Init initializes the mongodb database
  59. func Init(cfg config.Database) (*MongoDB, error) {
  60. port := cfg.Port
  61. if port <= 0 {
  62. port = 27017
  63. }
  64. session, err := mgo.DialWithInfo(&mgo.DialInfo{
  65. Addrs: []string{fmt.Sprintf("%s:%d", cfg.Host, port)},
  66. Timeout: 30 * time.Second,
  67. Database: cfg.Db,
  68. Username: cfg.Username,
  69. Password: cfg.Password,
  70. Mechanism: cfg.Mechanism,
  71. Source: cfg.Db,
  72. })
  73. if err != nil {
  74. return nil, err
  75. }
  76. db := session.DB(cfg.Db)
  77. characters, err := newCharacterRepository(db)
  78. if err != nil {
  79. session.Close()
  80. return nil, err
  81. }
  82. channels, err := newChannelRepository(db)
  83. if err != nil {
  84. session.Close()
  85. return nil, err
  86. }
  87. changes, err := newChangeRepository(db)
  88. if err != nil {
  89. session.Close()
  90. return nil, err
  91. }
  92. logs, err := newLogRepository(db)
  93. if err != nil {
  94. session.Close()
  95. return nil, err
  96. }
  97. posts, err := newPostRepository(db)
  98. if err != nil {
  99. session.Close()
  100. return nil, err
  101. }
  102. files, err := newFileRepository(db)
  103. if err != nil {
  104. session.Close()
  105. return nil, err
  106. }
  107. stories, err := newStoryRepository(db)
  108. if err != nil {
  109. session.Close()
  110. return nil, err
  111. }
  112. chapters, err := newChapterRepository(db)
  113. if err != nil {
  114. session.Close()
  115. return nil, err
  116. }
  117. comments, err := newCommentRepository(db)
  118. if err != nil {
  119. session.Close()
  120. return nil, err
  121. }
  122. go posts.fixPositions(logs)
  123. return &MongoDB{
  124. session: session,
  125. changes: changes,
  126. characters: characters,
  127. channels: channels,
  128. tags: newTagRepository(db),
  129. stories: stories,
  130. chapters: chapters,
  131. comments: comments,
  132. logs: logs,
  133. posts: posts,
  134. files: files,
  135. }, nil
  136. }
  137. type counter struct {
  138. coll *mgo.Collection
  139. category string
  140. name string
  141. }
  142. func newCounter(db *mgo.Database, category, name string) *counter {
  143. return &counter{
  144. coll: db.C("core.counters"),
  145. category: category,
  146. name: name,
  147. }
  148. }
  149. func (c *counter) WithName(name string) *counter {
  150. return &counter{
  151. coll: c.coll,
  152. category: c.category,
  153. name: name,
  154. }
  155. }
  156. func (c *counter) WithCategory(category string) *counter {
  157. return &counter{
  158. coll: c.coll,
  159. category: category,
  160. name: c.name,
  161. }
  162. }
  163. func (c *counter) With(category, name string) *counter {
  164. return &counter{
  165. coll: c.coll,
  166. category: category,
  167. name: name,
  168. }
  169. }
  170. func (c *counter) Increment(amount int) (int, error) {
  171. type counterDoc struct {
  172. ID string `bson:"_id"`
  173. Value int `bson:"value"`
  174. }
  175. id := c.category + "." + c.name
  176. doc := counterDoc{}
  177. _, err := c.coll.Find(bson.M{"_id": id}).Apply(mgo.Change{
  178. Update: bson.M{"$inc": bson.M{"value": amount}},
  179. Upsert: true,
  180. ReturnNew: true,
  181. }, &doc)
  182. if err != nil {
  183. return -1, err
  184. }
  185. return doc.Value, nil
  186. }