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.

165 lines
3.0 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. characters repositories.CharacterRepository
  15. tags repositories.TagRepository
  16. logs *logRepository
  17. posts *postRepository
  18. }
  19. func (m *MongoDB) Changes() repositories.ChangeRepository {
  20. return m.changes
  21. }
  22. func (m *MongoDB) Characters() repositories.CharacterRepository {
  23. return m.characters
  24. }
  25. func (m *MongoDB) Tags() repositories.TagRepository {
  26. return m.tags
  27. }
  28. func (m *MongoDB) Logs() repositories.LogRepository {
  29. return m.logs
  30. }
  31. func (m *MongoDB) Posts() repositories.PostRepository {
  32. return m.posts
  33. }
  34. func (m *MongoDB) Close(ctx context.Context) error {
  35. m.session.Close()
  36. return nil
  37. }
  38. // Init initializes the mongodb database
  39. func Init(cfg config.Database) (*MongoDB, error) {
  40. port := cfg.Port
  41. if port <= 0 {
  42. port = 27017
  43. }
  44. session, err := mgo.DialWithInfo(&mgo.DialInfo{
  45. Addrs: []string{fmt.Sprintf("%s:%d", cfg.Host, port)},
  46. Timeout: 30 * time.Second,
  47. Database: cfg.Db,
  48. Username: cfg.Username,
  49. Password: cfg.Password,
  50. Mechanism: cfg.Mechanism,
  51. Source: cfg.Db,
  52. })
  53. if err != nil {
  54. return nil, err
  55. }
  56. db := session.DB(cfg.Db)
  57. characters, err := newCharacterRepository(db)
  58. if err != nil {
  59. session.Close()
  60. return nil, err
  61. }
  62. changes, err := newChangeRepository(db)
  63. if err != nil {
  64. session.Close()
  65. return nil, err
  66. }
  67. logs, err := newLogRepository(db)
  68. if err != nil {
  69. session.Close()
  70. return nil, err
  71. }
  72. posts, err := newPostRepository(db)
  73. if err != nil {
  74. session.Close()
  75. return nil, err
  76. }
  77. go posts.fixPositions(logs)
  78. return &MongoDB{
  79. session: session,
  80. changes: changes,
  81. characters: characters,
  82. tags: newTagRepository(db),
  83. logs: logs,
  84. posts: posts,
  85. }, nil
  86. }
  87. type counter struct {
  88. coll *mgo.Collection
  89. category string
  90. name string
  91. }
  92. func newCounter(db *mgo.Database, category, name string) *counter {
  93. return &counter{
  94. coll: db.C("core.counters"),
  95. category: category,
  96. name: name,
  97. }
  98. }
  99. func (c *counter) WithName(name string) *counter {
  100. return &counter{
  101. coll: c.coll,
  102. category: c.category,
  103. name: name,
  104. }
  105. }
  106. func (c *counter) WithCategory(category string) *counter {
  107. return &counter{
  108. coll: c.coll,
  109. category: category,
  110. name: c.name,
  111. }
  112. }
  113. func (c *counter) With(category, name string) *counter {
  114. return &counter{
  115. coll: c.coll,
  116. category: category,
  117. name: name,
  118. }
  119. }
  120. func (c *counter) Increment(amount int) (int, error) {
  121. type counterDoc struct {
  122. ID string `bson:"_id"`
  123. Value int `bson:"value"`
  124. }
  125. id := c.category + "." + c.name
  126. doc := counterDoc{}
  127. _, err := c.coll.Find(bson.M{"_id": id}).Apply(mgo.Change{
  128. Update: bson.M{"$inc": bson.M{"value": amount}},
  129. Upsert: true,
  130. ReturnNew: true,
  131. }, &doc)
  132. if err != nil {
  133. return -1, err
  134. }
  135. return doc.Value, nil
  136. }