github.com/timoth-y/kicksware-api/order-service@v0.0.0-20201002192818-87b546a7ae5a/usecase/storage/mongo/repository.go (about) 1 package mongo 2 3 import ( 4 "context" 5 "crypto/tls" 6 "crypto/x509" 7 "github.com/pkg/errors" 8 "go.mongodb.org/mongo-driver/bson" 9 "go.mongodb.org/mongo-driver/mongo" 10 "go.mongodb.org/mongo-driver/mongo/options" 11 "go.mongodb.org/mongo-driver/mongo/readpref" 12 "io/ioutil" 13 "time" 14 15 "github.com/golang/glog" 16 TLS "github.com/timoth-y/kicksware-api/service-common/core/meta" 17 "github.com/timoth-y/kicksware-api/service-common/util" 18 19 "github.com/timoth-y/kicksware-api/service-common/core/meta" 20 "github.com/timoth-y/kicksware-api/order-service/core/model" 21 "github.com/timoth-y/kicksware-api/order-service/core/repo" 22 "github.com/timoth-y/kicksware-api/order-service/env" 23 "github.com/timoth-y/kicksware-api/order-service/usecase/business" 24 ) 25 26 type repository struct { 27 client *mongo.Client 28 database *mongo.Database 29 collection *mongo.Collection 30 timeout time.Duration 31 } 32 33 func NewRepository(config env.DataStoreConfig) (repo.OrderRepository, error) { 34 repo := &repository{ 35 timeout: time.Duration(config.Timeout) * time.Second, 36 } 37 client, err := newMongoClient(config); if err != nil { 38 return nil, errors.Wrap(err, "repository.NewRepository") 39 } 40 repo.client = client 41 database := client.Database(config.Database) 42 repo.database = database 43 repo.collection = database.Collection(config.Collection) 44 return repo, nil 45 } 46 47 func newMongoClient(config env.DataStoreConfig) (*mongo.Client, error) { 48 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(config.Timeout)*time.Second) 49 defer cancel() 50 client, err := mongo.Connect(ctx, options.Client(). 51 ApplyURI(config.URL). 52 SetTLSConfig(newTLSConfig(config.TLS)). 53 SetAuth(options.Credential{ 54 Username: config.Login, Password: config.Password, 55 }), 56 ) 57 err = client.Ping(ctx, readpref.Primary()); if err != nil { 58 return nil, err 59 } 60 return client, nil 61 } 62 63 func newTLSConfig(tlsConfig *TLS.TLSCertificate) *tls.Config { 64 if !tlsConfig.EnableTLS { 65 return nil 66 } 67 certs := x509.NewCertPool() 68 pem, err := ioutil.ReadFile(tlsConfig.CertFile); if err != nil { 69 glog.Fatalln(err) 70 } 71 certs.AppendCertsFromPEM(pem) 72 return &tls.Config{ 73 RootCAs: certs, 74 } 75 } 76 77 func (r *repository) FetchOne(code string, params *meta.RequestParams) (*model.Order, error) { 78 ctx, cancel := context.WithTimeout(context.Background(), r.timeout) 79 defer cancel() 80 81 query := r.buildQueryPipeline(bson.M{"unique_id": code}, params) 82 cursor, err := r.collection.Aggregate(ctx, query); if err != nil { 83 return nil, errors.Wrap(err, "repository.Order.FetchOne") 84 } 85 defer cursor.Close(ctx) 86 87 var orders []*model.Order 88 if err = cursor.All(ctx, &orders); err != nil { 89 return nil, errors.Wrap(err, "repository.Order.FetchOne") 90 } 91 if orders == nil || len(orders) == 0 { 92 if err == mongo.ErrNoDocuments{ 93 return nil, errors.Wrap(business.ErrOrderNotFound, "repository.Order.FetchOne") 94 } 95 return nil, errors.Wrap(err, "repository.Order.FetchOne") 96 } 97 return orders[0], nil 98 } 99 100 func (r *repository) Fetch(codes []string, params *meta.RequestParams) ([]*model.Order, error) { 101 ctx, cancel := context.WithTimeout(context.Background(), r.timeout) 102 defer cancel() 103 104 query := r.buildQueryPipeline(bson.M{"unique_id": bson.M{"$in": codes}}, params) 105 cursor, err := r.collection.Aggregate(ctx, query); if err != nil { 106 return nil, errors.Wrap(err, "repository.Order.Fetch") 107 } 108 defer cursor.Close(ctx) 109 110 var orders []*model.Order 111 if err = cursor.All(ctx, &orders); err != nil { 112 return nil, errors.Wrap(err, "repository.Order.Fetch") 113 } 114 if orders == nil || len(orders) == 0 { 115 if err == mongo.ErrNoDocuments { 116 return nil, errors.Wrap(business.ErrOrderNotFound, "repository.Order.Fetch") 117 } 118 return nil, errors.Wrap(err, "repository.Order.Fetch") 119 } 120 return orders, nil 121 } 122 123 func (r *repository) FetchAll(params *meta.RequestParams) ([]*model.Order, error) { 124 ctx, cancel := context.WithTimeout(context.Background(), r.timeout) 125 defer cancel() 126 127 query := r.buildQueryPipeline(bson.M{}, params) 128 cursor, err := r.collection.Aggregate(ctx, query); if err != nil { 129 return nil, errors.Wrap(err, "repository.Order.FetchAll") 130 } 131 defer cursor.Close(ctx) 132 133 var order []*model.Order 134 if err = cursor.All(ctx, &order); err != nil { 135 if err == mongo.ErrNoDocuments { 136 return nil, errors.Wrap(business.ErrOrderNotFound, "repository.Order.FetchAll") 137 } 138 return nil, errors.Wrap(err, "repository.Order.FetchAll") 139 } 140 return order, nil 141 } 142 143 func (r *repository) FetchQuery(query meta.RequestQuery, params *meta.RequestParams) ([]*model.Order, error) { 144 ctx, cancel := context.WithTimeout(context.Background(), r.timeout) 145 defer cancel() 146 147 filter, err := query.ToBson(); if err != nil { 148 return nil, errors.Wrap(err, "repository.Order.FetchQuery") 149 } 150 queryPipe := r.buildQueryPipeline(filter, params) 151 cursor, err := r.collection.Aggregate(ctx, queryPipe) 152 if err != nil { 153 return nil, errors.Wrap(err, "repository.Order.FetchQuery") 154 } 155 defer cursor.Close(ctx) 156 157 var orders []*model.Order 158 if err = cursor.All(ctx, &orders); err != nil { 159 return nil, errors.Wrap(err, "repository.Order.FetchQuery") 160 } 161 if orders == nil || len(orders) == 0 { 162 return nil, errors.Wrap(business.ErrOrderNotFound, "repository.Order.FetchQuery") 163 } 164 return orders, nil 165 } 166 167 func (r *repository) StoreOne(order *model.Order) error { 168 ctx, cancel := context.WithTimeout(context.Background(), r.timeout) 169 defer cancel() 170 _, err := r.collection.InsertOne(ctx, order) 171 if err != nil { 172 return errors.Wrap(err, "repository.Order.Store") 173 } 174 return nil 175 } 176 177 func (r *repository) Modify(order *model.Order) error { 178 ctx, cancel := context.WithTimeout(context.Background(), r.timeout) 179 defer cancel() 180 doc, err := util.ToBsonMap(order); if err != nil { 181 return errors.Wrap(err, "repository.Order.Modify") 182 } 183 update := bson.D{ 184 {"$set", doc}, 185 } 186 filter := bson.M{"unique_id": order.UniqueID} 187 if _, err = r.collection.UpdateOne(ctx, filter, update); err != nil { 188 return errors.Wrap(err, "repository.Order.Modify") 189 } 190 return nil 191 } 192 193 func (r *repository) Remove(code string) error { 194 ctx, cancel := context.WithTimeout(context.Background(), r.timeout) 195 defer cancel() 196 filter := bson.M{"unique_id": code} 197 if _, err := r.collection.DeleteOne(ctx, filter); err != nil { 198 return errors.Wrap(err, "repository.Order.Remove") 199 } 200 return nil 201 } 202 203 func (r *repository) Count(query meta.RequestQuery, params *meta.RequestParams) (int, error) { 204 ctx, cancel := context.WithTimeout(context.Background(), r.timeout) 205 defer cancel() 206 207 filter, err := query.ToBson(); if err != nil { 208 return 0, errors.Wrap(err, "repository.Order.Count") 209 } 210 211 count, err := r.collection.CountDocuments(ctx, filter); if err != nil { 212 return 0, errors.Wrap(err, "repository.Order.Count") 213 } 214 return int(count), nil 215 } 216 217 func (r *repository) CountAll() (int, error) { 218 ctx, cancel := context.WithTimeout(context.Background(), r.timeout) 219 defer cancel() 220 221 filter := bson.M{} 222 count, err := r.collection.CountDocuments(ctx, filter); if err != nil { 223 return 0, errors.Wrap(err, "repository.Order.Count") 224 } 225 return int(count), nil 226 } 227 228 229 func (r *repository) buildQueryPipeline(matchQuery bson.M, param *meta.RequestParams) mongo.Pipeline { 230 pipe := mongo.Pipeline{} 231 pipe = append(pipe, bson.D{{"$match", matchQuery}}) 232 233 return pipe 234 } 235