2025-02-14 10:56:24 +00:00
|
|
|
package queryupdate
|
2025-01-03 13:41:07 +00:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2025-01-23 14:56:20 +00:00
|
|
|
"errors"
|
2025-01-03 13:41:07 +00:00
|
|
|
"fmt"
|
2025-02-11 15:22:59 +00:00
|
|
|
"log/slog"
|
2025-03-05 12:05:46 +00:00
|
|
|
|
2025-02-14 10:56:24 +00:00
|
|
|
queryversionsyncrunner "queryorchestration/api/queryVersionSyncRunner"
|
2025-01-20 13:31:48 +00:00
|
|
|
"queryorchestration/internal/database/repository"
|
2025-02-14 10:56:24 +00:00
|
|
|
"queryorchestration/internal/query"
|
2025-01-29 11:52:37 +00:00
|
|
|
resultprocessor "queryorchestration/internal/query/result/processor"
|
2025-01-17 12:00:32 +00:00
|
|
|
contextfull "queryorchestration/internal/query/types/contextFull"
|
|
|
|
|
jsonextractor "queryorchestration/internal/query/types/jsonExtractor"
|
2025-02-14 10:56:24 +00:00
|
|
|
"queryorchestration/internal/serviceconfig/queue"
|
2025-02-11 15:22:59 +00:00
|
|
|
"queryorchestration/internal/validation"
|
2025-01-20 13:31:48 +00:00
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
2025-01-03 13:41:07 +00:00
|
|
|
)
|
|
|
|
|
|
2025-01-29 11:52:37 +00:00
|
|
|
func (s *Service) Update(ctx context.Context, entity *resultprocessor.Update) error {
|
2025-02-14 10:56:24 +00:00
|
|
|
current, err := s.svc.Query.Get(ctx, entity.ID)
|
2025-01-03 13:41:07 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-20 13:31:48 +00:00
|
|
|
err = s.normalizeUpdate(ctx, current, entity)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = s.submitUpdate(ctx, current, entity)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-14 10:56:24 +00:00
|
|
|
err = s.informUpdate(ctx, entity)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-20 13:31:48 +00:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-14 10:56:24 +00:00
|
|
|
func (s *Service) informUpdate(ctx context.Context, entity *resultprocessor.Update) error {
|
|
|
|
|
if entity.ActiveVersion == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return s.cfg.SendToQueue(ctx, &queue.SendParams{
|
|
|
|
|
QueueURL: s.cfg.GetQueryVersionSyncURL(),
|
|
|
|
|
Body: queryversionsyncrunner.Body{
|
2025-04-02 18:50:03 +00:00
|
|
|
QueryID: entity.ID,
|
2025-02-14 10:56:24 +00:00
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Service) normalizeUpdateRequiredQueryIDs(ctx context.Context, current *query.Query, entity query.RequiredQueryIDs) error {
|
|
|
|
|
err := s.svc.Query.NormalizeQueryIDs(ctx, entity)
|
2025-02-11 15:22:59 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if entity.GetRequiredQueryIDs() == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
createsloop, err := s.cfg.GetDBQueries().IsQueryInDependencyTree(ctx, &repository.IsQueryInDependencyTreeParams{
|
2025-03-20 11:06:41 +00:00
|
|
|
Queryid: ¤t.ID,
|
|
|
|
|
Requiredqueryids: *entity.GetRequiredQueryIDs(),
|
2025-02-11 15:22:59 +00:00
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
} else if createsloop {
|
|
|
|
|
return errors.New("required ids create a loop")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addIDs := getSetDifference(entity.GetRequiredQueryIDs(), current.RequiredQueryIDs)
|
|
|
|
|
removeIDs := getSetDifference(current.RequiredQueryIDs, entity.GetRequiredQueryIDs())
|
|
|
|
|
|
|
|
|
|
if len(addIDs) == 0 && len(removeIDs) == 0 {
|
|
|
|
|
entity.SetRequiredQueryIDs(nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-14 10:56:24 +00:00
|
|
|
func (s *Service) normalizeUpdate(ctx context.Context, current *query.Query, entity *resultprocessor.Update) error {
|
|
|
|
|
err := s.svc.Query.NormalizeActiveVersion(current, entity)
|
2025-01-20 13:31:48 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-11 15:22:59 +00:00
|
|
|
err = s.normalizeUpdateRequiredQueryIDs(ctx, current, entity)
|
2025-01-20 13:31:48 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-14 10:56:24 +00:00
|
|
|
err = s.svc.Query.NormalizeConfig(entity)
|
2025-02-11 15:22:59 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
2025-01-23 14:56:20 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-11 15:22:59 +00:00
|
|
|
activeVersionName, err := validation.GetFieldName(entity, entity.ActiveVersion)
|
2025-01-20 13:31:48 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-11 15:22:59 +00:00
|
|
|
if (entity.ActiveVersion == nil || *entity.ActiveVersion == current.LatestVersion+1) &&
|
|
|
|
|
validation.AreAllPointersNilExcept(entity, activeVersionName) {
|
2025-01-23 14:56:20 +00:00
|
|
|
return errors.New("no changes")
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-03 16:00:36 +00:00
|
|
|
validator, err := s.getUpdator(current.Type)
|
2025-01-03 13:41:07 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-14 10:56:24 +00:00
|
|
|
err = validator.Validate(ctx, query.ParseQuery(current), entity)
|
2025-01-03 13:41:07 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-20 13:31:48 +00:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-14 10:56:24 +00:00
|
|
|
func (s *Service) submitUpdate(ctx context.Context, current *query.Query, entity *resultprocessor.Update) error {
|
2025-01-31 13:43:55 +00:00
|
|
|
err := s.cfg.ExecuteDBTransaction(ctx, func(ctx context.Context, q *repository.Queries) error {
|
2025-03-20 11:06:41 +00:00
|
|
|
id := entity.ID
|
2025-01-31 13:43:55 +00:00
|
|
|
|
2025-02-14 18:43:26 +00:00
|
|
|
activeName, err := validation.GetFieldName(entity, entity.ActiveVersion)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
onlyactive := validation.AreAllPointersNilExcept(entity, activeName)
|
|
|
|
|
|
2025-02-17 14:30:37 +00:00
|
|
|
var latestVersion int32
|
2025-02-14 18:43:26 +00:00
|
|
|
if !onlyactive {
|
2025-02-17 14:30:37 +00:00
|
|
|
latestVersion, err = q.AddLatestQueryVersion(ctx, id)
|
2025-02-14 18:43:26 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if entity.ActiveVersion != nil {
|
|
|
|
|
err := q.AddActiveQueryVersion(ctx, &repository.AddActiveQueryVersionParams{
|
|
|
|
|
Queryid: id,
|
|
|
|
|
Versionid: *entity.ActiveVersion,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-14 10:56:24 +00:00
|
|
|
if entity.RequiredQueryIDs != nil {
|
|
|
|
|
addIDs := getSetDifference(entity.RequiredQueryIDs, current.RequiredQueryIDs)
|
|
|
|
|
for _, qID := range addIDs {
|
|
|
|
|
err := q.AddRequiredQuery(ctx, &repository.AddRequiredQueryParams{
|
|
|
|
|
Queryid: id,
|
2025-03-20 11:06:41 +00:00
|
|
|
Requiredqueryid: qID,
|
2025-02-14 10:56:24 +00:00
|
|
|
Addedversion: latestVersion,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2025-01-31 13:43:55 +00:00
|
|
|
}
|
2025-01-20 13:31:48 +00:00
|
|
|
|
2025-02-14 10:56:24 +00:00
|
|
|
removeIDs := getSetDifference(current.RequiredQueryIDs, entity.RequiredQueryIDs)
|
|
|
|
|
for _, qID := range removeIDs {
|
|
|
|
|
err := q.RemoveRequiredQuery(ctx, &repository.RemoveRequiredQueryParams{
|
|
|
|
|
Queryid: id,
|
2025-03-20 11:06:41 +00:00
|
|
|
Requiredqueryid: qID,
|
2025-02-14 10:56:24 +00:00
|
|
|
Removedversion: &latestVersion,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2025-01-31 13:43:55 +00:00
|
|
|
}
|
2025-01-20 13:31:48 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-31 13:43:55 +00:00
|
|
|
if entity.Config != nil && *entity.Config != "" {
|
2025-02-17 14:30:37 +00:00
|
|
|
err = q.SetQueryConfig(ctx, &repository.SetQueryConfigParams{
|
2025-01-31 13:43:55 +00:00
|
|
|
Queryid: id,
|
|
|
|
|
Config: []byte(*entity.Config),
|
|
|
|
|
Addedversion: latestVersion,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2025-01-20 13:31:48 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-11 15:22:59 +00:00
|
|
|
slog.Debug("query updated", "update", *entity)
|
|
|
|
|
|
2025-01-31 13:43:55 +00:00
|
|
|
return nil
|
2025-01-23 14:56:20 +00:00
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
2025-01-20 13:31:48 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-06 13:30:20 +00:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-20 13:31:48 +00:00
|
|
|
func getSetDifference(setA *[]uuid.UUID, setB *[]uuid.UUID) []uuid.UUID {
|
|
|
|
|
if setA == nil {
|
|
|
|
|
return []uuid.UUID{}
|
|
|
|
|
} else if setB == nil {
|
|
|
|
|
return *setA
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diff := []uuid.UUID{}
|
|
|
|
|
for _, q := range *setA {
|
|
|
|
|
isFound := false
|
|
|
|
|
for _, eq := range *setB {
|
|
|
|
|
if q == eq {
|
|
|
|
|
isFound = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !isFound {
|
|
|
|
|
diff = append(diff, q)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return diff
|
2025-01-03 13:41:07 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-29 11:52:37 +00:00
|
|
|
func (s *Service) getUpdator(qType resultprocessor.Type) (resultprocessor.Updator, error) {
|
2025-01-03 13:41:07 +00:00
|
|
|
switch qType {
|
2025-01-29 11:52:37 +00:00
|
|
|
case resultprocessor.TypeJsonExtractor:
|
2025-01-31 13:43:55 +00:00
|
|
|
return jsonextractor.NewUpdator(), nil
|
2025-01-29 11:52:37 +00:00
|
|
|
case resultprocessor.TypeContextFull:
|
2025-01-31 13:43:55 +00:00
|
|
|
return contextfull.NewUpdator(), nil
|
2025-01-03 13:41:07 +00:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("attempting to process invalid query type")
|
|
|
|
|
}
|
|
|
|
|
}
|