PageRenderTime 38ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/db/mongodb/mongodb.go

https://bitbucket.org/cloudedgemicroserviceteam/user
Go | 465 lines | 397 code | 36 blank | 32 comment | 84 complexity | 5ec7b5a59e885b3416574cfa71785ee8 MD5 | raw file
Possible License(s): Apache-2.0
  1. package mongodb
  2. import (
  3. "errors"
  4. "flag"
  5. "fmt"
  6. "net/url"
  7. "os"
  8. "time"
  9. "bitbucket.org/cloudedgemicroserviceteam/user/users"
  10. "gopkg.in/mgo.v2"
  11. "gopkg.in/mgo.v2/bson"
  12. )
  13. var (
  14. name string
  15. password string
  16. host string
  17. db = "users"
  18. //ErrInvalidHexID represents a entity id that is not a valid bson ObjectID
  19. ErrInvalidHexID = errors.New("Invalid Id Hex")
  20. )
  21. func init() {
  22. flag.StringVar(&name, "mongo-user", os.Getenv("MONGO_USER"), "Mongo user")
  23. flag.StringVar(&password, "mongo-password", os.Getenv("MONGO_PASS"), "Mongo password")
  24. flag.StringVar(&host, "mongo-host", os.Getenv("MONGO_HOST"), "Mongo host")
  25. }
  26. // Mongo meets the Database interface requirements
  27. type Mongo struct {
  28. //Session is a MongoDB Session
  29. Session *mgo.Session
  30. }
  31. // Init MongoDB
  32. func (m *Mongo) Init() error {
  33. u := getURL()
  34. var err error
  35. m.Session, err = mgo.DialWithTimeout(u.String(), time.Duration(5)*time.Second)
  36. if err != nil {
  37. return err
  38. }
  39. return m.EnsureIndexes()
  40. }
  41. // MongoUser is a wrapper for the users
  42. type MongoUser struct {
  43. users.User `bson:",inline"`
  44. ID bson.ObjectId `bson:"_id"`
  45. AddressIDs []bson.ObjectId `bson:"addresses"`
  46. CardIDs []bson.ObjectId `bson:"cards"`
  47. }
  48. // New Returns a new MongoUser
  49. func New() MongoUser {
  50. u := users.New()
  51. return MongoUser{
  52. User: u,
  53. AddressIDs: make([]bson.ObjectId, 0),
  54. CardIDs: make([]bson.ObjectId, 0),
  55. }
  56. }
  57. // AddUserIDs adds userID as string to user
  58. func (mu *MongoUser) AddUserIDs() {
  59. if mu.User.Addresses == nil {
  60. mu.User.Addresses = make([]users.Address, 0)
  61. }
  62. for _, id := range mu.AddressIDs {
  63. mu.User.Addresses = append(mu.User.Addresses, users.Address{
  64. ID: id.Hex(),
  65. })
  66. }
  67. if mu.User.Cards == nil {
  68. mu.User.Cards = make([]users.Card, 0)
  69. }
  70. for _, id := range mu.CardIDs {
  71. mu.User.Cards = append(mu.User.Cards, users.Card{ID: id.Hex()})
  72. }
  73. mu.User.UserID = mu.ID.Hex()
  74. }
  75. // MongoAddress is a wrapper for Address
  76. type MongoAddress struct {
  77. users.Address `bson:",inline"`
  78. ID bson.ObjectId `bson:"_id"`
  79. }
  80. // AddID ObjectID as string
  81. func (m *MongoAddress) AddID() {
  82. m.Address.ID = m.ID.Hex()
  83. }
  84. // MongoCard is a wrapper for Card
  85. type MongoCard struct {
  86. users.Card `bson:",inline"`
  87. ID bson.ObjectId `bson:"_id"`
  88. }
  89. // AddID ObjectID as string
  90. func (m *MongoCard) AddID() {
  91. m.Card.ID = m.ID.Hex()
  92. }
  93. // CreateUser Insert user to MongoDB, including connected addresses and cards, update passed in user with Ids
  94. func (m *Mongo) CreateUser(u *users.User) error {
  95. s := m.Session.Copy()
  96. defer s.Close()
  97. id := bson.NewObjectId()
  98. mu := New()
  99. mu.User = *u
  100. mu.ID = id
  101. var carderr error
  102. var addrerr error
  103. mu.CardIDs, carderr = m.createCards(u.Cards)
  104. mu.AddressIDs, addrerr = m.createAddresses(u.Addresses)
  105. c := s.DB("").C("customers")
  106. _, err := c.UpsertId(mu.ID, mu)
  107. if err != nil {
  108. // Gonna clean up if we can, ignore error
  109. // because the user save error takes precedence.
  110. m.cleanAttributes(mu)
  111. return err
  112. }
  113. mu.User.UserID = mu.ID.Hex()
  114. // Cheap err for attributes
  115. if carderr != nil || addrerr != nil {
  116. return fmt.Errorf("%v %v", carderr, addrerr)
  117. }
  118. *u = mu.User
  119. return nil
  120. }
  121. func (m *Mongo) createCards(cs []users.Card) ([]bson.ObjectId, error) {
  122. s := m.Session.Copy()
  123. defer s.Close()
  124. ids := make([]bson.ObjectId, 0)
  125. defer s.Close()
  126. for k, ca := range cs {
  127. id := bson.NewObjectId()
  128. mc := MongoCard{Card: ca, ID: id}
  129. c := s.DB("").C("cards")
  130. _, err := c.UpsertId(mc.ID, mc)
  131. if err != nil {
  132. return ids, err
  133. }
  134. ids = append(ids, id)
  135. cs[k].ID = id.Hex()
  136. }
  137. return ids, nil
  138. }
  139. func (m *Mongo) createAddresses(as []users.Address) ([]bson.ObjectId, error) {
  140. ids := make([]bson.ObjectId, 0)
  141. s := m.Session.Copy()
  142. defer s.Close()
  143. for k, a := range as {
  144. id := bson.NewObjectId()
  145. ma := MongoAddress{Address: a, ID: id}
  146. c := s.DB("").C("addresses")
  147. _, err := c.UpsertId(ma.ID, ma)
  148. if err != nil {
  149. return ids, err
  150. }
  151. ids = append(ids, id)
  152. as[k].ID = id.Hex()
  153. }
  154. return ids, nil
  155. }
  156. func (m *Mongo) cleanAttributes(mu MongoUser) error {
  157. s := m.Session.Copy()
  158. defer s.Close()
  159. c := s.DB("").C("addresses")
  160. _, err := c.RemoveAll(bson.M{"_id": bson.M{"$in": mu.AddressIDs}})
  161. c = s.DB("").C("cards")
  162. _, err = c.RemoveAll(bson.M{"_id": bson.M{"$in": mu.CardIDs}})
  163. return err
  164. }
  165. func (m *Mongo) appendAttributeId(attr string, id bson.ObjectId, userid string) error {
  166. s := m.Session.Copy()
  167. defer s.Close()
  168. c := s.DB("").C("customers")
  169. return c.Update(bson.M{"_id": bson.ObjectIdHex(userid)},
  170. bson.M{"$addToSet": bson.M{attr: id}})
  171. }
  172. func (m *Mongo) removeAttributeId(attr string, id bson.ObjectId, userid string) error {
  173. s := m.Session.Copy()
  174. defer s.Close()
  175. c := s.DB("").C("customers")
  176. return c.Update(bson.M{"_id": bson.ObjectIdHex(userid)},
  177. bson.M{"$pull": bson.M{attr: id}})
  178. }
  179. // GetUserByName Get user by their name
  180. func (m *Mongo) GetUserByName(name string) (users.User, error) {
  181. s := m.Session.Copy()
  182. defer s.Close()
  183. c := s.DB("").C("customers")
  184. mu := New()
  185. err := c.Find(bson.M{"username": name}).One(&mu)
  186. mu.AddUserIDs()
  187. return mu.User, err
  188. }
  189. // GetUser Get user by their object id
  190. func (m *Mongo) GetUser(id string) (users.User, error) {
  191. s := m.Session.Copy()
  192. defer s.Close()
  193. if !bson.IsObjectIdHex(id) {
  194. return users.New(), errors.New("Invalid Id Hex")
  195. }
  196. c := s.DB("").C("customers")
  197. mu := New()
  198. err := c.FindId(bson.ObjectIdHex(id)).One(&mu)
  199. mu.AddUserIDs()
  200. return mu.User, err
  201. }
  202. // GetUsers Get all users
  203. func (m *Mongo) GetUsers() ([]users.User, error) {
  204. // TODO: add paginations
  205. s := m.Session.Copy()
  206. defer s.Close()
  207. c := s.DB("").C("customers")
  208. var mus []MongoUser
  209. err := c.Find(nil).All(&mus)
  210. us := make([]users.User, 0)
  211. for _, mu := range mus {
  212. mu.AddUserIDs()
  213. us = append(us, mu.User)
  214. }
  215. return us, err
  216. }
  217. // GetUserAttributes given a user, load all cards and addresses connected to that user
  218. func (m *Mongo) GetUserAttributes(u *users.User) error {
  219. s := m.Session.Copy()
  220. defer s.Close()
  221. ids := make([]bson.ObjectId, 0)
  222. for _, a := range u.Addresses {
  223. if !bson.IsObjectIdHex(a.ID) {
  224. return ErrInvalidHexID
  225. }
  226. ids = append(ids, bson.ObjectIdHex(a.ID))
  227. }
  228. var ma []MongoAddress
  229. c := s.DB("").C("addresses")
  230. err := c.Find(bson.M{"_id": bson.M{"$in": ids}}).All(&ma)
  231. if err != nil {
  232. return err
  233. }
  234. na := make([]users.Address, 0)
  235. for _, a := range ma {
  236. a.Address.ID = a.ID.Hex()
  237. na = append(na, a.Address)
  238. }
  239. u.Addresses = na
  240. ids = make([]bson.ObjectId, 0)
  241. for _, c := range u.Cards {
  242. if !bson.IsObjectIdHex(c.ID) {
  243. return ErrInvalidHexID
  244. }
  245. ids = append(ids, bson.ObjectIdHex(c.ID))
  246. }
  247. var mc []MongoCard
  248. c = s.DB("").C("cards")
  249. err = c.Find(bson.M{"_id": bson.M{"$in": ids}}).All(&mc)
  250. if err != nil {
  251. return err
  252. }
  253. nc := make([]users.Card, 0)
  254. for _, ca := range mc {
  255. ca.Card.ID = ca.ID.Hex()
  256. nc = append(nc, ca.Card)
  257. }
  258. u.Cards = nc
  259. return nil
  260. }
  261. // GetCard Gets card by objects Id
  262. func (m *Mongo) GetCard(id string) (users.Card, error) {
  263. s := m.Session.Copy()
  264. defer s.Close()
  265. if !bson.IsObjectIdHex(id) {
  266. return users.Card{}, errors.New("Invalid Id Hex")
  267. }
  268. c := s.DB("").C("cards")
  269. mc := MongoCard{}
  270. err := c.FindId(bson.ObjectIdHex(id)).One(&mc)
  271. mc.AddID()
  272. return mc.Card, err
  273. }
  274. // GetCards Gets all cards
  275. func (m *Mongo) GetCards() ([]users.Card, error) {
  276. // TODO: add pagination
  277. s := m.Session.Copy()
  278. defer s.Close()
  279. c := s.DB("").C("cards")
  280. var mcs []MongoCard
  281. err := c.Find(nil).All(&mcs)
  282. cs := make([]users.Card, 0)
  283. for _, mc := range mcs {
  284. mc.AddID()
  285. cs = append(cs, mc.Card)
  286. }
  287. return cs, err
  288. }
  289. // CreateCard adds card to MongoDB
  290. func (m *Mongo) CreateCard(ca *users.Card, userid string) error {
  291. if userid != "" && !bson.IsObjectIdHex(userid) {
  292. return errors.New("Invalid Id Hex")
  293. }
  294. s := m.Session.Copy()
  295. defer s.Close()
  296. c := s.DB("").C("cards")
  297. id := bson.NewObjectId()
  298. mc := MongoCard{Card: *ca, ID: id}
  299. _, err := c.UpsertId(mc.ID, mc)
  300. if err != nil {
  301. return err
  302. }
  303. // Address for anonymous user
  304. if userid != "" {
  305. err = m.appendAttributeId("cards", mc.ID, userid)
  306. if err != nil {
  307. return err
  308. }
  309. }
  310. mc.AddID()
  311. *ca = mc.Card
  312. return err
  313. }
  314. // GetAddress Gets an address by object Id
  315. func (m *Mongo) GetAddress(id string) (users.Address, error) {
  316. s := m.Session.Copy()
  317. defer s.Close()
  318. if !bson.IsObjectIdHex(id) {
  319. return users.Address{}, errors.New("Invalid Id Hex")
  320. }
  321. c := s.DB("").C("addresses")
  322. ma := MongoAddress{}
  323. err := c.FindId(bson.ObjectIdHex(id)).One(&ma)
  324. ma.AddID()
  325. return ma.Address, err
  326. }
  327. // GetAddresses gets all addresses
  328. func (m *Mongo) GetAddresses() ([]users.Address, error) {
  329. // TODO: add pagination
  330. s := m.Session.Copy()
  331. defer s.Close()
  332. c := s.DB("").C("addresses")
  333. var mas []MongoAddress
  334. err := c.Find(nil).All(&mas)
  335. as := make([]users.Address, 0)
  336. for _, ma := range mas {
  337. ma.AddID()
  338. as = append(as, ma.Address)
  339. }
  340. return as, err
  341. }
  342. // CreateAddress Inserts Address into MongoDB
  343. func (m *Mongo) CreateAddress(a *users.Address, userid string) error {
  344. if userid != "" && !bson.IsObjectIdHex(userid) {
  345. return errors.New("Invalid Id Hex")
  346. }
  347. s := m.Session.Copy()
  348. defer s.Close()
  349. c := s.DB("").C("addresses")
  350. id := bson.NewObjectId()
  351. ma := MongoAddress{Address: *a, ID: id}
  352. _, err := c.UpsertId(ma.ID, ma)
  353. if err != nil {
  354. return err
  355. }
  356. // Address for anonymous user
  357. if userid != "" {
  358. err = m.appendAttributeId("addresses", ma.ID, userid)
  359. if err != nil {
  360. return err
  361. }
  362. }
  363. ma.AddID()
  364. *a = ma.Address
  365. return err
  366. }
  367. // CreateAddress Inserts Address into MongoDB
  368. func (m *Mongo) Delete(entity, id string) error {
  369. if !bson.IsObjectIdHex(id) {
  370. return errors.New("Invalid Id Hex")
  371. }
  372. s := m.Session.Copy()
  373. defer s.Close()
  374. c := s.DB("").C(entity)
  375. if entity == "customers" {
  376. u, err := m.GetUser(id)
  377. if err != nil {
  378. return err
  379. }
  380. aids := make([]bson.ObjectId, 0)
  381. for _, a := range u.Addresses {
  382. aids = append(aids, bson.ObjectIdHex(a.ID))
  383. }
  384. cids := make([]bson.ObjectId, 0)
  385. for _, c := range u.Cards {
  386. cids = append(cids, bson.ObjectIdHex(c.ID))
  387. }
  388. ac := s.DB("").C("addresses")
  389. ac.RemoveAll(bson.M{"_id": bson.M{"$in": aids}})
  390. cc := s.DB("").C("cards")
  391. cc.RemoveAll(bson.M{"_id": bson.M{"$in": cids}})
  392. } else {
  393. c := s.DB("").C("customers")
  394. c.UpdateAll(bson.M{},
  395. bson.M{"$pull": bson.M{entity: bson.ObjectIdHex(id)}})
  396. }
  397. return c.Remove(bson.M{"_id": bson.ObjectIdHex(id)})
  398. }
  399. func getURL() url.URL {
  400. ur := url.URL{
  401. Scheme: "mongodb",
  402. Host: host,
  403. Path: db,
  404. }
  405. if name != "" {
  406. u := url.UserPassword(name, password)
  407. ur.User = u
  408. }
  409. return ur
  410. }
  411. // EnsureIndexes ensures username is unique
  412. func (m *Mongo) EnsureIndexes() error {
  413. s := m.Session.Copy()
  414. defer s.Close()
  415. i := mgo.Index{
  416. Key: []string{"username"},
  417. Unique: true,
  418. DropDups: true,
  419. Background: true,
  420. Sparse: false,
  421. }
  422. c := s.DB("").C("customers")
  423. return c.EnsureIndex(i)
  424. }
  425. func (m *Mongo) Ping() error {
  426. s := m.Session.Copy()
  427. defer s.Close()
  428. return s.Ping()
  429. }