422 lines
11 KiB
Go
422 lines
11 KiB
Go
package mongo
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/fiskerinc/cloud-services/pkg/common"
|
|
"github.com/fiskerinc/cloud-services/pkg/db/queries"
|
|
|
|
"github.com/fiskerinc/cloud-services/pkg/utils/elptr"
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
)
|
|
|
|
// Vehicle serves as the schema for Vehicles collection
|
|
type Vehicle struct {
|
|
VIN string `json:"vin" bson:"vin"`
|
|
LogLevel common.LogLevel `json:"log_level" bson:"log_level"`
|
|
DLTEnabled bool `json:"dlt_enabled" bson:"dlt_enabled"`
|
|
DLTLevel int `json:"dlt_level,omitempty" bson:"dlt_level,omitempty"`
|
|
CANBus common.CANBus `json:"canbus" bson:"canbus"`
|
|
IDPSEnabled bool `json:"idps_enabled" bson:"idps_enabled"`
|
|
DebugMask string `json:"debug_mask,omitempty" bson:"debug_mask,omitempty"`
|
|
Fleets []Fleet `json:"fleets" bson:"fleets,omitempty"`
|
|
search string `json:"-" bson:"-"`
|
|
}
|
|
|
|
func (f *Vehicle) SetSearchQuery(search string) {
|
|
f.search = search
|
|
}
|
|
|
|
func (f *Vehicle) SearchQuery() string {
|
|
return f.search
|
|
}
|
|
|
|
type VehicleCANBusWithFleet struct {
|
|
CANBus struct {
|
|
Filters []common.CANFilterWithFleet `json:"filters,omitempty" bson:"filters,omitempty"`
|
|
} `json:"canbus" bson:"canbus"`
|
|
}
|
|
|
|
// NewVehiclesCollection is the construct for Vehicles and utilizes the same mongo connection
|
|
func NewVehiclesCollection(c CollectionInterface) VehiclesCollectionInterface {
|
|
return &VehiclesCollection{c}
|
|
}
|
|
|
|
type VehiclesCollectionInterface interface {
|
|
AddVehicle(vehicle *Vehicle) error
|
|
FindVehicle(filter *Vehicle) (*Vehicle, error)
|
|
UpdateVehicle(vehicle *Vehicle) error
|
|
DeleteVehicle(filter *Vehicle) error
|
|
|
|
AddFilterToVehicle(vin string, filter *common.CANFilter) error
|
|
GetFiltersForVehicle(vin string, options *queries.PageQueryOptions) ([]common.CANFilterWithFleet, error)
|
|
UpdateFilterForVehicle(vin string, id string, filter *common.CANFilter) error
|
|
DeleteFilterForVehicle(vin string, id string) error
|
|
|
|
GetFilterCountForVehicle(vin string) (int64, error)
|
|
UpdateFiltersForVehicle(vin string, filters []common.CANFilter) error
|
|
|
|
GetFleetsForVehicle(
|
|
vin, fleetName string,
|
|
options *queries.PageQueryOptions,
|
|
) ([]string, error)
|
|
GetFleetCountForVehicle(
|
|
vin, fleetName string,
|
|
) (int64, error)
|
|
|
|
CollectionInterface
|
|
}
|
|
|
|
// VehiclesCollection is the client for the collection
|
|
type VehiclesCollection struct {
|
|
CollectionInterface
|
|
}
|
|
|
|
func (c *VehiclesCollection) AddVehicle(vehicle *Vehicle) error {
|
|
vehicle.VIN = strings.ToUpper(vehicle.VIN)
|
|
_, err := c.InsertOne(vehicle)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *VehiclesCollection) FindVehicle(filter *Vehicle) (*Vehicle, error) {
|
|
|
|
m := bson.M{"vin": filter.VIN}
|
|
|
|
v := &Vehicle{}
|
|
err := c.FindOne(m, v, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if v.CANBus.DTCEnabled == nil {
|
|
v.CANBus.DTCEnabled = elptr.ElPtr(false)
|
|
}
|
|
|
|
return v, nil
|
|
}
|
|
|
|
func (c *VehiclesCollection) UpdateVehicle(vehicle *Vehicle) error {
|
|
m := bson.M{"vin": vehicle.VIN}
|
|
u := bson.M{"$set": bson.M{
|
|
"canbus.enabled": vehicle.CANBus.Enabled,
|
|
"canbus.data_logger": vehicle.CANBus.DataLogger,
|
|
"canbus.dtc_enabled": vehicle.CANBus.DTCEnabled,
|
|
"canbus.mem_buff_size": vehicle.CANBus.MemBuffSize,
|
|
"canbus.disk_buff_size": vehicle.CANBus.DiskBuffSize,
|
|
"log_level": vehicle.LogLevel,
|
|
"debug_mask": vehicle.DebugMask,
|
|
"dlt_enabled": vehicle.DLTEnabled,
|
|
"dlt_level": vehicle.DLTLevel,
|
|
"idps_enabled": vehicle.IDPSEnabled,
|
|
}}
|
|
|
|
_, err := c.UpdateOne(m, u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *VehiclesCollection) DeleteVehicle(vehicle *Vehicle) error {
|
|
m := bson.M{"vin": vehicle.VIN}
|
|
|
|
err := c.DeleteOne(m)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *VehiclesCollection) AddFilterToVehicle(vin string, filter *common.CANFilter) error {
|
|
m := bson.M{"vin": vin}
|
|
u := bson.M{"$addToSet": bson.M{"canbus.filters": filter}}
|
|
|
|
_, err := c.UpdateOne(m, u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *VehiclesCollection) filtersForVehiclePipe(
|
|
vin string,
|
|
) mongo.Pipeline {
|
|
// This pipeline works in a following way:
|
|
// 1. matches the vin from vehicles.
|
|
// 2. checks whether the canbus.filters is array, if not creates an empty one.
|
|
// 3. does lookup in fleets collection
|
|
// 3.1. checks whether fleets.vehicles is array and
|
|
// 3.2. matches a current vin with the vins in fleets.vehicles
|
|
// 3.3. checks if the canbus.filters of the matching fleet is array, if not creates an empty one
|
|
// 3.4. names it as matches
|
|
// 4. creates transformed matches as cfilters
|
|
// 4.1. goes through every canbus filter of the matches
|
|
// 4.2. concatenates them through creating a new object with a "fleet" field representing fleet name
|
|
// 4.3. eventually named as cfilters
|
|
// 5. merges cfilters and canbus.filters selected as "filters" eventually
|
|
// 6. unwinds filters
|
|
// 7. sorts the unwinded through filters.can_id
|
|
return mongo.Pipeline{
|
|
{{"$match", bson.D{{"vin", vin}}}},
|
|
{{"$project", bson.D{
|
|
{"canbus.filters", bson.D{
|
|
{"$cond",
|
|
bson.A{bson.D{{"$isArray", "$canbus.filters"}}, "$canbus.filters", bson.A{}},
|
|
},
|
|
}},
|
|
{"vin", 1}}}},
|
|
{{"$lookup",
|
|
bson.D{
|
|
{"from", "fleets"},
|
|
{"let", bson.D{{"vin", "$vin"}}},
|
|
{"pipeline", bson.A{bson.D{
|
|
{"$match", bson.D{
|
|
{"$expr", bson.D{
|
|
{"$and", bson.A{
|
|
bson.D{{"$isArray", "$vehicles"}},
|
|
bson.D{{"$in", bson.A{"$$vin", "$vehicles"}}},
|
|
}}}}}}}, bson.D{
|
|
{"$project", bson.D{
|
|
{"canbus.filters", bson.D{
|
|
{"$cond", bson.A{
|
|
bson.D{{"$isArray", "$canbus.filters"}},
|
|
"$canbus.filters",
|
|
bson.A{},
|
|
}}}},
|
|
{"name", 1},
|
|
}}}}},
|
|
{"as", "matches"}}}},
|
|
{{"$addFields", bson.D{
|
|
{"cfilters", bson.D{
|
|
{"$reduce", bson.D{
|
|
{"input", "$matches"},
|
|
{"initialValue", bson.A{}},
|
|
{"in", bson.D{
|
|
{"$concatArrays", bson.A{
|
|
"$$value", bson.D{
|
|
{"$map", bson.D{
|
|
{"input", "$$this.canbus.filters"},
|
|
{"as", "cfilter"},
|
|
{"in", bson.D{
|
|
{"fleet", "$$this.name"},
|
|
{"can_id", "$$cfilter.can_id"},
|
|
{"interval", "$$cfilter.interval"},
|
|
{"edge_mask", "$$cfilter.edge_mask"}}},
|
|
}}}}}}}}}}}}}},
|
|
{{"$project", bson.D{
|
|
{"filters", bson.D{
|
|
{"$concatArrays", bson.A{
|
|
"$canbus.filters",
|
|
"$cfilters",
|
|
}}}}}}},
|
|
{{"$unwind", "$filters"}},
|
|
{{"$sort", bson.D{{"filters.can_id", 1}}}},
|
|
}
|
|
}
|
|
|
|
func (c *VehiclesCollection) GetFiltersForVehicle(
|
|
vin string,
|
|
options *queries.PageQueryOptions,
|
|
) ([]common.CANFilterWithFleet, error) {
|
|
preProc := c.filtersForVehiclePipe(vin)
|
|
postProc := mongo.Pipeline{{
|
|
{"$group", bson.D{
|
|
{"_id", "$_id"},
|
|
{"filters", bson.D{{"$push", "$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 vehicles []VehicleCANBusWithFleet
|
|
err := c.Aggregate(pipe, &vehicles)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(vehicles) != 1 {
|
|
return []common.CANFilterWithFleet{}, nil
|
|
}
|
|
return vehicles[0].CANBus.Filters, nil
|
|
}
|
|
|
|
func (c *VehiclesCollection) UpdateFilterForVehicle(vin string, id string, filter *common.CANFilter) error {
|
|
m := bson.M{
|
|
"vin": vin,
|
|
"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 *VehiclesCollection) DeleteFilterForVehicle(vin string, id string) error {
|
|
m := bson.M{"vin": vin}
|
|
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 *VehiclesCollection) GetFilterCountForVehicle(vin string) (int64, error) {
|
|
pipe := append(c.filtersForVehiclePipe(vin), mongo.Pipeline{
|
|
{{"$group", bson.D{
|
|
{"_id", "$_id"},
|
|
{"filters", bson.D{{"$push", "$filters"}}}}}},
|
|
{{"$project", bson.D{{"canbus.filters", "$filters"}}}},
|
|
{{"$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 *VehiclesCollection) UpdateFiltersForVehicle(vin string, filters []common.CANFilter) error {
|
|
m := bson.M{"vin": vin}
|
|
u := bson.M{"$set": bson.M{"canbus.filters": filters}}
|
|
|
|
_, err := c.UpdateOne(m, u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *VehiclesCollection) getFleetsForVehiclePipe(vin, fleetName string) mongo.Pipeline {
|
|
ofFleet := bson.E{}
|
|
if fleetName != "" {
|
|
ofFleet = bson.E{"name", fleetName}
|
|
}
|
|
|
|
return mongo.Pipeline{
|
|
{{"$match", bson.D{{"vin", vin}}}},
|
|
{{"$project", bson.D{{"vin", 1}}}},
|
|
{{"$lookup", bson.D{
|
|
{"from", "fleets"},
|
|
{"let", bson.D{{"vin", "$vin"}}},
|
|
{"pipeline", bson.A{bson.D{
|
|
{"$match", bson.D{
|
|
{"$expr", bson.D{
|
|
{"$and", bson.A{
|
|
bson.D{{"$isArray", "$vehicles"}},
|
|
bson.D{{"$in", bson.A{"$$vin", "$vehicles"}}},
|
|
}}}}, ofFleet,
|
|
}}}, bson.D{
|
|
{"$project", bson.D{{"name", 1}}}}}},
|
|
{"as", "fleets"}}}},
|
|
{{"$project", bson.D{
|
|
{"fleets", bson.D{
|
|
{"$map", bson.D{
|
|
{"input", "$fleets"},
|
|
{"as", "fleet"},
|
|
{"in", "$$fleet.name"}}}}}}}},
|
|
{{"$unwind", "$fleets"}}}
|
|
}
|
|
|
|
func (c *VehiclesCollection) GetFleetCountForVehicle(
|
|
vin, fleetName string,
|
|
) (int64, error) {
|
|
pipe := append(c.getFleetsForVehiclePipe(vin, fleetName), mongo.Pipeline{
|
|
{{"$group", bson.D{
|
|
{"_id", "$_id"},
|
|
{"fleets", bson.D{{"$push", "$fleets"}}}}}},
|
|
{{"$project", bson.D{{
|
|
"total", bson.D{{
|
|
"$size", bson.D{{
|
|
"$cond", bson.A{bson.D{{"$isArray", "$fleets"}}, "$fleets", []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 *VehiclesCollection) GetFleetsForVehicle(
|
|
vin, fleetName string,
|
|
options *queries.PageQueryOptions,
|
|
) ([]string, error) {
|
|
preProc := c.getFleetsForVehiclePipe(vin, fleetName)
|
|
|
|
postProc := mongo.Pipeline{{
|
|
{"$group", bson.D{
|
|
{"_id", "$_id"},
|
|
{"fleets", bson.D{{"$push", "$fleets"}}}}}}}
|
|
|
|
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 []struct {
|
|
Fleets []string `bson:"fleets"`
|
|
}
|
|
err := c.Aggregate(pipe, &fleets)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(fleets) != 1 {
|
|
return []string{}, nil
|
|
}
|
|
return fleets[0].Fleets, nil
|
|
}
|