Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
455
pkg/mongo/fleets.go
Normal file
455
pkg/mongo/fleets.go
Normal file
@@ -0,0 +1,455 @@
|
||||
package mongo
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"fiskerinc.com/modules/common"
|
||||
"fiskerinc.com/modules/db/queries"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
|
||||
"fiskerinc.com/modules/utils/elptr"
|
||||
"github.com/pkg/errors"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
|
||||
// NewFleetsCollection is the constructor for Fleets and utilizes the same mongo connection
|
||||
func NewFleetsCollection(c CollectionInterface) FleetsCollectionInterface {
|
||||
return &FleetsCollection{c}
|
||||
}
|
||||
|
||||
type FleetsCollectionInterface interface {
|
||||
AddFleet(fleet *Fleet) error
|
||||
FindFleet(filter *Fleet) (*Fleet, error)
|
||||
UpdateFleet(filter *Fleet, fleet *Fleet) error
|
||||
DeleteFleet(fleet *Fleet) error
|
||||
|
||||
SelectFleets(filter *Fleet, options *queries.PageQueryOptions) ([]Fleet, error)
|
||||
GetFleetCount(filter *Fleet) (int64, error)
|
||||
|
||||
GetVehiclesForFleet(name, search string, options *queries.PageQueryOptions) ([]string, error)
|
||||
GetVehiclesForFleetCount(name, search string) (int64, error)
|
||||
AddVehiclesToFleet(name string, vins []string) error
|
||||
DeleteVehiclesFromFleet(name string, vins []string) error
|
||||
|
||||
GetFiltersForFleet(name string, options *queries.PageQueryOptions) ([]common.CANFilter, error)
|
||||
GetFiltersForFleetCount(name string) (int64, error)
|
||||
AddFilterToFleet(name string, filter *common.CANFilter) error
|
||||
UpdateFilterForFleet(name string, id string, filter *common.CANFilter) error
|
||||
DeleteFilterFromFleet(name string, id string) error
|
||||
|
||||
GetCANBusForVehicle(vin string) (*Fleet, error)
|
||||
|
||||
CollectionInterface
|
||||
}
|
||||
|
||||
// FleetsCollection is the client for the collection
|
||||
type FleetsCollection struct {
|
||||
CollectionInterface
|
||||
}
|
||||
|
||||
// Fleet is an embedded object within Vehicle
|
||||
type Fleet struct {
|
||||
Name string `json:"name" bson:"name"`
|
||||
LogLevel common.LogLevel `json:"log_level" bson:"log_level,omitempty"`
|
||||
CANBus common.CANBus `json:"canbus" bson:"canbus,omitempty"`
|
||||
IDPSEnabled bool `json:"idps_enabled" bson:"idps_enabled"`
|
||||
DebugMask string `json:"debug_mask,omitempty" bson:"debug_mask,omitempty"`
|
||||
Tags []string `json:"tags" bson:"tags,omitempty"`
|
||||
Vehicles []string `json:"vehicles" bson:"vehicles,omitempty"`
|
||||
VehiclesCount int `json:"vehicles_count" bson:"vehicles_count,omitempty"`
|
||||
search string `json:"-" bson:"-"`
|
||||
}
|
||||
|
||||
func (f *Fleet) SetSearchQuery(search string) {
|
||||
f.search = search
|
||||
}
|
||||
|
||||
func (f *Fleet) SearchQuery() string {
|
||||
return f.search
|
||||
}
|
||||
|
||||
func (f *Fleet) AsExpr() bson.M {
|
||||
if f == nil || len(strings.Trim(f.search, " ")) == 0 {
|
||||
return bson.M{}
|
||||
}
|
||||
|
||||
return bson.M{"$text": bson.M{"$search": f.search}}
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) AddFleet(fleet *Fleet) error {
|
||||
_, err := c.InsertOne(fleet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) FindFleet(filter *Fleet) (*Fleet, error) {
|
||||
m := bson.M{"name": filter.Name}
|
||||
projection := bson.D{{"vehicles", 0}}
|
||||
|
||||
f := &Fleet{}
|
||||
err := c.FindOne(m, f, projection)
|
||||
if err != nil {
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) UpdateFleet(filter *Fleet, fleet *Fleet) error {
|
||||
if fleet.CANBus.DTCEnabled == nil {
|
||||
fleet.CANBus.DTCEnabled = elptr.ElPtr(false)
|
||||
}
|
||||
m := bson.M{"name": filter.Name}
|
||||
u := bson.M{"$set": bson.M{
|
||||
"name": fleet.Name,
|
||||
"canbus.enabled": fleet.CANBus.Enabled,
|
||||
"canbus.data_logger": fleet.CANBus.DataLogger,
|
||||
"canbus.dtc_enabled": fleet.CANBus.DTCEnabled,
|
||||
"canbus.mem_buff_size": fleet.CANBus.MemBuffSize,
|
||||
"canbus.disk_buff_size": fleet.CANBus.DiskBuffSize,
|
||||
"idps_enabled": fleet.IDPSEnabled,
|
||||
"log_level": fleet.LogLevel,
|
||||
"debug_mask": fleet.DebugMask,
|
||||
}}
|
||||
|
||||
_, err := c.UpdateOne(m, u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) DeleteFleet(fleet *Fleet) error {
|
||||
m := bson.M{"name": fleet.Name}
|
||||
|
||||
err := c.DeleteOne(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) SelectFleets(filter *Fleet, options *queries.PageQueryOptions) ([]Fleet, error) {
|
||||
m, f := filter.AsExpr(), make([]Fleet, 0, 0)
|
||||
|
||||
if err := c.Find(m, &f, options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for x := range f {
|
||||
if f[x].CANBus.DTCEnabled == nil {
|
||||
f[x].CANBus.DTCEnabled = elptr.ElPtr(false)
|
||||
}
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) GetFleetCount(filter *Fleet) (int64, error) {
|
||||
m := filter.AsExpr()
|
||||
|
||||
if len(filter.Tags) > 0 {
|
||||
m["tags"] = bson.M{"$all": filter.Tags}
|
||||
}
|
||||
|
||||
return c.Count(m)
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) GetVehiclesForFleet(name, search string, options *queries.PageQueryOptions) ([]string, error) {
|
||||
preProc := mongo.Pipeline{
|
||||
{{"$match", bson.D{{"name", name}}}},
|
||||
{{"$project", bson.D{{
|
||||
"vin", bson.D{{
|
||||
"$cond", bson.A{bson.D{{"$isArray", "$vehicles"}}, "$vehicles", []string{}},
|
||||
}},
|
||||
}}}},
|
||||
{{"$unwind", "$vin"}},
|
||||
}
|
||||
|
||||
if search != "" {
|
||||
preProc = append(preProc, bson.D{
|
||||
{"$match", bson.M{"vin": primitive.Regex{
|
||||
Pattern: search,
|
||||
Options: "i",
|
||||
}}}})
|
||||
}
|
||||
|
||||
preProc = append(preProc, bson.D{{"$sort", bson.D{{"vin", 1}}}})
|
||||
|
||||
postProc := mongo.Pipeline{
|
||||
{{"$group", bson.D{{"_id", "$_id"}, {"vehicles", bson.D{{"$push", "$vin"}}}}}},
|
||||
}
|
||||
|
||||
pipe := mongo.Pipeline{}
|
||||
pipe = append(pipe, preProc...)
|
||||
if options.Offset > 0 {
|
||||
pipe = append(pipe, bson.D{{"$skip", options.Offset}})
|
||||
}
|
||||
if options.Limit > 0 {
|
||||
pipe = append(pipe, bson.D{{"$limit", options.Limit}})
|
||||
}
|
||||
pipe = append(pipe, postProc...)
|
||||
|
||||
var fleets []Fleet
|
||||
err := c.Aggregate(pipe, &fleets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(fleets) != 1 {
|
||||
return []string{}, nil
|
||||
}
|
||||
return fleets[0].Vehicles, nil
|
||||
}
|
||||
|
||||
type count struct {
|
||||
Total int64 `bson:"total"`
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) GetVehiclesForFleetCount(name, search string) (int64, error) {
|
||||
pipe := mongo.Pipeline{
|
||||
{{"$match", bson.D{{"name", name}}}},
|
||||
}
|
||||
if search == "" {
|
||||
pipe = append(pipe, bson.D{{"$project", bson.D{{
|
||||
"total", bson.D{{
|
||||
"$size", bson.D{{
|
||||
"$cond", bson.A{
|
||||
bson.D{{"$isArray", "$vehicles"}}, "$vehicles", []string{}},
|
||||
}},
|
||||
}}}},
|
||||
}})
|
||||
} else {
|
||||
pipe = append(pipe,
|
||||
bson.D{{"$project",
|
||||
bson.D{{"vin",
|
||||
bson.D{{"$cond",
|
||||
bson.A{
|
||||
bson.D{{"$isArray", "$vehicles"}}, "$vehicles", []string{}}}}}}}},
|
||||
bson.D{{"$unwind", "$vin"}},
|
||||
bson.D{{"$match", bson.M{"vin": primitive.Regex{
|
||||
Pattern: search,
|
||||
Options: "i",
|
||||
}}}},
|
||||
bson.D{{"$count", "total"}},
|
||||
)
|
||||
}
|
||||
|
||||
var counter []count
|
||||
|
||||
err := c.Aggregate(pipe, &counter)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(counter) != 1 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return counter[0].Total, nil
|
||||
}
|
||||
|
||||
// Creates a Mongodb pipeline to accomplish several steps
|
||||
// 1. Get document by name
|
||||
// 2. Merge vins as sets
|
||||
// 3. Calculate an accurate count
|
||||
// 4. Store result in db
|
||||
func createPipelineForFleetVehicles(name string, vins []string, mergeStrategy string) mongo.Pipeline {
|
||||
return mongo.Pipeline{
|
||||
{{"$match", bson.D{{"name", name}}}},
|
||||
{{"$addFields", bson.D{
|
||||
{"vehicles", bson.D{
|
||||
{mergeStrategy, bson.A{
|
||||
bson.D{{"$ifNull", bson.A{"$vehicles", bson.A{}}}},
|
||||
vins,
|
||||
}},
|
||||
}},
|
||||
}}},
|
||||
{{"$set", bson.D{
|
||||
{"vehicles_count", bson.D{
|
||||
{"$size", bson.D{
|
||||
{"$ifNull", bson.A{"$vehicles", bson.A{}}},
|
||||
}},
|
||||
}},
|
||||
}}},
|
||||
{{"$merge", bson.D{{"into", "fleets"}}}},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) AddVehiclesToFleet(name string, vins []string) error {
|
||||
if len(vins) == 0 {
|
||||
return errors.Errorf("No VINs to add to fleet")
|
||||
}
|
||||
|
||||
pipe := createPipelineForFleetVehicles(name, vins, "$setUnion")
|
||||
|
||||
var result []interface{}
|
||||
err := c.Aggregate(pipe, &result)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) DeleteVehiclesFromFleet(name string, vins []string) error {
|
||||
if len(vins) == 0 {
|
||||
return errors.Errorf("No VINs to remove from fleet")
|
||||
}
|
||||
|
||||
pipe := createPipelineForFleetVehicles(name, vins, "$setDifference")
|
||||
|
||||
var result []interface{}
|
||||
err := c.Aggregate(pipe, &result)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) GetFiltersForFleet(name string, options *queries.PageQueryOptions) ([]common.CANFilter, error) {
|
||||
preProc := mongo.Pipeline{
|
||||
{{"$match", bson.D{{"name", name}}}},
|
||||
{{"$project", bson.D{{
|
||||
"canbus.filters", bson.D{{
|
||||
"$cond", bson.A{bson.D{{"$isArray", "$canbus.filters"}}, "$canbus.filters", []common.CANFilter{}},
|
||||
}},
|
||||
}}}},
|
||||
{{"$unwind", "$canbus.filters"}},
|
||||
{{"$sort", bson.D{{"canbus.filters.can_id", 1}}}},
|
||||
}
|
||||
postProc := mongo.Pipeline{
|
||||
{{"$group", bson.D{{"_id", "$_id"}, {"filters", bson.D{{"$push", "$canbus.filters"}}}}}},
|
||||
{{"$project", bson.D{{"canbus.filters", "$filters"}}}},
|
||||
}
|
||||
|
||||
pipe := mongo.Pipeline{}
|
||||
pipe = append(pipe, preProc...)
|
||||
if options.Offset > 0 {
|
||||
pipe = append(pipe, bson.D{{"$skip", options.Offset}})
|
||||
}
|
||||
if options.Limit > 0 {
|
||||
pipe = append(pipe, bson.D{{"$limit", options.Limit}})
|
||||
}
|
||||
pipe = append(pipe, postProc...)
|
||||
|
||||
var fleets []Fleet
|
||||
err := c.Aggregate(pipe, &fleets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(fleets) != 1 {
|
||||
return []common.CANFilter{}, nil
|
||||
}
|
||||
return fleets[0].CANBus.Filters, nil
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) GetFiltersForFleetCount(name string) (int64, error) {
|
||||
pipe := mongo.Pipeline{
|
||||
{{"$match", bson.D{{"name", name}}}},
|
||||
{{"$project", bson.D{{
|
||||
"total", bson.D{{
|
||||
"$size", bson.D{{
|
||||
"$cond", bson.A{bson.D{{"$isArray", "$canbus.filters"}}, "$canbus.filters", []common.CANBus{}},
|
||||
}},
|
||||
}}}},
|
||||
}},
|
||||
}
|
||||
|
||||
var counter []count
|
||||
|
||||
err := c.Aggregate(pipe, &counter)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(counter) != 1 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return counter[0].Total, nil
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) AddFilterToFleet(name string, filter *common.CANFilter) error {
|
||||
m := bson.M{"name": name}
|
||||
u := bson.M{"$addToSet": bson.M{"canbus.filters": filter}}
|
||||
|
||||
_, err := c.UpdateOne(m, u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) UpdateFilterForFleet(name string, id string, filter *common.CANFilter) error {
|
||||
m := bson.M{
|
||||
"name": name,
|
||||
"canbus.filters.can_id": id,
|
||||
}
|
||||
u := bson.M{"$set": bson.M{
|
||||
"canbus.filters.$.interval": filter.Interval,
|
||||
"canbus.filters.$.edge_mask": filter.EdgeMask}}
|
||||
|
||||
_, err := c.UpdateOne(m, u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) DeleteFilterFromFleet(name string, id string) error {
|
||||
m := bson.M{"name": name}
|
||||
u := bson.M{"$pull": bson.M{"canbus.filters": bson.M{"can_id": id}}}
|
||||
|
||||
_, err := c.UpdateOne(m, u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FleetsCollection) GetCANBusForVehicle(vin string) (*Fleet, error) {
|
||||
pipe := mongo.Pipeline{
|
||||
{{"$match", bson.D{{"vehicles", vin}}}},
|
||||
{{"$unwind", bson.D{{"path", "$canbus.filters"}, {"preserveNullAndEmptyArrays", true}}}},
|
||||
{{"$group", bson.D{
|
||||
{"_id", nil},
|
||||
{"filters", bson.D{{"$push", "$canbus.filters"}}},
|
||||
{"enabled", bson.D{{"$max", "$canbus.enabled"}}},
|
||||
{"data_logger", bson.D{{"$max", "$canbus.data_logger"}}},
|
||||
{"mem_buff_size", bson.D{{"$min", "$canbus.mem_buff_size"}}},
|
||||
{"disk_buff_size", bson.D{{"$min", "$canbus.disk_buff_size"}}},
|
||||
}}},
|
||||
{{"$project", bson.D{
|
||||
{"canbus.filters", "$filters"},
|
||||
{"canbus.enabled", "$enabled"},
|
||||
{"canbus.data_logger", "$data_logger"},
|
||||
{"canbus.mem_buff_size", "$mem_buff_size"},
|
||||
{"canbus.disk_buff_size", "$disk_buff_size"},
|
||||
{"canbus.dtc_enabled", "$dtc_enabled"},
|
||||
}}},
|
||||
}
|
||||
|
||||
var fleets []Fleet
|
||||
err := c.Aggregate(pipe, &fleets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(fleets) != 1 {
|
||||
return nil, nil
|
||||
}
|
||||
theFleet := &fleets[0]
|
||||
if theFleet.CANBus.DTCEnabled == nil {
|
||||
theFleet.CANBus.DTCEnabled = elptr.ElPtr(false)
|
||||
}
|
||||
return theFleet, nil
|
||||
}
|
||||
Reference in New Issue
Block a user