github.com/lingyao2333/mo-zero@v1.4.1/core/stores/mon/model.go (about) 1 package mon 2 3 import ( 4 "context" 5 "log" 6 "strings" 7 8 "github.com/lingyao2333/mo-zero/core/breaker" 9 "github.com/lingyao2333/mo-zero/core/timex" 10 "go.mongodb.org/mongo-driver/mongo" 11 mopt "go.mongodb.org/mongo-driver/mongo/options" 12 ) 13 14 const ( 15 startSession = "StartSession" 16 abortTransaction = "AbortTransaction" 17 commitTransaction = "CommitTransaction" 18 withTransaction = "WithTransaction" 19 endSession = "EndSession" 20 ) 21 22 type ( 23 // Model is a mongodb store model that represents a collection. 24 Model struct { 25 Collection 26 name string 27 cli *mongo.Client 28 brk breaker.Breaker 29 opts []Option 30 } 31 32 wrappedSession struct { 33 mongo.Session 34 name string 35 brk breaker.Breaker 36 } 37 ) 38 39 // MustNewModel returns a Model, exits on errors. 40 func MustNewModel(uri, db, collection string, opts ...Option) *Model { 41 model, err := NewModel(uri, db, collection, opts...) 42 if err != nil { 43 log.Fatal(err) 44 } 45 46 return model 47 } 48 49 // NewModel returns a Model. 50 func NewModel(uri, db, collection string, opts ...Option) (*Model, error) { 51 cli, err := getClient(uri) 52 if err != nil { 53 return nil, err 54 } 55 56 name := strings.Join([]string{uri, collection}, "/") 57 brk := breaker.GetBreaker(uri) 58 coll := newCollection(cli.Database(db).Collection(collection), brk) 59 return newModel(name, cli, coll, brk, opts...), nil 60 } 61 62 func newModel(name string, cli *mongo.Client, coll Collection, brk breaker.Breaker, 63 opts ...Option) *Model { 64 return &Model{ 65 name: name, 66 Collection: coll, 67 cli: cli, 68 brk: brk, 69 opts: opts, 70 } 71 } 72 73 // StartSession starts a new session. 74 func (m *Model) StartSession(opts ...*mopt.SessionOptions) (sess mongo.Session, err error) { 75 err = m.brk.DoWithAcceptable(func() error { 76 starTime := timex.Now() 77 defer func() { 78 logDuration(context.Background(), m.name, startSession, starTime, err) 79 }() 80 81 session, sessionErr := m.cli.StartSession(opts...) 82 if sessionErr != nil { 83 return sessionErr 84 } 85 86 sess = &wrappedSession{ 87 Session: session, 88 name: m.name, 89 brk: m.brk, 90 } 91 92 return nil 93 }, acceptable) 94 95 return 96 } 97 98 // Aggregate executes an aggregation pipeline. 99 func (m *Model) Aggregate(ctx context.Context, v, pipeline interface{}, opts ...*mopt.AggregateOptions) error { 100 cur, err := m.Collection.Aggregate(ctx, pipeline, opts...) 101 if err != nil { 102 return err 103 } 104 defer cur.Close(ctx) 105 106 return cur.All(ctx, v) 107 } 108 109 // DeleteMany deletes documents that match the filter. 110 func (m *Model) DeleteMany(ctx context.Context, filter interface{}, opts ...*mopt.DeleteOptions) (int64, error) { 111 res, err := m.Collection.DeleteMany(ctx, filter, opts...) 112 if err != nil { 113 return 0, err 114 } 115 116 return res.DeletedCount, nil 117 } 118 119 // DeleteOne deletes the first document that matches the filter. 120 func (m *Model) DeleteOne(ctx context.Context, filter interface{}, opts ...*mopt.DeleteOptions) (int64, error) { 121 res, err := m.Collection.DeleteOne(ctx, filter, opts...) 122 if err != nil { 123 return 0, err 124 } 125 126 return res.DeletedCount, nil 127 } 128 129 // Find finds documents that match the filter. 130 func (m *Model) Find(ctx context.Context, v, filter interface{}, opts ...*mopt.FindOptions) error { 131 cur, err := m.Collection.Find(ctx, filter, opts...) 132 if err != nil { 133 return err 134 } 135 defer cur.Close(ctx) 136 137 return cur.All(ctx, v) 138 } 139 140 // FindOne finds the first document that matches the filter. 141 func (m *Model) FindOne(ctx context.Context, v, filter interface{}, opts ...*mopt.FindOneOptions) error { 142 res, err := m.Collection.FindOne(ctx, filter, opts...) 143 if err != nil { 144 return err 145 } 146 147 return res.Decode(v) 148 } 149 150 // FindOneAndDelete finds a single document and deletes it. 151 func (m *Model) FindOneAndDelete(ctx context.Context, v, filter interface{}, 152 opts ...*mopt.FindOneAndDeleteOptions) error { 153 res, err := m.Collection.FindOneAndDelete(ctx, filter, opts...) 154 if err != nil { 155 return err 156 } 157 158 return res.Decode(v) 159 } 160 161 // FindOneAndReplace finds a single document and replaces it. 162 func (m *Model) FindOneAndReplace(ctx context.Context, v, filter, replacement interface{}, 163 opts ...*mopt.FindOneAndReplaceOptions) error { 164 res, err := m.Collection.FindOneAndReplace(ctx, filter, replacement, opts...) 165 if err != nil { 166 return err 167 } 168 169 return res.Decode(v) 170 } 171 172 // FindOneAndUpdate finds a single document and updates it. 173 func (m *Model) FindOneAndUpdate(ctx context.Context, v, filter, update interface{}, 174 opts ...*mopt.FindOneAndUpdateOptions) error { 175 res, err := m.Collection.FindOneAndUpdate(ctx, filter, update, opts...) 176 if err != nil { 177 return err 178 } 179 180 return res.Decode(v) 181 } 182 183 // AbortTransaction implements the mongo.Session interface. 184 func (w *wrappedSession) AbortTransaction(ctx context.Context) (err error) { 185 ctx, span := startSpan(ctx, abortTransaction) 186 defer func() { 187 endSpan(span, err) 188 }() 189 190 return w.brk.DoWithAcceptable(func() error { 191 starTime := timex.Now() 192 defer func() { 193 logDuration(ctx, w.name, abortTransaction, starTime, err) 194 }() 195 196 return w.Session.AbortTransaction(ctx) 197 }, acceptable) 198 } 199 200 // CommitTransaction implements the mongo.Session interface. 201 func (w *wrappedSession) CommitTransaction(ctx context.Context) (err error) { 202 ctx, span := startSpan(ctx, commitTransaction) 203 defer func() { 204 endSpan(span, err) 205 }() 206 207 return w.brk.DoWithAcceptable(func() error { 208 starTime := timex.Now() 209 defer func() { 210 logDuration(ctx, w.name, commitTransaction, starTime, err) 211 }() 212 213 return w.Session.CommitTransaction(ctx) 214 }, acceptable) 215 } 216 217 // WithTransaction implements the mongo.Session interface. 218 func (w *wrappedSession) WithTransaction( 219 ctx context.Context, 220 fn func(sessCtx mongo.SessionContext) (interface{}, error), 221 opts ...*mopt.TransactionOptions, 222 ) (res interface{}, err error) { 223 ctx, span := startSpan(ctx, withTransaction) 224 defer func() { 225 endSpan(span, err) 226 }() 227 228 err = w.brk.DoWithAcceptable(func() error { 229 starTime := timex.Now() 230 defer func() { 231 logDuration(ctx, w.name, withTransaction, starTime, err) 232 }() 233 234 res, err = w.Session.WithTransaction(ctx, fn, opts...) 235 return err 236 }, acceptable) 237 238 return 239 } 240 241 // EndSession implements the mongo.Session interface. 242 func (w *wrappedSession) EndSession(ctx context.Context) { 243 var err error 244 ctx, span := startSpan(ctx, endSession) 245 defer func() { 246 endSpan(span, err) 247 }() 248 249 err = w.brk.DoWithAcceptable(func() error { 250 starTime := timex.Now() 251 defer func() { 252 logDuration(ctx, w.name, endSession, starTime, err) 253 }() 254 255 w.Session.EndSession(ctx) 256 return nil 257 }, acceptable) 258 }