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.

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