1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-27 13:48:49 +08:00
Darko Draskovic 340e685d70
MF-1180 - Add redis based twins and states cache (#1184)
* Add twins redis cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add connectToRedis to twins main and twinCache to twins service

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add tracing to twins cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add twins cache mock and test setup for redis cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add TestTwinSave to redis twins cache tests

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add remove twin redis cache test

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add channels param to CreateDefinition helper method in mocks

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add IDs test to redis twins cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Simplify senml rec array and attribute creation funcs by removing unnecessary params

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Align cache remove twin method with service remove twin method

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add cache funcs to twins save, update and remove

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add def SaveIDs to redis cache and ref to service SaveStates

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add TwinSaveIDs tests for redis cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add cache related env vars desc to README.md

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add twinid bson key constant

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add Update method to cache

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Integrate uuid unification related changes

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Use named arguments in interface method declarations

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Add env vars to docker-compose file

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Make parameter names in interface methods and implementations consistent

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>

* Wrap vars and consts in var and const blocks

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
2020-06-05 11:42:16 +02:00

157 lines
3.5 KiB
Go

// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package mongodb
import (
"context"
"github.com/mainflux/mainflux/twins"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
const (
statesCollection string = "states"
twinid = "twinid"
)
type stateRepository struct {
db *mongo.Database
}
var _ twins.StateRepository = (*stateRepository)(nil)
// NewStateRepository instantiates a MongoDB implementation of state
// repository.
func NewStateRepository(db *mongo.Database) twins.StateRepository {
return &stateRepository{
db: db,
}
}
// SaveState persists the state
func (sr *stateRepository) Save(ctx context.Context, st twins.State) error {
coll := sr.db.Collection(statesCollection)
if _, err := coll.InsertOne(context.Background(), st); err != nil {
return err
}
return nil
}
// Update persists the state
func (sr *stateRepository) Update(ctx context.Context, st twins.State) error {
coll := sr.db.Collection(statesCollection)
filter := bson.M{"id": st.ID, twinid: st.TwinID}
update := bson.M{"$set": st}
if _, err := coll.UpdateOne(context.Background(), filter, update); err != nil {
return err
}
return nil
}
// CountStates returns the number of states related to twin
func (sr *stateRepository) Count(ctx context.Context, tw twins.Twin) (int64, error) {
coll := sr.db.Collection(statesCollection)
filter := bson.M{twinid: tw.ID}
total, err := coll.CountDocuments(ctx, filter)
if err != nil {
return 0, err
}
return total, nil
}
// RetrieveAll retrieves the subset of states related to twin specified by id
func (sr *stateRepository) RetrieveAll(ctx context.Context, offset uint64, limit uint64, twinID string) (twins.StatesPage, error) {
coll := sr.db.Collection(statesCollection)
findOptions := options.Find()
findOptions.SetSkip(int64(offset))
findOptions.SetLimit(int64(limit))
filter := bson.M{twinid: twinID}
cur, err := coll.Find(ctx, filter, findOptions)
if err != nil {
return twins.StatesPage{}, err
}
results, err := decodeStates(ctx, cur)
if err != nil {
return twins.StatesPage{}, err
}
total, err := coll.CountDocuments(ctx, filter)
if err != nil {
return twins.StatesPage{}, err
}
return twins.StatesPage{
States: results,
PageMetadata: twins.PageMetadata{
Total: uint64(total),
Offset: offset,
Limit: limit,
},
}, nil
}
// RetrieveLast returns the last state related to twin spec by id
func (sr *stateRepository) RetrieveLast(ctx context.Context, twinID string) (twins.State, error) {
coll := sr.db.Collection(statesCollection)
filter := bson.M{twinid: twinID}
total, err := coll.CountDocuments(ctx, filter)
if err != nil {
return twins.State{}, err
}
findOptions := options.Find()
var skip int64
if total > 0 {
skip = total - 1
}
findOptions.SetSkip(skip)
findOptions.SetLimit(1)
cur, err := coll.Find(ctx, filter, findOptions)
if err != nil {
return twins.State{}, err
}
results, err := decodeStates(ctx, cur)
if err != nil {
return twins.State{}, err
}
if len(results) < 1 {
return twins.State{}, nil
}
return results[0], nil
}
func decodeStates(ctx context.Context, cur *mongo.Cursor) ([]twins.State, error) {
defer cur.Close(ctx)
var results []twins.State
for cur.Next(ctx) {
var elem twins.State
if err := cur.Decode(&elem); err != nil {
return []twins.State{}, nil
}
results = append(results, elem)
}
if err := cur.Err(); err != nil {
return []twins.State{}, nil
}
return results, nil
}