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.

55 lines
1.2 KiB

  1. package counter
  2. import (
  3. "git.aiterp.net/rpdata/api/internal/store"
  4. "github.com/globalsign/mgo"
  5. "github.com/globalsign/mgo/bson"
  6. )
  7. var collection *mgo.Collection
  8. type counter struct {
  9. ID string `bson:"_id"`
  10. Value int `bson:"value"`
  11. }
  12. // Next gets the next value of a counter, or an error if it hasn't.
  13. func Next(category, name string) (int, error) {
  14. id := category + "." + name
  15. doc := counter{}
  16. _, err := collection.Find(bson.M{"_id": id}).Apply(mgo.Change{
  17. Update: bson.M{"$inc": bson.M{"value": 1}},
  18. Upsert: true,
  19. ReturnNew: true,
  20. }, &doc)
  21. if err != nil {
  22. return -1, err
  23. }
  24. return doc.Value, nil
  25. }
  26. // NextMany gets the next value of a counter, or an error if it hasn't, and increments by a specified value.
  27. // Any value `returned` to `returned+(increment-1)` should then be safe to use.
  28. func NextMany(category, name string, increment int) (int, error) {
  29. id := category + "." + name
  30. doc := counter{}
  31. _, err := collection.Find(bson.M{"_id": id}).Apply(mgo.Change{
  32. Update: bson.M{"$inc": bson.M{"value": increment}},
  33. Upsert: true,
  34. ReturnNew: true,
  35. }, &doc)
  36. if err != nil {
  37. return -1, err
  38. }
  39. return doc.Value, nil
  40. }
  41. func init() {
  42. store.HandleInit(func(db *mgo.Database) {
  43. collection = db.C("core.counters")
  44. })
  45. }