Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
421
pkg/mongo/vehicles.go
Normal file
421
pkg/mongo/vehicles.go
Normal file
@@ -0,0 +1,421 @@
|
||||
package mongo
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"fiskerinc.com/modules/common"
|
||||
"fiskerinc.com/modules/db/queries"
|
||||
|
||||
"fiskerinc.com/modules/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
|
||||
}
|
||||
Reference in New Issue
Block a user