github.com/lingyao2333/mo-zero@v1.4.1/core/stores/mongoc/cachedmodel.go (about)

     1  package mongoc
     2  
     3  import (
     4  	"log"
     5  
     6  	"github.com/globalsign/mgo"
     7  	"github.com/lingyao2333/mo-zero/core/stores/cache"
     8  	"github.com/lingyao2333/mo-zero/core/stores/mongo"
     9  	"github.com/lingyao2333/mo-zero/core/stores/redis"
    10  )
    11  
    12  // A Model is a mongo model that built with cache capability.
    13  type Model struct {
    14  	*mongo.Model
    15  	cache              cache.Cache
    16  	generateCollection func(*mgo.Session) CachedCollection
    17  }
    18  
    19  // MustNewNodeModel returns a Model with a cache node, exists on errors.
    20  func MustNewNodeModel(url, collection string, rds *redis.Redis, opts ...cache.Option) *Model {
    21  	model, err := NewNodeModel(url, collection, rds, opts...)
    22  	if err != nil {
    23  		log.Fatal(err)
    24  	}
    25  
    26  	return model
    27  }
    28  
    29  // MustNewModel returns a Model with a cache cluster, exists on errors.
    30  func MustNewModel(url, collection string, c cache.CacheConf, opts ...cache.Option) *Model {
    31  	model, err := NewModel(url, collection, c, opts...)
    32  	if err != nil {
    33  		log.Fatal(err)
    34  	}
    35  
    36  	return model
    37  }
    38  
    39  // NewModel returns a Model with a cache cluster.
    40  func NewModel(url, collection string, conf cache.CacheConf, opts ...cache.Option) (*Model, error) {
    41  	c := cache.New(conf, singleFlight, stats, mgo.ErrNotFound, opts...)
    42  	return NewModelWithCache(url, collection, c)
    43  }
    44  
    45  // NewModelWithCache returns a Model with a custom cache.
    46  func NewModelWithCache(url, collection string, c cache.Cache) (*Model, error) {
    47  	return createModel(url, collection, c, func(collection mongo.Collection) CachedCollection {
    48  		return newCollection(collection, c)
    49  	})
    50  }
    51  
    52  // NewNodeModel returns a Model with a cache node.
    53  func NewNodeModel(url, collection string, rds *redis.Redis, opts ...cache.Option) (*Model, error) {
    54  	c := cache.NewNode(rds, singleFlight, stats, mgo.ErrNotFound, opts...)
    55  	return NewModelWithCache(url, collection, c)
    56  }
    57  
    58  // Count returns the count of given query.
    59  func (mm *Model) Count(query interface{}) (int, error) {
    60  	return mm.executeInt(func(c CachedCollection) (int, error) {
    61  		return c.Count(query)
    62  	})
    63  }
    64  
    65  // DelCache deletes the cache with given keys.
    66  func (mm *Model) DelCache(keys ...string) error {
    67  	return mm.cache.Del(keys...)
    68  }
    69  
    70  // GetCache unmarshal the cache into v with given key.
    71  func (mm *Model) GetCache(key string, v interface{}) error {
    72  	return mm.cache.Get(key, v)
    73  }
    74  
    75  // GetCollection returns a cache collection.
    76  func (mm *Model) GetCollection(session *mgo.Session) CachedCollection {
    77  	return mm.generateCollection(session)
    78  }
    79  
    80  // FindAllNoCache finds all records without cache.
    81  func (mm *Model) FindAllNoCache(v, query interface{}, opts ...QueryOption) error {
    82  	return mm.execute(func(c CachedCollection) error {
    83  		return c.FindAllNoCache(v, query, opts...)
    84  	})
    85  }
    86  
    87  // FindOne unmarshals a record into v with given key and query.
    88  func (mm *Model) FindOne(v interface{}, key string, query interface{}) error {
    89  	return mm.execute(func(c CachedCollection) error {
    90  		return c.FindOne(v, key, query)
    91  	})
    92  }
    93  
    94  // FindOneNoCache unmarshals a record into v with query, without cache.
    95  func (mm *Model) FindOneNoCache(v, query interface{}) error {
    96  	return mm.execute(func(c CachedCollection) error {
    97  		return c.FindOneNoCache(v, query)
    98  	})
    99  }
   100  
   101  // FindOneId unmarshals a record into v with query.
   102  func (mm *Model) FindOneId(v interface{}, key string, id interface{}) error {
   103  	return mm.execute(func(c CachedCollection) error {
   104  		return c.FindOneId(v, key, id)
   105  	})
   106  }
   107  
   108  // FindOneIdNoCache unmarshals a record into v with query, without cache.
   109  func (mm *Model) FindOneIdNoCache(v, id interface{}) error {
   110  	return mm.execute(func(c CachedCollection) error {
   111  		return c.FindOneIdNoCache(v, id)
   112  	})
   113  }
   114  
   115  // Insert inserts docs.
   116  func (mm *Model) Insert(docs ...interface{}) error {
   117  	return mm.execute(func(c CachedCollection) error {
   118  		return c.Insert(docs...)
   119  	})
   120  }
   121  
   122  // Pipe returns a mongo pipe with given pipeline.
   123  func (mm *Model) Pipe(pipeline interface{}) (mongo.Pipe, error) {
   124  	return mm.pipe(func(c CachedCollection) mongo.Pipe {
   125  		return c.Pipe(pipeline)
   126  	})
   127  }
   128  
   129  // Remove removes a record with given selector, and remove it from cache with given keys.
   130  func (mm *Model) Remove(selector interface{}, keys ...string) error {
   131  	return mm.execute(func(c CachedCollection) error {
   132  		return c.Remove(selector, keys...)
   133  	})
   134  }
   135  
   136  // RemoveNoCache removes a record with given selector.
   137  func (mm *Model) RemoveNoCache(selector interface{}) error {
   138  	return mm.execute(func(c CachedCollection) error {
   139  		return c.RemoveNoCache(selector)
   140  	})
   141  }
   142  
   143  // RemoveAll removes all records with given selector, and removes cache with given keys.
   144  func (mm *Model) RemoveAll(selector interface{}, keys ...string) (*mgo.ChangeInfo, error) {
   145  	return mm.change(func(c CachedCollection) (*mgo.ChangeInfo, error) {
   146  		return c.RemoveAll(selector, keys...)
   147  	})
   148  }
   149  
   150  // RemoveAllNoCache removes all records with given selector, and returns a mgo.ChangeInfo.
   151  func (mm *Model) RemoveAllNoCache(selector interface{}) (*mgo.ChangeInfo, error) {
   152  	return mm.change(func(c CachedCollection) (*mgo.ChangeInfo, error) {
   153  		return c.RemoveAllNoCache(selector)
   154  	})
   155  }
   156  
   157  // RemoveId removes a record with given id, and removes cache with given keys.
   158  func (mm *Model) RemoveId(id interface{}, keys ...string) error {
   159  	return mm.execute(func(c CachedCollection) error {
   160  		return c.RemoveId(id, keys...)
   161  	})
   162  }
   163  
   164  // RemoveIdNoCache removes a record with given id.
   165  func (mm *Model) RemoveIdNoCache(id interface{}) error {
   166  	return mm.execute(func(c CachedCollection) error {
   167  		return c.RemoveIdNoCache(id)
   168  	})
   169  }
   170  
   171  // SetCache sets the cache with given key and value.
   172  func (mm *Model) SetCache(key string, v interface{}) error {
   173  	return mm.cache.Set(key, v)
   174  }
   175  
   176  // Update updates the record with given selector, and delete cache with given keys.
   177  func (mm *Model) Update(selector, update interface{}, keys ...string) error {
   178  	return mm.execute(func(c CachedCollection) error {
   179  		return c.Update(selector, update, keys...)
   180  	})
   181  }
   182  
   183  // UpdateNoCache updates the record with given selector.
   184  func (mm *Model) UpdateNoCache(selector, update interface{}) error {
   185  	return mm.execute(func(c CachedCollection) error {
   186  		return c.UpdateNoCache(selector, update)
   187  	})
   188  }
   189  
   190  // UpdateId updates the record with given id, and delete cache with given keys.
   191  func (mm *Model) UpdateId(id, update interface{}, keys ...string) error {
   192  	return mm.execute(func(c CachedCollection) error {
   193  		return c.UpdateId(id, update, keys...)
   194  	})
   195  }
   196  
   197  // UpdateIdNoCache updates the record with given id.
   198  func (mm *Model) UpdateIdNoCache(id, update interface{}) error {
   199  	return mm.execute(func(c CachedCollection) error {
   200  		return c.UpdateIdNoCache(id, update)
   201  	})
   202  }
   203  
   204  // Upsert upserts a record with given selector, and delete cache with given keys.
   205  func (mm *Model) Upsert(selector, update interface{}, keys ...string) (*mgo.ChangeInfo, error) {
   206  	return mm.change(func(c CachedCollection) (*mgo.ChangeInfo, error) {
   207  		return c.Upsert(selector, update, keys...)
   208  	})
   209  }
   210  
   211  // UpsertNoCache upserts a record with given selector.
   212  func (mm *Model) UpsertNoCache(selector, update interface{}) (*mgo.ChangeInfo, error) {
   213  	return mm.change(func(c CachedCollection) (*mgo.ChangeInfo, error) {
   214  		return c.UpsertNoCache(selector, update)
   215  	})
   216  }
   217  
   218  func (mm *Model) change(fn func(c CachedCollection) (*mgo.ChangeInfo, error)) (*mgo.ChangeInfo, error) {
   219  	session, err := mm.TakeSession()
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  	defer mm.PutSession(session)
   224  
   225  	return fn(mm.GetCollection(session))
   226  }
   227  
   228  func (mm *Model) execute(fn func(c CachedCollection) error) error {
   229  	session, err := mm.TakeSession()
   230  	if err != nil {
   231  		return err
   232  	}
   233  	defer mm.PutSession(session)
   234  
   235  	return fn(mm.GetCollection(session))
   236  }
   237  
   238  func (mm *Model) executeInt(fn func(c CachedCollection) (int, error)) (int, error) {
   239  	session, err := mm.TakeSession()
   240  	if err != nil {
   241  		return 0, err
   242  	}
   243  	defer mm.PutSession(session)
   244  
   245  	return fn(mm.GetCollection(session))
   246  }
   247  
   248  func (mm *Model) pipe(fn func(c CachedCollection) mongo.Pipe) (mongo.Pipe, error) {
   249  	session, err := mm.TakeSession()
   250  	if err != nil {
   251  		return nil, err
   252  	}
   253  	defer mm.PutSession(session)
   254  
   255  	return fn(mm.GetCollection(session)), nil
   256  }
   257  
   258  func createModel(url, collection string, c cache.Cache,
   259  	create func(mongo.Collection) CachedCollection) (*Model, error) {
   260  	model, err := mongo.NewModel(url, collection)
   261  	if err != nil {
   262  		return nil, err
   263  	}
   264  
   265  	return &Model{
   266  		Model: model,
   267  		cache: c,
   268  		generateCollection: func(session *mgo.Session) CachedCollection {
   269  			collection := model.GetCollection(session)
   270  			return create(collection)
   271  		},
   272  	}, nil
   273  }