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.

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