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  }