Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
566
pkg/db/queries/updatemanifests.go
Normal file
566
pkg/db/queries/updatemanifests.go
Normal file
@@ -0,0 +1,566 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"fiskerinc.com/modules/common"
|
||||
"fiskerinc.com/modules/db"
|
||||
"fiskerinc.com/modules/logger"
|
||||
"fiskerinc.com/modules/validator"
|
||||
|
||||
"github.com/go-pg/pg/v10"
|
||||
"github.com/go-pg/pg/v10/orm"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type UpdateManifestsInterface interface {
|
||||
QueryBaseInterface
|
||||
Archive(ids []int64, active bool) (orm.Result, error)
|
||||
Count(filter common.UpdateManifest) (int, error)
|
||||
Delete(manifest *common.UpdateManifest) (orm.Result, error)
|
||||
Insert(manifest *common.UpdateManifest) (orm.Result, error)
|
||||
Select(filter *common.UpdateManifest, paging *PageQueryOptions) ([]common.UpdateManifest, error)
|
||||
SelectByVIN(vin string, paging *PageQueryOptions) ([]common.StatusManifest, error)
|
||||
Update(manifest *common.UpdateManifest) (orm.Result, error)
|
||||
Load(manifest *common.UpdateManifest) error
|
||||
Search(filter common.UpdateManifestSearch, paging *PageQueryOptions) ([]common.UpdateManifest, error)
|
||||
SearchCount(filter common.UpdateManifestSearch) (int, error)
|
||||
ECURollback(man *common.UpdateManifestECU, vin string) ([]*common.UpdateManifestECU, error)
|
||||
ECUInsert(manifest *common.UpdateManifestECU) (orm.Result, error)
|
||||
FileInsert(manifest *common.UpdateManifestFile) (orm.Result, error)
|
||||
AddSUMSVersion(manifest *common.UpdateManifest) (orm.Result, error)
|
||||
SelectFlashPackByVersion(versionNumber string) (manifest common.UpdateManifest, err error)
|
||||
}
|
||||
|
||||
// NewUpdateManifest returns UpdateManifestInterface.
|
||||
// mode allows to use more flexible requests.
|
||||
// If mode is nil, default mode is used.
|
||||
func NewUpdateManifest(mode UpdateManifestMode) UpdateManifestsInterface {
|
||||
if mode == nil {
|
||||
return &UpdateManifests{
|
||||
mode: DefaultMode{},
|
||||
}
|
||||
}
|
||||
|
||||
return &UpdateManifests{
|
||||
mode: mode,
|
||||
}
|
||||
}
|
||||
|
||||
type UpdateManifests struct {
|
||||
mode UpdateManifestMode
|
||||
QueryBase
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) Count(filter common.UpdateManifest) (int, error) {
|
||||
query := um.GetDBConn().Model((*common.UpdateManifest)(nil))
|
||||
|
||||
um.selectFilter(query, &filter)
|
||||
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) Delete(manifest *common.UpdateManifest) (orm.Result, error) {
|
||||
total := ORMResults{}
|
||||
|
||||
err := validator.ValidateIDField(manifest.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = um.Load(manifest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx, err := um.GetDBConn().Begin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = um.manifestDelete(tx, &total, manifest)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &total, err
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) Insert(manifest *common.UpdateManifest) (orm.Result, error) {
|
||||
total := ORMResults{}
|
||||
|
||||
tx, err := um.GetDBConn().Begin()
|
||||
if err != nil {
|
||||
err = errors.WithStack(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = um.manifestInsert(tx, &total, manifest)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
err = errors.WithStack(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
err = errors.WithStack(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &total, nil
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) ECUInsert(ecu *common.UpdateManifestECU) (orm.Result, error) {
|
||||
total := ORMResults{}
|
||||
|
||||
tx, err := um.GetDBConn().Begin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = um.ecuInsert(tx, &total, ecu)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &total, nil
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) FileInsert(file *common.UpdateManifestFile) (orm.Result, error) {
|
||||
total := ORMResults{}
|
||||
|
||||
tx, err := um.GetDBConn().Begin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = um.fileInsert(tx, &total, file)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &total, nil
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) Select(filter *common.UpdateManifest, paging *PageQueryOptions) ([]common.UpdateManifest, error) {
|
||||
manifests := []common.UpdateManifest{}
|
||||
query := um.GetDBConn().Model(&manifests)
|
||||
|
||||
um.selectFilter(query, filter)
|
||||
um.pageQuery(query, paging)
|
||||
|
||||
err := query.Select()
|
||||
|
||||
return manifests, errors.WithStack(err)
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) Archive(ids []int64, active bool) (orm.Result, error) {
|
||||
manifests := []common.UpdateManifest{}
|
||||
return um.resultWithStack(
|
||||
um.GetDBConn().Model(&manifests).
|
||||
Set("active = ?", active).
|
||||
Where("id IN (?)", pg.In(ids)).
|
||||
Update(),
|
||||
)
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) SelectByVIN(vin string, paging *PageQueryOptions) ([]common.StatusManifest, error) {
|
||||
manifests := []common.StatusManifest{}
|
||||
query := um.GetDBConn().Model(&manifests)
|
||||
query.
|
||||
ColumnExpr("status_manifest.*").
|
||||
ColumnExpr("car_updates.status as status").
|
||||
ColumnExpr("car_updates.updated_at as status_updated").
|
||||
ColumnExpr("status_manifest.created_at as manifest_created").
|
||||
Join("LEFT JOIN car_updates ON car_updates.update_manifest_id=status_manifest.id").
|
||||
Where("vin = ?", vin)
|
||||
|
||||
query = um.mode.SelectByVINCondition(query)
|
||||
query = um.pageQuery(query, paging)
|
||||
err := query.Select()
|
||||
|
||||
return manifests, errors.WithStack(err)
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) Update(manifest *common.UpdateManifest) (orm.Result, error) {
|
||||
err := validator.ValidateIDField(manifest.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := um.GetDBConn().Model(manifest).Column(
|
||||
"name",
|
||||
"release_notes",
|
||||
"type",
|
||||
"fingerprint",
|
||||
"rollback_enabled",
|
||||
"update_duration",
|
||||
"max_attempts",
|
||||
)
|
||||
if manifest.Active != nil {
|
||||
query = query.Column("active")
|
||||
}
|
||||
if manifest.Env != "" {
|
||||
query = query.Column("env")
|
||||
}
|
||||
if manifest.SUMS != "" {
|
||||
query = query.Column("sums")
|
||||
}
|
||||
|
||||
return query.WherePK().Update()
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) Load(manifest *common.UpdateManifest) error {
|
||||
query := um.GetDBConn().Model(manifest)
|
||||
|
||||
if manifest.ID > 0 {
|
||||
query.WherePK()
|
||||
} else if manifest.Name != "" && manifest.Version != "" {
|
||||
query.Where("name = ?name AND version = ?version")
|
||||
} else {
|
||||
return errors.New("no id, name or version")
|
||||
}
|
||||
|
||||
// For Magna, we will add the manifest type, then we will only get it when it is equal to two
|
||||
if manifest.ManifestType > 0 {
|
||||
query.Where("manifest_type = ?", manifest.ManifestType)
|
||||
}
|
||||
|
||||
if manifest.Env == "" {
|
||||
manifest.Env = common.EnvCurrent
|
||||
}
|
||||
|
||||
return um.mode.LoadRelations(query)
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) Search(filter common.UpdateManifestSearch, paging *PageQueryOptions) ([]common.UpdateManifest, error) {
|
||||
manifests := []common.UpdateManifest{}
|
||||
query := um.GetDBConn().Model(&manifests)
|
||||
|
||||
um.searchFilter(query, &filter)
|
||||
um.pageQuery(query, paging)
|
||||
|
||||
err := query.Select()
|
||||
|
||||
return manifests, errors.WithStack(err)
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) SearchCount(filter common.UpdateManifestSearch) (int, error) {
|
||||
query := um.GetDBConn().Model((*common.UpdateManifest)(nil))
|
||||
|
||||
um.searchFilter(query, &filter)
|
||||
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// Used to get rollbacks for ecu's
|
||||
func (um *UpdateManifests) ECURollback(man *common.UpdateManifestECU, vin string) (rollBackManifest []*common.UpdateManifestECU, err error) {
|
||||
// Use our new rollback system, if it fails return the old get for rollbacks
|
||||
// This may fail as the car_ecus system is a bit corrupted in data
|
||||
targetedRollback, err := um.getECURollbackSpecificToCar(man, vin)
|
||||
if err == nil && targetedRollback != nil {
|
||||
rollBackManifest = append(rollBackManifest, targetedRollback)
|
||||
return
|
||||
}
|
||||
|
||||
return um.getRollbacksListOfPossible(man)
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) getECURollbackSpecificToCar(man *common.UpdateManifestECU, vin string) (rollbackManifest *common.UpdateManifestECU, err error) {
|
||||
conn := um.GetDBConn()
|
||||
targetCarECU := common.CarECU{}
|
||||
targetCarECU.VIN = vin
|
||||
targetCarECU.ECU = man.ECU
|
||||
// Using the ecu and vin, get the latest carECU for that specific car
|
||||
err = conn.Model(&targetCarECU).
|
||||
Where("vin = ?", targetCarECU.VIN).
|
||||
Where("ecu = ?", targetCarECU.ECU).
|
||||
Where("version != 'unavailable'"). // We have so many of these though, like its not something that you can even roll back to
|
||||
Order("epoch_usec DESC").
|
||||
Limit(1).
|
||||
Select()
|
||||
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Msgf("failed to get car ecu for rollback for car %s ecu %s", vin, man.ECU)
|
||||
return
|
||||
}
|
||||
|
||||
if targetCarECU.Version == "" {
|
||||
logger.Warn().Interface("target car ecu", targetCarECU).Msgf("failed to fetch a previous ecu version for car %s ecu %s", vin, man.ECU)
|
||||
err = fmt.Errorf("getRollBackNew error")
|
||||
return
|
||||
}
|
||||
|
||||
targetManifest := common.UpdateManifestECU{}
|
||||
err = conn.Model(&targetManifest).
|
||||
Where("version = ?", targetCarECU.Version).
|
||||
Where("ecu = ?", targetCarECU.ECU).
|
||||
Select()
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Msgf("failed to get ecu rollback update manifest ecu for car %s", vin)
|
||||
return
|
||||
}
|
||||
if targetManifest.ID == 0 {
|
||||
logger.Warn().Interface("target ecu", targetCarECU).Msgf("failed to get ecu rollback update manifest ecu for car %s", vin)
|
||||
err = fmt.Errorf("getRollBackNew error")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) getRollbacksListOfPossible(man *common.UpdateManifestECU) (rollBackManifest []*common.UpdateManifestECU, err error) {
|
||||
var manifests []*common.UpdateManifestECU
|
||||
conn := um.GetDBConn()
|
||||
sub := conn.Model(&manifests).ColumnExpr("version, max(created_at)").
|
||||
Where("ecu = ?", man.ECU).
|
||||
Where("hw_versions = ?", pg.Array(man.HWVersions)).
|
||||
Where("version != ?", man.Version).
|
||||
Group("version")
|
||||
err = conn.
|
||||
Model(&manifests).
|
||||
With("sub", sub).
|
||||
Column("update_manifest_ecu.version", "id").
|
||||
Join("INNER JOIN sub ON update_manifest_ecu.version = sub.version AND "+
|
||||
"update_manifest_ecu.created_at = sub.max").
|
||||
Where("ecu = ?", man.ECU).
|
||||
Where("hw_versions = ?", pg.Array(man.HWVersions)).
|
||||
Where("update_manifest_ecu.version != ?", man.Version).
|
||||
Relation("Files").
|
||||
Relation("Files.WriteRegion").
|
||||
Relation("Files.EraseRegion").
|
||||
Order("version").
|
||||
Select()
|
||||
if err != nil {
|
||||
errors.WithMessagef(err, "failed to do ECURollback() for manifest_id %d on ECU %s id: %d", man.UpdateManifestID, man.ECU, man.ID)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) manifestDelete(operation db.Operation, resultsTotal *ORMResults, manifest *common.UpdateManifest) (orm.Result, error) {
|
||||
// Removed manifest.ecuDelete as the deletes are now propagated by the database
|
||||
result, err := um.resultWithStack(operation.Model(manifest).WherePK().Delete())
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resultsTotal, nil
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) manifestInsert(operation db.Operation, resultsTotal *ORMResults, manifest *common.UpdateManifest) (orm.Result, error) {
|
||||
result, err := um.resultWithStack(operation.Model(manifest).Insert())
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
resultsTotal.SetModel(result.Model())
|
||||
|
||||
if manifest.ECUs != nil {
|
||||
for i := range manifest.ECUs {
|
||||
ecu := manifest.ECUs[i]
|
||||
ecu.UpdateManifestID = manifest.ID
|
||||
result, err = um.ecuInsert(operation, resultsTotal, ecu)
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultsTotal, nil
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) ecuDelete(operation db.Operation, resultsTotal *ORMResults, ecu *common.UpdateManifestECU) (orm.Result, error) {
|
||||
if ecu.Files != nil {
|
||||
for i := range ecu.Files {
|
||||
file := ecu.Files[i]
|
||||
result, err := um.fileDelete(operation, resultsTotal, file)
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result, err := operation.Model(ecu).WherePK().Delete()
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resultsTotal, nil
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) ecuInsert(operation db.Operation, resultsTotal *ORMResults, ecu *common.UpdateManifestECU) (orm.Result, error) {
|
||||
result, err := um.resultWithStack(operation.Model(ecu).Insert())
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ecu.Files != nil {
|
||||
for i := range ecu.Files {
|
||||
file := ecu.Files[i]
|
||||
file.UpdateManifestECUID = ecu.ID
|
||||
result, err := um.fileInsert(operation, resultsTotal, file)
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultsTotal, nil
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) fileDelete(operation db.Operation, resultsTotal *ORMResults, file *common.UpdateManifestFile) (orm.Result, error) {
|
||||
result, err := um.resultWithStack(operation.Model(file).WherePK().Delete())
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
resultsTotal.SetModel(result.Model())
|
||||
|
||||
result, err = um.resultWithStack(operation.Model(&common.MemoryRegion{ID: file.WriteRegionID}).WherePK().Delete())
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if file.EraseRegionID != 0 {
|
||||
result, err = um.resultWithStack(operation.Model(&common.MemoryRegion{ID: file.EraseRegionID}).WherePK().Delete())
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
result, err = um.fileKeyDelete(operation, resultsTotal, file)
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resultsTotal, nil
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) fileKeyDelete(operation db.Operation, resultsTotal *ORMResults, file *common.UpdateManifestFile) (orm.Result, error) {
|
||||
fk := &common.FileKey{FileID: file.FileID}
|
||||
result, err := um.resultWithStack(operation.Model(fk).WherePK().Delete())
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
return resultsTotal, err
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) fileInsert(operation db.Operation, resultsTotal *ORMResults, file *common.UpdateManifestFile) (orm.Result, error) {
|
||||
result, err := um.resultWithStack(operation.Model(&file.WriteRegion).Insert())
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
file.WriteRegionID = file.WriteRegion.ID
|
||||
|
||||
if file.EraseRegion != nil {
|
||||
result, err = um.resultWithStack(operation.Model(file.EraseRegion).Insert())
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
file.EraseRegionID = file.EraseRegion.ID
|
||||
}
|
||||
|
||||
result, err = um.resultWithStack(operation.Model(file).Insert())
|
||||
if um.hasErrorResult(resultsTotal, result, err) {
|
||||
return nil, err
|
||||
}
|
||||
resultsTotal.SetModel(result.Model())
|
||||
|
||||
return resultsTotal, nil
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) selectFilter(query *orm.Query, filter *common.UpdateManifest) {
|
||||
if filter.ID > 0 {
|
||||
query.Where("id = ?", filter.ID)
|
||||
}
|
||||
|
||||
if filter.Name != "" {
|
||||
query.Where("name = ?", filter.Name)
|
||||
}
|
||||
|
||||
if filter.Version != "" {
|
||||
query.Where("version = ?", filter.Version)
|
||||
}
|
||||
|
||||
if filter.Description != "" {
|
||||
query.Where("description LIKE ?", filter.Description)
|
||||
}
|
||||
|
||||
if filter.ManifestType > 0 {
|
||||
query.Where("manifest_type = ?", filter.ManifestType)
|
||||
}
|
||||
|
||||
if filter.Active != nil {
|
||||
query.Where("active = ?", filter.Active)
|
||||
}
|
||||
|
||||
if filter.Country != "" {
|
||||
query.Where("country = ? or country is null", filter.Country)
|
||||
}
|
||||
|
||||
if filter.PowerTrain != "" {
|
||||
query.Where("powertrain = ? or powertrain is null", filter.PowerTrain)
|
||||
}
|
||||
|
||||
if filter.Restraint != "" {
|
||||
query.Where("restraint = ? or restraint is null", filter.Restraint)
|
||||
}
|
||||
|
||||
if filter.Model != "" {
|
||||
query.Where("model = ? or model is null", filter.Model)
|
||||
}
|
||||
|
||||
if filter.Trim != "" {
|
||||
query.Where("trim = ? or trim is null", filter.Trim)
|
||||
}
|
||||
|
||||
if filter.Year != 0 {
|
||||
query.Where("year = ? or year is null", filter.Year)
|
||||
}
|
||||
|
||||
if filter.BodyType != "" {
|
||||
query.Where("body_type = ? or body_type is null", filter.BodyType)
|
||||
}
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) searchFilter(query *orm.Query, filter *common.UpdateManifestSearch) {
|
||||
if filter.Search != "" {
|
||||
query.Where("document @@ plainto_tsquery(?)", filter.Search)
|
||||
}
|
||||
|
||||
if filter.ManifestType == common.SoftwareUpdateType {
|
||||
filter.ManifestType = 0
|
||||
query.WhereInMulti("manifest_type in (?)", common.SoftwareUpdateType, common.MagnaManifestUpdateType, common.AftersalesUpdateType)
|
||||
}
|
||||
|
||||
um.selectFilter(query, &filter.UpdateManifest)
|
||||
}
|
||||
|
||||
func (um *UpdateManifests) AddSUMSVersion(manifest *common.UpdateManifest) (orm.Result, error) {
|
||||
return um.resultWithStack(um.GetDBConn().Model(manifest).Column("sums").Where("id = ?id AND sums IS NULL").Update())
|
||||
}
|
||||
|
||||
// Given a flashpack version number: 14.4, we will return the corresponding flashpack
|
||||
func (um *UpdateManifests) SelectFlashPackByVersion(versionNumber string) (manifest common.UpdateManifest, err error) {
|
||||
// Prepare for Like Statement
|
||||
versionNumber = "%" + versionNumber
|
||||
err = um.GetDBConn().Model(&manifest).Where("manifest_type = ? AND name LIKE ?", common.AsBuiltUpdateType, versionNumber).Limit(1).Select()
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user