Merged in feature/update (pull request #27)
Query Update * baselineupdate * baseupdateplusmodelupdates * passtests * somemoresubmittesting * testinnerfunctions * readmeandinstall * cleanerstartup * readmeplusdeps * tidyatrighttime * validatetests * normalizedontvalidate * abitofzenormalizationcleanup * addunitstestforhelperfuns * normalizeactiveversiontestas
This commit is contained in:
+52
-21
@@ -14,12 +14,7 @@ import (
|
||||
)
|
||||
|
||||
func (s *Service) Create(ctx context.Context, entity *queryprocessor.Create) (uuid.UUID, error) {
|
||||
validator, err := s.getCreator(entity.Type)
|
||||
if err != nil {
|
||||
return uuid.Nil, err
|
||||
}
|
||||
|
||||
err = validator.Validate(ctx, entity)
|
||||
err := s.normalizeCreate(ctx, entity)
|
||||
if err != nil {
|
||||
return uuid.Nil, err
|
||||
}
|
||||
@@ -32,6 +27,30 @@ func (s *Service) Create(ctx context.Context, entity *queryprocessor.Create) (uu
|
||||
return id, err
|
||||
}
|
||||
|
||||
func (s *Service) normalizeCreate(ctx context.Context, entity *queryprocessor.Create) error {
|
||||
err := s.normalizeQueryIDs(ctx, entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.normalizeConfig(entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
validator, err := s.getCreator(entity.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = validator.Validate(ctx, entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) submitCreate(ctx context.Context, entity *queryprocessor.Create) (uuid.UUID, error) {
|
||||
query, err := parseCreateQuery(entity)
|
||||
if err != nil {
|
||||
@@ -53,21 +72,23 @@ func (s *Service) submitCreate(ctx context.Context, entity *queryprocessor.Creat
|
||||
return uuid.Nil, err
|
||||
}
|
||||
|
||||
for _, reqQuery := range query.RequiredQueryIDs {
|
||||
err = qtx.CreateRequiredQuery(ctx, &repository.CreateRequiredQueryParams{
|
||||
Queryid: dbID,
|
||||
Requiredqueryid: reqQuery,
|
||||
Addedversion: 1,
|
||||
})
|
||||
if err != nil {
|
||||
return uuid.Nil, err
|
||||
if query.RequiredQueryIDs != nil {
|
||||
for _, reqQuery := range *query.RequiredQueryIDs {
|
||||
err = qtx.AddRequiredQuery(ctx, &repository.AddRequiredQueryParams{
|
||||
Queryid: dbID,
|
||||
Requiredqueryid: reqQuery,
|
||||
Addedversion: 1,
|
||||
})
|
||||
if err != nil {
|
||||
return uuid.Nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if query.Config != nil && string(query.Config) != "" {
|
||||
err = qtx.CreateQueryConfig(ctx, &repository.CreateQueryConfigParams{
|
||||
if query.Config != nil && string(*query.Config) != "" {
|
||||
err = qtx.AddQueryConfig(ctx, &repository.AddQueryConfigParams{
|
||||
Queryid: dbID,
|
||||
Config: query.Config,
|
||||
Config: *query.Config,
|
||||
Addedversion: 1,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -99,8 +120,8 @@ func (s *Service) getCreator(qType queryprocessor.Type) (queryprocessor.Creator,
|
||||
|
||||
type createQuery struct {
|
||||
Type repository.Querytype
|
||||
RequiredQueryIDs []pgtype.UUID
|
||||
Config []byte
|
||||
RequiredQueryIDs *[]pgtype.UUID
|
||||
Config *[]byte
|
||||
}
|
||||
|
||||
func parseCreateQuery(q *queryprocessor.Create) (*createQuery, error) {
|
||||
@@ -109,11 +130,21 @@ func parseCreateQuery(q *queryprocessor.Create) (*createQuery, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reqIDs := database.MustToDBUUIDArray(q.RequiredQueryIDs)
|
||||
var reqIDs *[]pgtype.UUID
|
||||
if q.RequiredQueryIDs != nil {
|
||||
tIDs := database.MustToDBUUIDArray(*q.RequiredQueryIDs)
|
||||
reqIDs = &tIDs
|
||||
}
|
||||
|
||||
var cfg *[]byte
|
||||
if q.Config != nil {
|
||||
tC := []byte(*q.Config)
|
||||
cfg = &tC
|
||||
}
|
||||
|
||||
return &createQuery{
|
||||
Type: t,
|
||||
RequiredQueryIDs: reqIDs,
|
||||
Config: []byte(q.Config),
|
||||
Config: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package query_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/query"
|
||||
@@ -32,10 +33,10 @@ func TestCreate(t *testing.T) {
|
||||
q := query.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: config,
|
||||
Config: &config,
|
||||
}
|
||||
create := &queryprocessor.Create{
|
||||
Type: q.Type,
|
||||
@@ -46,16 +47,20 @@ func TestCreate(t *testing.T) {
|
||||
dbType, err := queryprocessor.ToDBQueryType(create.Type)
|
||||
assert.Nil(t, err)
|
||||
|
||||
pool.ExpectQuery("name: AllQueriesExist :one").WithArgs(database.MustToDBUUIDArray(*create.RequiredQueryIDs)).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"all_exist"}).AddRow(true),
|
||||
)
|
||||
|
||||
pool.ExpectBeginTx(pgx.TxOptions{})
|
||||
pool.ExpectQuery("name: CreateQuery :one").WithArgs(dbType).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).
|
||||
AddRow(database.MustToDBUUID(q.ID)),
|
||||
)
|
||||
for _, req := range create.RequiredQueryIDs {
|
||||
pool.ExpectExec("name: CreateRequiredQuery :exec").WithArgs(database.MustToDBUUID(q.ID), database.MustToDBUUID(req), int32(1)).
|
||||
for _, req := range *create.RequiredQueryIDs {
|
||||
pool.ExpectExec("name: AddRequiredQuery :exec").WithArgs(database.MustToDBUUID(q.ID), database.MustToDBUUID(req), int32(1)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
}
|
||||
pool.ExpectExec("name: CreateQueryConfig :exec").WithArgs(database.MustToDBUUID(q.ID), []byte(create.Config), int32(1)).
|
||||
pool.ExpectExec("name: AddQueryConfig :exec").WithArgs(database.MustToDBUUID(q.ID), []byte(*create.Config), int32(1)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectCommit()
|
||||
|
||||
@@ -63,3 +68,74 @@ func TestCreate(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, q.ID, id)
|
||||
}
|
||||
|
||||
func TestCreateMinimal(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
pool, err := pgxmock.NewPool()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open pgxmock database: %v", err)
|
||||
}
|
||||
queries := repository.New(pool)
|
||||
db := &database.Connection{
|
||||
Queries: queries,
|
||||
Pool: pool,
|
||||
}
|
||||
svc := query.New(db)
|
||||
|
||||
q := query.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
}
|
||||
create := &queryprocessor.Create{
|
||||
Type: q.Type,
|
||||
}
|
||||
|
||||
dbType, err := queryprocessor.ToDBQueryType(create.Type)
|
||||
assert.Nil(t, err)
|
||||
|
||||
pool.ExpectBeginTx(pgx.TxOptions{})
|
||||
pool.ExpectQuery("name: CreateQuery :one").WithArgs(dbType).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).
|
||||
AddRow(database.MustToDBUUID(q.ID)),
|
||||
)
|
||||
pool.ExpectCommit()
|
||||
|
||||
id, err := svc.Create(ctx, create)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, q.ID, id)
|
||||
}
|
||||
|
||||
func TestCreateRollback(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
pool, err := pgxmock.NewPool()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open pgxmock database: %v", err)
|
||||
}
|
||||
queries := repository.New(pool)
|
||||
db := &database.Connection{
|
||||
Queries: queries,
|
||||
Pool: pool,
|
||||
}
|
||||
svc := query.New(db)
|
||||
|
||||
q := query.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
}
|
||||
create := &queryprocessor.Create{
|
||||
Type: q.Type,
|
||||
}
|
||||
|
||||
dbType, err := queryprocessor.ToDBQueryType(create.Type)
|
||||
assert.Nil(t, err)
|
||||
|
||||
pool.ExpectBeginTx(pgx.TxOptions{})
|
||||
msg := "database failure"
|
||||
pool.ExpectQuery("name: CreateQuery :one").WithArgs(dbType).WillReturnError(errors.New(msg))
|
||||
pool.ExpectRollback()
|
||||
|
||||
_, err = svc.Create(ctx, create)
|
||||
assert.EqualError(t, err, msg)
|
||||
}
|
||||
|
||||
@@ -41,30 +41,34 @@ func TestGetCreator(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseCreateQuery(t *testing.T) {
|
||||
cfg := "{\"key\":\"value\"}"
|
||||
cQuery := &queryprocessor.Create{
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: "{\"key\":\"value\"}",
|
||||
Config: &cfg,
|
||||
}
|
||||
|
||||
resultQuery, err := parseCreateQuery(cQuery)
|
||||
assert.Nil(t, err)
|
||||
rQIDs := database.MustToDBUUIDArray(*cQuery.RequiredQueryIDs)
|
||||
qcfg := []byte(*cQuery.Config)
|
||||
assert.EqualExportedValues(t, createQuery{
|
||||
Type: repository.QuerytypeContextFull,
|
||||
RequiredQueryIDs: database.MustToDBUUIDArray(cQuery.RequiredQueryIDs),
|
||||
Config: []byte(cQuery.Config),
|
||||
RequiredQueryIDs: &rQIDs,
|
||||
Config: &qcfg,
|
||||
}, *resultQuery)
|
||||
}
|
||||
|
||||
func TestParseCreateQueryInvalidType(t *testing.T) {
|
||||
cfg := "{\"key\":\"value\"}"
|
||||
cQuery := &queryprocessor.Create{
|
||||
Type: queryprocessor.Type(-1),
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: "{\"key\":\"value\"}",
|
||||
Config: &cfg,
|
||||
}
|
||||
|
||||
_, err := parseCreateQuery(cQuery)
|
||||
@@ -89,10 +93,10 @@ func TestSubmitCreate(t *testing.T) {
|
||||
q := Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: config,
|
||||
Config: &config,
|
||||
}
|
||||
create := &queryprocessor.Create{
|
||||
Type: q.Type,
|
||||
@@ -108,11 +112,11 @@ func TestSubmitCreate(t *testing.T) {
|
||||
pgxmock.NewRows([]string{"id"}).
|
||||
AddRow(database.MustToDBUUID(q.ID)),
|
||||
)
|
||||
for _, req := range create.RequiredQueryIDs {
|
||||
pool.ExpectExec("name: CreateRequiredQuery :exec").WithArgs(database.MustToDBUUID(q.ID), database.MustToDBUUID(req), int32(1)).
|
||||
for _, req := range *create.RequiredQueryIDs {
|
||||
pool.ExpectExec("name: AddRequiredQuery :exec").WithArgs(database.MustToDBUUID(q.ID), database.MustToDBUUID(req), int32(1)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
}
|
||||
pool.ExpectExec("name: CreateQueryConfig :exec").WithArgs(database.MustToDBUUID(q.ID), []byte(create.Config), int32(1)).
|
||||
pool.ExpectExec("name: AddQueryConfig :exec").WithArgs(database.MustToDBUUID(q.ID), []byte(*create.Config), int32(1)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectCommit()
|
||||
|
||||
@@ -120,3 +124,77 @@ func TestSubmitCreate(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, q.ID, id)
|
||||
}
|
||||
|
||||
func TestSubmitCreateNoReqsOrConfig(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
pool, err := pgxmock.NewPool()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open pgxmock database: %v", err)
|
||||
}
|
||||
queries := repository.New(pool)
|
||||
db := &database.Connection{
|
||||
Queries: queries,
|
||||
Pool: pool,
|
||||
}
|
||||
svc := New(db)
|
||||
|
||||
q := Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
}
|
||||
create := &queryprocessor.Create{
|
||||
Type: q.Type,
|
||||
}
|
||||
|
||||
dbType, err := queryprocessor.ToDBQueryType(create.Type)
|
||||
assert.Nil(t, err)
|
||||
|
||||
pool.ExpectBeginTx(pgx.TxOptions{})
|
||||
pool.ExpectQuery("name: CreateQuery :one").WithArgs(dbType).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).
|
||||
AddRow(database.MustToDBUUID(q.ID)),
|
||||
)
|
||||
pool.ExpectCommit()
|
||||
|
||||
id, err := svc.submitCreate(ctx, create)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, q.ID, id)
|
||||
}
|
||||
|
||||
func TestNormalizeCreate(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
pool, err := pgxmock.NewPool()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open pgxmock database: %v", err)
|
||||
}
|
||||
queries := repository.New(pool)
|
||||
db := &database.Connection{
|
||||
Queries: queries,
|
||||
Pool: pool,
|
||||
}
|
||||
svc := New(db)
|
||||
|
||||
cfg := "{}"
|
||||
create := &queryprocessor.Create{
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
Config: &cfg,
|
||||
RequiredQueryIDs: &[]uuid.UUID{},
|
||||
}
|
||||
|
||||
dbids := database.MustToDBUUIDArray(*create.RequiredQueryIDs)
|
||||
|
||||
pool.ExpectQuery("name: AllQueriesExist :one").WithArgs(dbids).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"all_exist"}).
|
||||
AddRow(true),
|
||||
)
|
||||
|
||||
err = svc.normalizeCreate(ctx, create)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualExportedValues(t, queryprocessor.Create{
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
Config: nil,
|
||||
RequiredQueryIDs: nil,
|
||||
}, *create)
|
||||
}
|
||||
|
||||
@@ -129,18 +129,22 @@ func TestSyncDBFail(t *testing.T) {
|
||||
pgxmock.NewRows([]string{"id", "jobId", "minCleanVersion", "minTextVersion"}).
|
||||
AddRow(dbCollectorId, dbJobID, minCleanVersion, minTextVersion),
|
||||
)
|
||||
qV := int32(1)
|
||||
reqID := database.MustToDBUUID(uuid.New())
|
||||
resID := database.MustToDBUUID(uuid.New())
|
||||
pool.ExpectQuery("name: ListResultsByDocumentID :many").WithArgs(database.MustToDBUUID(doc.ID), minCleanVersion, minTextVersion).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "queryVersion"}),
|
||||
pgxmock.NewRows([]string{"id", "queryId", "queryVersion"}).
|
||||
AddRow(resID, reqID, qV),
|
||||
)
|
||||
dbErr = "database failure"
|
||||
qV := int32(1)
|
||||
pool.ExpectQuery("name: GetCollectorQueries :many").WithArgs(dbCollectorId).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"collectorId", "queryId", "type", "queryVersion", "requiredIds"}).
|
||||
AddRow(dbCollectorId, dbQueryID, repository.NullQuerytype{Querytype: repository.QuerytypeJsonExtractor, Valid: true}, &qV, []pgtype.UUID{}),
|
||||
AddRow(dbCollectorId, dbQueryID, repository.NullQuerytype{Querytype: repository.QuerytypeJsonExtractor, Valid: true}, &qV, []pgtype.UUID{reqID}).
|
||||
AddRow(dbCollectorId, reqID, repository.NullQuerytype{Querytype: repository.QuerytypeContextFull, Valid: true}, &qV, []pgtype.UUID{}),
|
||||
)
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs([]pgtype.UUID{}).
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs([]pgtype.UUID{resID}).
|
||||
WillReturnError(errors.New(dbErr))
|
||||
|
||||
docSvc = document.New(db)
|
||||
|
||||
+16
-6
@@ -14,8 +14,8 @@ type Query struct {
|
||||
Type queryprocessor.Type
|
||||
ActiveVersion int32
|
||||
LatestVersion int32
|
||||
RequiredQueryIDs []uuid.UUID
|
||||
Config string
|
||||
RequiredQueryIDs *[]uuid.UUID
|
||||
Config *string
|
||||
}
|
||||
|
||||
func (s *Service) Get(ctx context.Context, id uuid.UUID) (*Query, error) {
|
||||
@@ -28,9 +28,13 @@ func (s *Service) Get(ctx context.Context, id uuid.UUID) (*Query, error) {
|
||||
}
|
||||
|
||||
func ParseFullActiveQuery(q *repository.Fullactivequery) (*Query, error) {
|
||||
reqQueryIDs := []uuid.UUID{}
|
||||
if !(len(q.Requiredids) == 0 || len(q.Requiredids) == 1 && database.MustToUUID(q.Requiredids[0]) == uuid.Nil) {
|
||||
reqQueryIDs = database.MustToUUIDArray(q.Requiredids)
|
||||
var reqQueryIDs *[]uuid.UUID
|
||||
if len(q.Requiredids) > 0 {
|
||||
rQ, err := database.ToUUIDArray(q.Requiredids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqQueryIDs = &rQ
|
||||
}
|
||||
|
||||
qType, err := queryprocessor.ParseDBType(q.Type)
|
||||
@@ -38,13 +42,19 @@ func ParseFullActiveQuery(q *repository.Fullactivequery) (*Query, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var scfg *string
|
||||
if q.Config != nil && string(q.Config) != "" {
|
||||
s := string(q.Config)
|
||||
scfg = &s
|
||||
}
|
||||
|
||||
return &Query{
|
||||
ID: database.MustToUUID(q.ID),
|
||||
ActiveVersion: q.Activeversion,
|
||||
LatestVersion: q.Latestversion,
|
||||
Type: qType,
|
||||
RequiredQueryIDs: reqQueryIDs,
|
||||
Config: string(q.Config),
|
||||
Config: scfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
+15
-28
@@ -9,7 +9,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -34,13 +33,13 @@ func TestGet(t *testing.T) {
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(1),
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: config,
|
||||
Config: &config,
|
||||
}
|
||||
|
||||
dbReqIDs := database.MustToDBUUIDArray(query.RequiredQueryIDs)
|
||||
dbReqIDs := database.MustToDBUUIDArray(*query.RequiredQueryIDs)
|
||||
|
||||
pool.ExpectQuery("name: GetQuery :one").WithArgs(database.MustToDBUUID(query.ID)).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "type", "activeVersion", "latestVersion", "config", "requiredIds"}).
|
||||
@@ -59,19 +58,15 @@ func TestFullActiveQueryEmpty(t *testing.T) {
|
||||
Type: repository.QuerytypeContextFull,
|
||||
Activeversion: int32(1),
|
||||
Latestversion: int32(2),
|
||||
Config: []byte(""),
|
||||
Requiredids: []pgtype.UUID{},
|
||||
}
|
||||
|
||||
out, err := query.ParseFullActiveQuery(dbQuery)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualExportedValues(t, query.Query{
|
||||
ID: database.MustToUUID(dbQuery.ID),
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
Config: "",
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
ID: database.MustToUUID(dbQuery.ID),
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
}, *out)
|
||||
}
|
||||
|
||||
@@ -81,19 +76,15 @@ func TestFullActiveQueryWithNullUUID(t *testing.T) {
|
||||
Type: repository.QuerytypeContextFull,
|
||||
Activeversion: int32(1),
|
||||
Latestversion: int32(2),
|
||||
Config: []byte(""),
|
||||
Requiredids: []pgtype.UUID{database.MustToDBUUID(uuid.Nil)},
|
||||
}
|
||||
|
||||
out, err := query.ParseFullActiveQuery(dbQuery)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualExportedValues(t, query.Query{
|
||||
ID: database.MustToUUID(dbQuery.ID),
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
Config: "",
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
ID: database.MustToUUID(dbQuery.ID),
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
}, *out)
|
||||
}
|
||||
|
||||
@@ -104,8 +95,6 @@ func TestFullActiveQueryArray(t *testing.T) {
|
||||
Type: repository.QuerytypeContextFull,
|
||||
Activeversion: int32(1),
|
||||
Latestversion: int32(2),
|
||||
Config: []byte(""),
|
||||
Requiredids: []pgtype.UUID{},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -113,12 +102,10 @@ func TestFullActiveQueryArray(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.EqualExportedValues(t, []*query.Query{
|
||||
{
|
||||
ID: database.MustToUUID(dbQueries[0].ID),
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
Config: "",
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
ID: database.MustToUUID(dbQueries[0].ID),
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
},
|
||||
}, out)
|
||||
}
|
||||
|
||||
@@ -33,13 +33,13 @@ func TestList(t *testing.T) {
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(1),
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: config,
|
||||
Config: &config,
|
||||
}
|
||||
|
||||
dbReqIDs := database.MustToDBUUIDArray(q.RequiredQueryIDs)
|
||||
dbReqIDs := database.MustToDBUUIDArray(*q.RequiredQueryIDs)
|
||||
|
||||
filters := query.ListFilters{}
|
||||
|
||||
@@ -74,13 +74,13 @@ func TestListFilterType(t *testing.T) {
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(1),
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: config,
|
||||
Config: &config,
|
||||
}
|
||||
|
||||
dbReqIDs := database.MustToDBUUIDArray(q.RequiredQueryIDs)
|
||||
dbReqIDs := database.MustToDBUUIDArray(*q.RequiredQueryIDs)
|
||||
|
||||
filters := query.ListFilters{}
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"queryorchestration/internal/database"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Config interface {
|
||||
GetConfig() *string
|
||||
SetConfig(*string)
|
||||
}
|
||||
|
||||
func (s *Service) normalizeConfig(config Config) error {
|
||||
if config == nil || config.GetConfig() == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
trim := strings.TrimSpace(*config.GetConfig())
|
||||
|
||||
if trim == "" {
|
||||
config.SetConfig(nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !json.Valid([]byte(trim)) {
|
||||
return errors.New("invalid config JSON")
|
||||
}
|
||||
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(trim), &data); err != nil {
|
||||
return fmt.Errorf("error unmarshalling JSON: %s", err)
|
||||
}
|
||||
|
||||
prettyJSON, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshalling JSON: %s", err)
|
||||
}
|
||||
|
||||
strJSON := string(prettyJSON)
|
||||
|
||||
if strJSON == "{}" {
|
||||
config.SetConfig(nil)
|
||||
} else {
|
||||
config.SetConfig(&strJSON)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type RequiredQueryIDs interface {
|
||||
GetRequiredQueryIDs() *[]uuid.UUID
|
||||
SetRequiredQueryIDs(*[]uuid.UUID)
|
||||
}
|
||||
|
||||
func (s *Service) normalizeQueryIDs(ctx context.Context, ids RequiredQueryIDs) error {
|
||||
if ids == nil || ids.GetRequiredQueryIDs() == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ide := ids.GetRequiredQueryIDs()
|
||||
|
||||
if len(*ide) == 0 {
|
||||
ids.SetRequiredQueryIDs(nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
dbids := database.MustToDBUUIDArray(*ide)
|
||||
|
||||
exist, err := s.db.Queries.AllQueriesExist(ctx, dbids)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !exist {
|
||||
return errors.New("not all required ids are present")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) normalizeActiveVersion(current *Query, entity *queryprocessor.Update) error {
|
||||
if current == nil {
|
||||
return errors.New("current query required")
|
||||
}
|
||||
|
||||
if entity == nil || entity.ActiveVersion == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if entity.ActiveVersion == ¤t.ActiveVersion {
|
||||
entity.ActiveVersion = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
if *entity.ActiveVersion < 1 || *entity.ActiveVersion > current.LatestVersion+1 {
|
||||
return fmt.Errorf("active version must be in the range: 1 <= activeVersion <= %d", current.LatestVersion+1)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNormalizeConfig(t *testing.T) {
|
||||
s := Service{}
|
||||
|
||||
err := s.normalizeConfig(nil)
|
||||
assert.Nil(t, err)
|
||||
|
||||
entity := queryprocessor.Create{}
|
||||
|
||||
entity.Config = nil
|
||||
err = s.normalizeConfig(&entity)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, entity.Config)
|
||||
|
||||
cfg := ""
|
||||
entity.Config = &cfg
|
||||
err = s.normalizeConfig(&entity)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, entity.Config)
|
||||
|
||||
cfg = " "
|
||||
entity.Config = &cfg
|
||||
err = s.normalizeConfig(&entity)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, entity.Config)
|
||||
|
||||
cfg = "{}"
|
||||
entity.Config = &cfg
|
||||
err = s.normalizeConfig(&entity)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, entity.Config)
|
||||
|
||||
cfg = "{\"hello\":\"bye\"}"
|
||||
entity.Config = &cfg
|
||||
err = s.normalizeConfig(&entity)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "{\"hello\":\"bye\"}", *(entity.Config))
|
||||
|
||||
cfg = " { \"hello\" : \"bye\" } "
|
||||
entity.Config = &cfg
|
||||
err = s.normalizeConfig(&entity)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "{\"hello\":\"bye\"}", *(entity.Config))
|
||||
|
||||
cfg = "{'hello':'bye'}"
|
||||
entity.Config = &cfg
|
||||
err = s.normalizeConfig(&entity)
|
||||
assert.Error(t, err)
|
||||
|
||||
cfg = "{\"hello\":\"}"
|
||||
entity.Config = &cfg
|
||||
err = s.normalizeConfig(&entity)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNormalizeQueryIDs(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
pool, err := pgxmock.NewPool()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open pgxmock database: %v", err)
|
||||
}
|
||||
queries := repository.New(pool)
|
||||
db := &database.Connection{
|
||||
Queries: queries,
|
||||
Pool: pool,
|
||||
}
|
||||
s := Service{db: db}
|
||||
|
||||
err = s.normalizeQueryIDs(ctx, nil)
|
||||
assert.Nil(t, err)
|
||||
|
||||
entity := queryprocessor.Create{}
|
||||
|
||||
entity.RequiredQueryIDs = nil
|
||||
err = s.normalizeQueryIDs(ctx, &entity)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, entity.RequiredQueryIDs)
|
||||
|
||||
entity.RequiredQueryIDs = &[]uuid.UUID{}
|
||||
err = s.normalizeQueryIDs(ctx, &entity)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, entity.RequiredQueryIDs)
|
||||
|
||||
ids := []uuid.UUID{uuid.New()}
|
||||
entity.RequiredQueryIDs = &ids
|
||||
dbids := database.MustToDBUUIDArray(*entity.RequiredQueryIDs)
|
||||
|
||||
pool.ExpectQuery("name: AllQueriesExist :one").WithArgs(dbids).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"all_exist"}).
|
||||
AddRow(true),
|
||||
)
|
||||
|
||||
err = s.normalizeQueryIDs(ctx, &entity)
|
||||
assert.Nil(t, err)
|
||||
assert.ElementsMatch(t, ids, *entity.RequiredQueryIDs)
|
||||
|
||||
pool.ExpectQuery("name: AllQueriesExist :one").WithArgs(dbids).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"all_exist"}).
|
||||
AddRow(false),
|
||||
)
|
||||
|
||||
err = s.normalizeQueryIDs(ctx, &entity)
|
||||
assert.Error(t, err)
|
||||
assert.ElementsMatch(t, ids, *entity.RequiredQueryIDs)
|
||||
|
||||
pool.ExpectQuery("name: AllQueriesExist :one").WithArgs(dbids).
|
||||
WillReturnError(errors.New("database failure"))
|
||||
|
||||
err = s.normalizeQueryIDs(ctx, &entity)
|
||||
assert.Error(t, err)
|
||||
assert.ElementsMatch(t, ids, *entity.RequiredQueryIDs)
|
||||
}
|
||||
|
||||
func TestNormalizeActiveVersion(t *testing.T) {
|
||||
s := Service{}
|
||||
|
||||
err := s.normalizeActiveVersion(nil, nil)
|
||||
assert.Error(t, err)
|
||||
|
||||
current := Query{
|
||||
ActiveVersion: 2,
|
||||
LatestVersion: 4,
|
||||
}
|
||||
entity := queryprocessor.Update{}
|
||||
|
||||
err = s.normalizeActiveVersion(nil, &entity)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = s.normalizeActiveVersion(¤t, nil)
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = s.normalizeActiveVersion(¤t, &entity)
|
||||
assert.Nil(t, err)
|
||||
|
||||
entity.ActiveVersion = ¤t.ActiveVersion
|
||||
err = s.normalizeActiveVersion(¤t, &entity)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, entity.ActiveVersion)
|
||||
|
||||
aV := current.ActiveVersion + 1
|
||||
entity.ActiveVersion = &aV
|
||||
err = s.normalizeActiveVersion(¤t, &entity)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, aV, *entity.ActiveVersion)
|
||||
|
||||
aV = current.LatestVersion + 2
|
||||
entity.ActiveVersion = &aV
|
||||
err = s.normalizeActiveVersion(¤t, &entity)
|
||||
assert.Error(t, err)
|
||||
|
||||
aV = 0
|
||||
entity.ActiveVersion = &aV
|
||||
err = s.normalizeActiveVersion(¤t, &entity)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
@@ -13,15 +13,16 @@ import (
|
||||
)
|
||||
|
||||
func TestParseQuery(t *testing.T) {
|
||||
cfg := "example"
|
||||
q := &query.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: "example",
|
||||
Config: &cfg,
|
||||
}
|
||||
|
||||
out := query.ParseQuery(q)
|
||||
@@ -48,14 +49,15 @@ func TestParseFullActiveQuery(t *testing.T) {
|
||||
|
||||
out, err := query.ParseFullActiveQuery(q)
|
||||
assert.Nil(t, err)
|
||||
bcfg := string(q.Config)
|
||||
assert.EqualExportedValues(t, query.Query{
|
||||
ID: database.MustToUUID(q.ID),
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
ActiveVersion: q.Activeversion,
|
||||
LatestVersion: q.Latestversion,
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
database.MustToUUID(q.Requiredids[0]),
|
||||
},
|
||||
Config: string(q.Config),
|
||||
Config: &bcfg,
|
||||
}, *out)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func ParseDBNullType(qType repository.NullQuerytype) (Type, error) {
|
||||
@@ -64,7 +66,11 @@ func ToDBNullQueryType(t Type) (repository.NullQuerytype, error) {
|
||||
}
|
||||
|
||||
func ParseDBCollectorQuery(q *repository.GetCollectorQueriesRow) (*Query, error) {
|
||||
reqQueryIDs := database.MustToUUIDArray(q.Requiredids)
|
||||
var reqQueryIDs *[]uuid.UUID
|
||||
if len(q.Requiredids) > 0 {
|
||||
ids := database.MustToUUIDArray(q.Requiredids)
|
||||
reqQueryIDs = &ids
|
||||
}
|
||||
|
||||
qType, err := ParseDBNullType(q.Type)
|
||||
if err != nil {
|
||||
|
||||
@@ -22,7 +22,7 @@ func TestParseDBCollectorQuery(t *testing.T) {
|
||||
value, err := queryprocessor.ParseDBCollectorQuery(&dbResult)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, uuid.Nil, value.ID)
|
||||
assert.Equal(t, []uuid.UUID{}, value.RequiredQueryIDs)
|
||||
assert.Nil(t, value.RequiredQueryIDs)
|
||||
assert.Equal(t, int32(0), value.Version)
|
||||
assert.Equal(t, queryprocessor.Type(queryprocessor.TypeJsonExtractor), value.Type)
|
||||
|
||||
|
||||
@@ -16,22 +16,55 @@ const (
|
||||
|
||||
type Create struct {
|
||||
Type Type
|
||||
RequiredQueryIDs []uuid.UUID
|
||||
Config string
|
||||
RequiredQueryIDs *[]uuid.UUID
|
||||
Config *string
|
||||
}
|
||||
|
||||
func (s *Create) GetConfig() *string {
|
||||
return s.Config
|
||||
}
|
||||
|
||||
func (s *Create) SetConfig(cfg *string) {
|
||||
s.Config = cfg
|
||||
}
|
||||
|
||||
func (s *Create) GetRequiredQueryIDs() *[]uuid.UUID {
|
||||
return s.RequiredQueryIDs
|
||||
}
|
||||
|
||||
func (s *Create) SetRequiredQueryIDs(ids *[]uuid.UUID) {
|
||||
s.RequiredQueryIDs = ids
|
||||
}
|
||||
|
||||
type Update struct {
|
||||
ID uuid.UUID
|
||||
RequiredQueryIDs []uuid.UUID
|
||||
Config string
|
||||
ActiveVersion *int32
|
||||
RequiredQueryIDs *[]uuid.UUID
|
||||
Config *string
|
||||
}
|
||||
|
||||
func (s *Update) GetConfig() *string {
|
||||
return s.Config
|
||||
}
|
||||
|
||||
func (s *Update) SetConfig(cfg *string) {
|
||||
s.Config = cfg
|
||||
}
|
||||
|
||||
func (s *Update) GetRequiredQueryIDs() *[]uuid.UUID {
|
||||
return s.RequiredQueryIDs
|
||||
}
|
||||
|
||||
func (s *Update) SetRequiredQueryIDs(ids *[]uuid.UUID) {
|
||||
s.RequiredQueryIDs = ids
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
ID uuid.UUID
|
||||
Type Type
|
||||
Version int32
|
||||
RequiredQueryIDs []uuid.UUID
|
||||
Config string
|
||||
RequiredQueryIDs *[]uuid.UUID
|
||||
Config *string
|
||||
}
|
||||
|
||||
type Creator interface {
|
||||
@@ -43,5 +76,5 @@ type Updator interface {
|
||||
}
|
||||
|
||||
type Processor interface {
|
||||
Process(ctx context.Context, query *Query, values []result.Value) (string, error)
|
||||
Process(ctx context.Context, query *Query, values *[]result.Value) (string, error)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package queryprocessor_test
|
||||
|
||||
import (
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreateGetConfig(t *testing.T) {
|
||||
entity := queryprocessor.Create{}
|
||||
|
||||
assert.Nil(t, entity.GetConfig())
|
||||
|
||||
cfg := "example_config"
|
||||
entity.Config = &cfg
|
||||
assert.NotNil(t, entity.GetConfig())
|
||||
assert.Equal(t, cfg, *entity.GetConfig())
|
||||
}
|
||||
|
||||
func TestCreateSetConfig(t *testing.T) {
|
||||
entity := queryprocessor.Create{}
|
||||
|
||||
assert.Nil(t, entity.Config)
|
||||
|
||||
cfg := "example_config"
|
||||
entity.SetConfig(&cfg)
|
||||
assert.Equal(t, cfg, *entity.Config)
|
||||
}
|
||||
|
||||
func TestUpdateGetConfig(t *testing.T) {
|
||||
entity := queryprocessor.Update{}
|
||||
|
||||
assert.Nil(t, entity.GetConfig())
|
||||
|
||||
cfg := "example_config"
|
||||
entity.Config = &cfg
|
||||
assert.NotNil(t, entity.GetConfig())
|
||||
assert.Equal(t, cfg, *entity.GetConfig())
|
||||
}
|
||||
|
||||
func TestUpdateSetConfig(t *testing.T) {
|
||||
entity := queryprocessor.Update{}
|
||||
|
||||
assert.Nil(t, entity.Config)
|
||||
|
||||
cfg := "example_config"
|
||||
entity.SetConfig(&cfg)
|
||||
assert.Equal(t, cfg, *entity.Config)
|
||||
}
|
||||
|
||||
func TestCreateGetRequiredQueryIDs(t *testing.T) {
|
||||
entity := queryprocessor.Create{}
|
||||
|
||||
assert.Nil(t, entity.GetRequiredQueryIDs())
|
||||
|
||||
ids := []uuid.UUID{uuid.New()}
|
||||
entity.RequiredQueryIDs = &ids
|
||||
assert.NotNil(t, entity.GetRequiredQueryIDs())
|
||||
assert.Equal(t, ids, *entity.GetRequiredQueryIDs())
|
||||
}
|
||||
|
||||
func TestCreateSetRequiredQueryIDs(t *testing.T) {
|
||||
entity := queryprocessor.Create{}
|
||||
|
||||
assert.Nil(t, entity.RequiredQueryIDs)
|
||||
|
||||
ids := []uuid.UUID{uuid.New()}
|
||||
entity.SetRequiredQueryIDs(&ids)
|
||||
assert.Equal(t, ids, *entity.RequiredQueryIDs)
|
||||
}
|
||||
|
||||
func TestUpdateGetRequiredQueryIDs(t *testing.T) {
|
||||
entity := queryprocessor.Update{}
|
||||
|
||||
assert.Nil(t, entity.GetRequiredQueryIDs())
|
||||
|
||||
ids := []uuid.UUID{uuid.New()}
|
||||
entity.RequiredQueryIDs = &ids
|
||||
assert.NotNil(t, entity.GetRequiredQueryIDs())
|
||||
assert.Equal(t, ids, *entity.GetRequiredQueryIDs())
|
||||
}
|
||||
|
||||
func TestUpdateSetRequiredQueryIDs(t *testing.T) {
|
||||
entity := queryprocessor.Update{}
|
||||
|
||||
assert.Nil(t, entity.RequiredQueryIDs)
|
||||
|
||||
ids := []uuid.UUID{uuid.New()}
|
||||
entity.SetRequiredQueryIDs(&ids)
|
||||
assert.Equal(t, ids, *entity.RequiredQueryIDs)
|
||||
}
|
||||
@@ -64,20 +64,24 @@ func (q *Queue) Add(qu *queryprocessor.Query) {
|
||||
if entry.ID == qu.ID {
|
||||
return
|
||||
}
|
||||
for _, id := range qu.RequiredQueryIDs {
|
||||
if entry.ID == id {
|
||||
requiredIndex = index
|
||||
break
|
||||
if qu.RequiredQueryIDs != nil {
|
||||
for _, id := range *qu.RequiredQueryIDs {
|
||||
if entry.ID == id {
|
||||
requiredIndex = index
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, entry := range q.collectorQueries {
|
||||
for _, id := range entry.RequiredQueryIDs {
|
||||
if qu.ID == id {
|
||||
dependentQueries = append(dependentQueries, entry)
|
||||
break
|
||||
if entry.RequiredQueryIDs != nil {
|
||||
for _, id := range *entry.RequiredQueryIDs {
|
||||
if qu.ID == id {
|
||||
dependentQueries = append(dependentQueries, entry)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -60,13 +61,16 @@ func TestGetCollectorQueries(t *testing.T) {
|
||||
dbCollectorID := database.MustToDBUUID(svc.collector.ID)
|
||||
|
||||
collectorQueries := []*queryprocessor.Query{
|
||||
{ID: uuid.New(), Type: queryprocessor.TypeContextFull, RequiredQueryIDs: []uuid.UUID{}, Version: int32(1)},
|
||||
{ID: uuid.New(), Type: queryprocessor.TypeContextFull, Version: int32(1)},
|
||||
}
|
||||
|
||||
rows := pgxmock.NewRows([]string{"collectorId", "queryId", "type", "queryVersion", "requiredIds"})
|
||||
for _, q := range collectorQueries {
|
||||
dbID := database.MustToDBUUID(q.ID)
|
||||
dbReqIDs := database.MustToDBUUIDArray(q.RequiredQueryIDs)
|
||||
dbReqIDs := []pgtype.UUID{}
|
||||
if q.RequiredQueryIDs != nil {
|
||||
dbReqIDs = database.MustToDBUUIDArray(*q.RequiredQueryIDs)
|
||||
}
|
||||
ty, err := queryprocessor.ToDBNullQueryType(q.Type)
|
||||
assert.Nil(t, err)
|
||||
rows = rows.
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"queryorchestration/internal/query/result"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
@@ -27,43 +28,57 @@ func (q *Queue) Execute(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (q *Queue) executeQuery(ctx context.Context, qu *queryprocessor.Query) error {
|
||||
resultIDs := make([]pgtype.UUID, len(qu.RequiredQueryIDs))
|
||||
for index, id := range qu.RequiredQueryIDs {
|
||||
var queryVersion int32
|
||||
for _, entry := range q.collectorQueries {
|
||||
if entry.ID == id {
|
||||
queryVersion = entry.Version
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, entry := range q.results {
|
||||
if entry.QueryID == id && entry.QueryVersion == queryVersion {
|
||||
resultIDs[index] = database.MustToDBUUID(entry.ID)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
values, err := q.db.Queries.ListResultValuesByID(ctx, resultIDs)
|
||||
values, err := q.getRequiredResults(ctx, qu.RequiredQueryIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cleanValues := make([]result.Value, len(values))
|
||||
for index, r := range values {
|
||||
cleanValue, err := q.getResultValue(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cleanValues[index] = cleanValue
|
||||
}
|
||||
|
||||
err = q.setResult(ctx, qu, cleanValues)
|
||||
err = q.setResult(ctx, qu, values)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *Queue) getRequiredResults(ctx context.Context, requiredQueryIDs *[]uuid.UUID) (*[]result.Value, error) {
|
||||
var values *[]result.Value
|
||||
if requiredQueryIDs != nil {
|
||||
resultIDs := make([]pgtype.UUID, len(*requiredQueryIDs))
|
||||
for index, id := range *requiredQueryIDs {
|
||||
var queryVersion int32
|
||||
for _, entry := range q.collectorQueries {
|
||||
if entry.ID == id {
|
||||
queryVersion = entry.Version
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, entry := range q.results {
|
||||
if entry.QueryID == id && entry.QueryVersion == queryVersion {
|
||||
resultIDs[index] = database.MustToDBUUID(entry.ID)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resultValues, err := q.db.Queries.ListResultValuesByID(ctx, resultIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rValues := make([]result.Value, len(resultValues))
|
||||
for index, r := range resultValues {
|
||||
cleanValue, err := q.getResultValue(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rValues[index] = cleanValue
|
||||
}
|
||||
|
||||
values = &rValues
|
||||
}
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
@@ -58,19 +58,22 @@ func TestExecute(t *testing.T) {
|
||||
contextID := uuid.New()
|
||||
contextVersion := int32(1)
|
||||
collectorQueries := []queryprocessor.Query{
|
||||
{ID: contextID, Type: queryprocessor.TypeContextFull, RequiredQueryIDs: []uuid.UUID{}, Version: contextVersion},
|
||||
{ID: queryOneID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{contextID}, Version: queryOneVersion},
|
||||
{ID: queryTwoID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{queryOneID}, Version: queryTwoVersion},
|
||||
{ID: queryThreeID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{queryOneID}, Version: queryThreeVersion},
|
||||
{ID: queryFourID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{contextID}, Version: queryFourVersion},
|
||||
{ID: queryFiveID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{querySixID}, Version: queryFiveVersion},
|
||||
{ID: querySixID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{contextID}, Version: querySixVersion},
|
||||
{ID: contextID, Type: queryprocessor.TypeContextFull, Version: contextVersion},
|
||||
{ID: queryOneID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{contextID}, Version: queryOneVersion},
|
||||
{ID: queryTwoID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{queryOneID}, Version: queryTwoVersion},
|
||||
{ID: queryThreeID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{queryOneID}, Version: queryThreeVersion},
|
||||
{ID: queryFourID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{contextID}, Version: queryFourVersion},
|
||||
{ID: queryFiveID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{querySixID}, Version: queryFiveVersion},
|
||||
{ID: querySixID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{contextID}, Version: querySixVersion},
|
||||
}
|
||||
|
||||
rows := pgxmock.NewRows([]string{"collectorId", "queryId", "type", "queryVersion", "requiredIds"})
|
||||
for _, q := range collectorQueries {
|
||||
dbID := database.MustToDBUUID(q.ID)
|
||||
dbReqIDs := database.MustToDBUUIDArray(q.RequiredQueryIDs)
|
||||
dbReqIDs := []pgtype.UUID{}
|
||||
if q.RequiredQueryIDs != nil {
|
||||
dbReqIDs = database.MustToDBUUIDArray(*q.RequiredQueryIDs)
|
||||
}
|
||||
ty, err := queryprocessor.ToDBNullQueryType(q.Type)
|
||||
assert.Nil(t, err)
|
||||
rows = rows.
|
||||
@@ -88,11 +91,11 @@ func TestExecute(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedQueries := []*queryprocessor.Query{
|
||||
{ID: querySixID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{contextID}, Version: querySixVersion},
|
||||
{ID: queryFiveID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{querySixID}, Version: queryFiveVersion},
|
||||
{ID: queryOneID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{contextID}, Version: queryOneVersion},
|
||||
{ID: queryThreeID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{queryOneID}, Version: queryThreeVersion},
|
||||
{ID: queryTwoID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{queryOneID}, Version: queryTwoVersion},
|
||||
{ID: querySixID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{contextID}, Version: querySixVersion},
|
||||
{ID: queryFiveID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{querySixID}, Version: queryFiveVersion},
|
||||
{ID: queryOneID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{contextID}, Version: queryOneVersion},
|
||||
{ID: queryThreeID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{queryOneID}, Version: queryThreeVersion},
|
||||
{ID: queryTwoID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{queryOneID}, Version: queryTwoVersion},
|
||||
}
|
||||
|
||||
docID := uuid.New()
|
||||
|
||||
@@ -27,8 +27,8 @@ func TestExecute(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedQueries := []*queryprocessor.Query{
|
||||
{ID: uuid.New(), Type: queryprocessor.TypeContextFull, RequiredQueryIDs: []uuid.UUID{}, Version: int32(1)},
|
||||
{ID: uuid.New(), Type: queryprocessor.TypeContextFull, RequiredQueryIDs: []uuid.UUID{}, Version: int32(2)},
|
||||
{ID: uuid.New(), Type: queryprocessor.TypeContextFull, Version: int32(1)},
|
||||
{ID: uuid.New(), Type: queryprocessor.TypeContextFull, Version: int32(2)},
|
||||
}
|
||||
|
||||
q := &Queue{
|
||||
@@ -39,17 +39,11 @@ func TestExecute(t *testing.T) {
|
||||
textVersion: int32(2),
|
||||
}
|
||||
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs([]pgtype.UUID{}).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "value"}),
|
||||
)
|
||||
pool.ExpectQuery("name: SetResult :one").WithArgs(database.MustToDBUUID(expectedQueries[0].ID), database.MustToDBUUID(q.documentId), pgxmock.AnyArg(), q.cleanVersion, q.textVersion, expectedQueries[0].Version).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).AddRow(pgtype.UUID{}),
|
||||
)
|
||||
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs([]pgtype.UUID{}).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "value"}),
|
||||
)
|
||||
pool.ExpectQuery("name: SetResult :one").WithArgs(database.MustToDBUUID(expectedQueries[1].ID), database.MustToDBUUID(q.documentId), pgxmock.AnyArg(), q.cleanVersion, q.textVersion, expectedQueries[1].Version).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).AddRow(pgtype.UUID{}),
|
||||
@@ -72,7 +66,7 @@ func TestExecuteQuery(t *testing.T) {
|
||||
Pool: pool,
|
||||
}
|
||||
|
||||
qu := &queryprocessor.Query{ID: uuid.New(), Type: queryprocessor.TypeContextFull, RequiredQueryIDs: []uuid.UUID{}, Version: int32(1)}
|
||||
qu := &queryprocessor.Query{ID: uuid.New(), Type: queryprocessor.TypeContextFull, Version: int32(1)}
|
||||
|
||||
q := &Queue{
|
||||
db: db,
|
||||
@@ -81,9 +75,6 @@ func TestExecuteQuery(t *testing.T) {
|
||||
textVersion: int32(2),
|
||||
}
|
||||
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs([]pgtype.UUID{}).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "value"}),
|
||||
)
|
||||
pool.ExpectQuery("name: SetResult :one").WithArgs(database.MustToDBUUID(qu.ID), database.MustToDBUUID(q.documentId), pgxmock.AnyArg(), q.cleanVersion, q.textVersion, qu.Version).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).AddRow(pgtype.UUID{}),
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
jsonextractor "queryorchestration/internal/query/types/jsonExtractor"
|
||||
)
|
||||
|
||||
func (q *Queue) setResult(ctx context.Context, qu *queryprocessor.Query, resultValues []result.Value) error {
|
||||
func (q *Queue) setResult(ctx context.Context, qu *queryprocessor.Query, resultValues *[]result.Value) error {
|
||||
processor, err := q.getProcessor(qu.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestSetResult(t *testing.T) {
|
||||
textVersion: int32(2),
|
||||
}
|
||||
|
||||
qu := &queryprocessor.Query{ID: uuid.New(), Type: queryprocessor.TypeContextFull, RequiredQueryIDs: []uuid.UUID{}, Version: int32(1)}
|
||||
qu := &queryprocessor.Query{ID: uuid.New(), Type: queryprocessor.TypeContextFull, Version: int32(1)}
|
||||
resultValues := []result.Value{}
|
||||
|
||||
pool.ExpectQuery("name: SetResult :one").WithArgs(database.MustToDBUUID(qu.ID), database.MustToDBUUID(q.documentId), pgxmock.AnyArg(), q.cleanVersion, q.textVersion, qu.Version).
|
||||
@@ -42,7 +42,7 @@ func TestSetResult(t *testing.T) {
|
||||
pgxmock.NewRows([]string{"id"}).AddRow(pgtype.UUID{}),
|
||||
)
|
||||
|
||||
err = q.setResult(ctx, qu, resultValues)
|
||||
err = q.setResult(ctx, qu, &resultValues)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -57,19 +58,22 @@ func TestService(t *testing.T) {
|
||||
contextID := uuid.New()
|
||||
contextVersion := int32(1)
|
||||
collectorQueries := []queryprocessor.Query{
|
||||
{ID: contextID, Type: queryprocessor.TypeContextFull, RequiredQueryIDs: []uuid.UUID{}, Version: contextVersion},
|
||||
{ID: queryOneID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{contextID}, Version: queryOneVersion},
|
||||
{ID: queryTwoID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{queryOneID}, Version: queryTwoVersion},
|
||||
{ID: queryThreeID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{queryOneID}, Version: queryThreeVersion},
|
||||
{ID: queryFourID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{contextID}, Version: queryFourVersion},
|
||||
{ID: queryFiveID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{querySixID}, Version: queryFiveVersion},
|
||||
{ID: querySixID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{contextID}, Version: querySixVersion},
|
||||
{ID: contextID, Type: queryprocessor.TypeContextFull, Version: contextVersion},
|
||||
{ID: queryOneID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{contextID}, Version: queryOneVersion},
|
||||
{ID: queryTwoID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{queryOneID}, Version: queryTwoVersion},
|
||||
{ID: queryThreeID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{queryOneID}, Version: queryThreeVersion},
|
||||
{ID: queryFourID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{contextID}, Version: queryFourVersion},
|
||||
{ID: queryFiveID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{querySixID}, Version: queryFiveVersion},
|
||||
{ID: querySixID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{contextID}, Version: querySixVersion},
|
||||
}
|
||||
|
||||
rows := pgxmock.NewRows([]string{"collectorId", "queryId", "type", "queryVersion", "requiredIds"})
|
||||
for _, q := range collectorQueries {
|
||||
dbID := database.MustToDBUUID(q.ID)
|
||||
dbReqIDs := database.MustToDBUUIDArray(q.RequiredQueryIDs)
|
||||
dbReqIDs := []pgtype.UUID{}
|
||||
if q.RequiredQueryIDs != nil {
|
||||
dbReqIDs = database.MustToDBUUIDArray(*q.RequiredQueryIDs)
|
||||
}
|
||||
ty, err := queryprocessor.ToDBNullQueryType(q.Type)
|
||||
assert.Nil(t, err)
|
||||
rows = rows.
|
||||
@@ -87,11 +91,11 @@ func TestService(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedQueries := []*queryprocessor.Query{
|
||||
{ID: querySixID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{contextID}, Version: querySixVersion},
|
||||
{ID: queryFiveID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{querySixID}, Version: queryFiveVersion},
|
||||
{ID: queryOneID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{contextID}, Version: queryOneVersion},
|
||||
{ID: queryThreeID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{queryOneID}, Version: queryThreeVersion},
|
||||
{ID: queryTwoID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: []uuid.UUID{queryOneID}, Version: queryTwoVersion},
|
||||
{ID: querySixID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{contextID}, Version: querySixVersion},
|
||||
{ID: queryFiveID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{querySixID}, Version: queryFiveVersion},
|
||||
{ID: queryOneID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{contextID}, Version: queryOneVersion},
|
||||
{ID: queryThreeID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{queryOneID}, Version: queryThreeVersion},
|
||||
{ID: queryTwoID, Type: queryprocessor.TypeJsonExtractor, RequiredQueryIDs: &[]uuid.UUID{queryOneID}, Version: queryTwoVersion},
|
||||
}
|
||||
|
||||
docID := uuid.New()
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
contextfull "queryorchestration/internal/query/types/contextFull"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -30,9 +29,7 @@ func TestCreatorValidate(t *testing.T) {
|
||||
assert.NotNil(t, svc)
|
||||
|
||||
entity := &queryprocessor.Create{
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
}
|
||||
|
||||
err = svc.Validate(ctx, entity)
|
||||
|
||||
@@ -17,15 +17,14 @@ func TestContextFull(t *testing.T) {
|
||||
extractor := contextfull.NewExtractor()
|
||||
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Version: int32(1),
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
Version: int32(1),
|
||||
}
|
||||
|
||||
values := []result.Value{}
|
||||
|
||||
value, err := extractor.Process(ctx, query, values)
|
||||
value, err := extractor.Process(ctx, query, &values)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "", value)
|
||||
|
||||
@@ -33,6 +32,6 @@ func TestContextFull(t *testing.T) {
|
||||
contextfull.NewResult("example_result"),
|
||||
}
|
||||
|
||||
_, err = extractor.Process(ctx, query, values)
|
||||
_, err = extractor.Process(ctx, query, &values)
|
||||
assert.EqualError(t, err, "no requirements expected")
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ func NewExtractor() Extractor {
|
||||
return Extractor{}
|
||||
}
|
||||
|
||||
func (e Extractor) Process(ctx context.Context, query *queryprocessor.Query, values []result.Value) (string, error) {
|
||||
if len(values) > 0 {
|
||||
func (e Extractor) Process(ctx context.Context, query *queryprocessor.Query, values *[]result.Value) (string, error) {
|
||||
if values != nil && len(*values) > 0 {
|
||||
return "", errors.New("no requirements expected")
|
||||
}
|
||||
// TODO
|
||||
|
||||
@@ -30,17 +30,13 @@ func TestUpdatorValidate(t *testing.T) {
|
||||
assert.NotNil(t, svc)
|
||||
|
||||
current := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
Version: int32(1),
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
Version: int32(1),
|
||||
}
|
||||
|
||||
entity := &queryprocessor.Update{
|
||||
ID: current.ID,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
ID: current.ID,
|
||||
}
|
||||
|
||||
err = svc.Validate(ctx, current, entity)
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
jsonextractor "queryorchestration/internal/query/types/jsonExtractor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -30,9 +29,7 @@ func TestCreatorValidate(t *testing.T) {
|
||||
assert.NotNil(t, svc)
|
||||
|
||||
entity := &queryprocessor.Create{
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
}
|
||||
|
||||
err = svc.Validate(ctx, entity)
|
||||
|
||||
@@ -33,10 +33,9 @@ func TestJSONProcess(t *testing.T) {
|
||||
extractor := jsonextractor.NewExtractor(db)
|
||||
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Version: int32(1),
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
Version: int32(1),
|
||||
}
|
||||
entryValue := "value"
|
||||
|
||||
@@ -53,7 +52,7 @@ func TestJSONProcess(t *testing.T) {
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err := extractor.Process(ctx, query, values)
|
||||
value, err := extractor.Process(ctx, query, &values)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, entryValue, value)
|
||||
|
||||
@@ -68,7 +67,7 @@ func TestJSONProcess(t *testing.T) {
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
value, err = extractor.Process(ctx, query, &values)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, entryValue, value)
|
||||
|
||||
@@ -83,7 +82,7 @@ func TestJSONProcess(t *testing.T) {
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
value, err = extractor.Process(ctx, query, &values)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, entryValue, value)
|
||||
}
|
||||
@@ -104,10 +103,9 @@ func TestJSONProcessJSON(t *testing.T) {
|
||||
extractor := jsonextractor.NewExtractor(db)
|
||||
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Version: int32(1),
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
Version: int32(1),
|
||||
}
|
||||
entryValue := "value"
|
||||
|
||||
@@ -124,7 +122,7 @@ func TestJSONProcessJSON(t *testing.T) {
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err := extractor.Process(ctx, query, values)
|
||||
value, err := extractor.Process(ctx, query, &values)
|
||||
assert.EqualError(t, err, "JSON path does not exist: invalid_key")
|
||||
assert.Empty(t, value)
|
||||
|
||||
@@ -136,7 +134,7 @@ func TestJSONProcessJSON(t *testing.T) {
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
value, err = extractor.Process(ctx, query, &values)
|
||||
assert.EqualError(t, err, "unexpected end of JSON input")
|
||||
assert.Empty(t, value)
|
||||
|
||||
@@ -148,7 +146,7 @@ func TestJSONProcessJSON(t *testing.T) {
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
value, err = extractor.Process(ctx, query, &values)
|
||||
assert.EqualError(t, err, "JSON path does not exist: ")
|
||||
assert.Empty(t, value)
|
||||
|
||||
@@ -160,7 +158,7 @@ func TestJSONProcessJSON(t *testing.T) {
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
value, err = extractor.Process(ctx, query, &values)
|
||||
assert.EqualError(t, err, "invalid character '}' looking for beginning of value")
|
||||
assert.Empty(t, value)
|
||||
|
||||
@@ -169,7 +167,7 @@ func TestJSONProcessJSON(t *testing.T) {
|
||||
pgxmock.NewRows([]string{"id", "config"}),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
value, err = extractor.Process(ctx, query, &values)
|
||||
assert.EqualError(t, err, "no rows in result set")
|
||||
assert.Empty(t, value)
|
||||
}
|
||||
@@ -190,14 +188,13 @@ func TestJSONProcessResults(t *testing.T) {
|
||||
extractor := jsonextractor.NewExtractor(db)
|
||||
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Version: int32(1),
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
Version: int32(1),
|
||||
}
|
||||
|
||||
results := []result.Value{}
|
||||
value, err := extractor.Process(ctx, query, results)
|
||||
value, err := extractor.Process(ctx, query, &results)
|
||||
assert.EqualError(t, err, "JSON Extraction requires 1 result")
|
||||
assert.Empty(t, value)
|
||||
|
||||
@@ -205,7 +202,7 @@ func TestJSONProcessResults(t *testing.T) {
|
||||
contextfull.NewResult(""),
|
||||
contextfull.NewResult(""),
|
||||
}
|
||||
value, err = extractor.Process(ctx, query, results)
|
||||
value, err = extractor.Process(ctx, query, &results)
|
||||
assert.EqualError(t, err, "JSON Extraction requires 1 result")
|
||||
assert.Empty(t, value)
|
||||
|
||||
@@ -214,7 +211,7 @@ func TestJSONProcessResults(t *testing.T) {
|
||||
contextfull.NewResult(""),
|
||||
contextfull.NewResult(""),
|
||||
}
|
||||
value, err = extractor.Process(ctx, query, results)
|
||||
value, err = extractor.Process(ctx, query, &results)
|
||||
assert.EqualError(t, err, "JSON Extraction requires 1 result")
|
||||
assert.Empty(t, value)
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ func NewExtractor(db *database.Connection) Extractor {
|
||||
return Extractor{db}
|
||||
}
|
||||
|
||||
func (e Extractor) Process(ctx context.Context, query *queryprocessor.Query, values []result.Value) (string, error) {
|
||||
if len(values) != 1 {
|
||||
func (e Extractor) Process(ctx context.Context, query *queryprocessor.Query, values *[]result.Value) (string, error) {
|
||||
if values == nil || len(*values) != 1 {
|
||||
return "", fmt.Errorf("JSON Extraction requires 1 result")
|
||||
}
|
||||
|
||||
value, err := values[0].GetValue(ctx)
|
||||
value, err := (*values)[0].GetValue(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -30,17 +30,13 @@ func TestUpdatorValidate(t *testing.T) {
|
||||
assert.NotNil(t, svc)
|
||||
|
||||
current := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
Version: int32(1),
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
Version: int32(1),
|
||||
}
|
||||
|
||||
entity := &queryprocessor.Update{
|
||||
ID: current.ID,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
ID: current.ID,
|
||||
}
|
||||
|
||||
err = svc.Validate(ctx, current, entity)
|
||||
|
||||
+143
-5
@@ -3,9 +3,13 @@ package query
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
contextfull "queryorchestration/internal/query/types/contextFull"
|
||||
jsonextractor "queryorchestration/internal/query/types/jsonExtractor"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func (s *Service) Update(ctx context.Context, entity *queryprocessor.Update) error {
|
||||
@@ -14,6 +18,35 @@ func (s *Service) Update(ctx context.Context, entity *queryprocessor.Update) err
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.normalizeUpdate(ctx, current, entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.submitUpdate(ctx, current, entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) normalizeUpdate(ctx context.Context, current *Query, entity *queryprocessor.Update) error {
|
||||
err := s.normalizeActiveVersion(current, entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.normalizeQueryIDs(ctx, entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.normalizeConfig(entity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
validator, err := s.getUpdator(current.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -24,18 +57,123 @@ func (s *Service) Update(ctx context.Context, entity *queryprocessor.Update) err
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.submitUpdate(ctx, entity)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) submitUpdate(ctx context.Context, current *Query, entity *queryprocessor.Update) error {
|
||||
tx, err := s.db.Pool.Begin(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = tx.Rollback(ctx)
|
||||
}()
|
||||
|
||||
qtx := s.db.Queries.WithTx(tx)
|
||||
|
||||
latestVersion := current.LatestVersion + 1
|
||||
id := database.MustToDBUUID(entity.ID)
|
||||
|
||||
hasChanges := false
|
||||
|
||||
addIDs := getSetDifference(entity.RequiredQueryIDs, current.RequiredQueryIDs)
|
||||
for _, qID := range addIDs {
|
||||
err = qtx.AddRequiredQuery(ctx, &repository.AddRequiredQueryParams{
|
||||
Queryid: id,
|
||||
Requiredqueryid: database.MustToDBUUID(qID),
|
||||
Addedversion: latestVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hasChanges = true
|
||||
}
|
||||
|
||||
removeIDs := getSetDifference(current.RequiredQueryIDs, entity.RequiredQueryIDs)
|
||||
for _, qID := range removeIDs {
|
||||
err = qtx.RemoveRequiredQuery(ctx, &repository.RemoveRequiredQueryParams{
|
||||
Queryid: id,
|
||||
Requiredqueryid: database.MustToDBUUID(qID),
|
||||
Removedversion: &latestVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasChanges = true
|
||||
}
|
||||
|
||||
if entity.Config != nil && *entity.Config != "" {
|
||||
err = qtx.RemoveQueryConfig(ctx, &repository.RemoveQueryConfigParams{
|
||||
Queryid: id,
|
||||
Removedversion: &latestVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = qtx.AddQueryConfig(ctx, &repository.AddQueryConfigParams{
|
||||
Queryid: id,
|
||||
Config: []byte(*entity.Config),
|
||||
Addedversion: latestVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasChanges = true
|
||||
}
|
||||
|
||||
activeVersion := current.ActiveVersion
|
||||
if entity.ActiveVersion != nil {
|
||||
activeVersion = *entity.ActiveVersion
|
||||
}
|
||||
|
||||
if activeVersion != current.ActiveVersion {
|
||||
hasChanges = true
|
||||
}
|
||||
|
||||
if hasChanges {
|
||||
err = qtx.UpdateQuery(ctx, &repository.UpdateQueryParams{
|
||||
Latestversion: latestVersion,
|
||||
Activeversion: activeVersion,
|
||||
ID: id,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) submitUpdate(ctx context.Context, entity *queryprocessor.Update) error {
|
||||
// TODO - generate new entity
|
||||
// TODO - submit update - id, type, activeversion, requiredQueryId, Config
|
||||
return nil
|
||||
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
|
||||
}
|
||||
|
||||
func (s *Service) getUpdator(qType queryprocessor.Type) (queryprocessor.Updator, error) {
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -30,29 +32,23 @@ func TestUpdate(t *testing.T) {
|
||||
config := "{\"path\":\"example_path\"}"
|
||||
existing := query.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(1),
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: config,
|
||||
}
|
||||
update := &queryprocessor.Update{
|
||||
ID: existing.ID,
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: config,
|
||||
}
|
||||
|
||||
dbReqIDs := database.MustToDBUUIDArray(existing.RequiredQueryIDs)
|
||||
|
||||
pool.ExpectQuery("name: GetQuery :one").WithArgs(database.MustToDBUUID(update.ID)).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "type", "activeVersion", "latestVersion", "config", "requiredIds"}).
|
||||
AddRow(database.MustToDBUUID(existing.ID), repository.QuerytypeJsonExtractor, existing.ActiveVersion, existing.LatestVersion, []byte(config), dbReqIDs),
|
||||
AddRow(database.MustToDBUUID(existing.ID), repository.QuerytypeJsonExtractor, existing.ActiveVersion, existing.LatestVersion, []byte(config), []pgtype.UUID{}),
|
||||
)
|
||||
|
||||
pool.ExpectBeginTx(pgx.TxOptions{})
|
||||
pool.ExpectExec("name: UpdateQuery :exec").WithArgs(int32(1), int32(2), database.MustToDBUUID(update.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectCommit()
|
||||
|
||||
err = svc.Update(ctx, update)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
@@ -2,12 +2,14 @@ package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -56,17 +58,246 @@ func TestSubmitUpdate(t *testing.T) {
|
||||
config := "{\"path\":\"example_path\"}"
|
||||
q := Query{
|
||||
ID: uuid.New(),
|
||||
RequiredQueryIDs: []uuid.UUID{
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: config,
|
||||
Config: &config,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
}
|
||||
aV := int32(10)
|
||||
update := &queryprocessor.Update{
|
||||
ID: q.ID,
|
||||
RequiredQueryIDs: q.RequiredQueryIDs,
|
||||
Config: q.Config,
|
||||
ID: q.ID,
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
},
|
||||
Config: q.Config,
|
||||
ActiveVersion: &aV,
|
||||
}
|
||||
|
||||
err = svc.submitUpdate(ctx, update)
|
||||
pool.ExpectBeginTx(pgx.TxOptions{})
|
||||
pool.ExpectExec("name: AddRequiredQuery :exec").WithArgs(database.MustToDBUUID(update.ID), database.MustToDBUUID((*update.RequiredQueryIDs)[0]), pgxmock.AnyArg()).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectExec("name: RemoveRequiredQuery :exec").WithArgs(pgxmock.AnyArg(), database.MustToDBUUID((*q.RequiredQueryIDs)[0]), database.MustToDBUUID(update.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectExec("name: RemoveQueryConfig :exec").WithArgs(pgxmock.AnyArg(), database.MustToDBUUID(update.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectExec("name: AddQueryConfig :exec").WithArgs(database.MustToDBUUID(update.ID), []byte(*update.Config), int32(3)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectExec("name: UpdateQuery :exec").WithArgs(aV, int32(3), database.MustToDBUUID(update.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectCommit()
|
||||
|
||||
err = svc.submitUpdate(ctx, &q, update)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestSubmitUpdateRollback(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
pool, err := pgxmock.NewPool()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open pgxmock database: %v", err)
|
||||
}
|
||||
queries := repository.New(pool)
|
||||
db := &database.Connection{
|
||||
Queries: queries,
|
||||
Pool: pool,
|
||||
}
|
||||
svc := New(db)
|
||||
|
||||
q := Query{
|
||||
ID: uuid.New(),
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
}
|
||||
aV := int32(10)
|
||||
update := &queryprocessor.Update{
|
||||
ID: q.ID,
|
||||
ActiveVersion: &aV,
|
||||
}
|
||||
|
||||
pool.ExpectBeginTx(pgx.TxOptions{})
|
||||
msg := "database failure"
|
||||
pool.ExpectExec("name: UpdateQuery :exec").WithArgs(aV, int32(3), database.MustToDBUUID(update.ID)).
|
||||
WillReturnError(errors.New(msg))
|
||||
pool.ExpectCommit()
|
||||
|
||||
err = svc.submitUpdate(ctx, &q, update)
|
||||
assert.EqualError(t, err, msg)
|
||||
}
|
||||
|
||||
func TestSubmitUpdateRequiredQueries(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
pool, err := pgxmock.NewPool()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open pgxmock database: %v", err)
|
||||
}
|
||||
queries := repository.New(pool)
|
||||
db := &database.Connection{
|
||||
Queries: queries,
|
||||
Pool: pool,
|
||||
}
|
||||
svc := New(db)
|
||||
|
||||
config := "{\"path\":\"example_path\"}"
|
||||
q := Query{
|
||||
ID: uuid.New(),
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
uuid.New(),
|
||||
uuid.New(),
|
||||
},
|
||||
Config: &config,
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
}
|
||||
update := &queryprocessor.Update{
|
||||
ID: q.ID,
|
||||
RequiredQueryIDs: &[]uuid.UUID{
|
||||
uuid.New(),
|
||||
uuid.New(),
|
||||
(*q.RequiredQueryIDs)[0],
|
||||
},
|
||||
}
|
||||
|
||||
pool.ExpectBeginTx(pgx.TxOptions{})
|
||||
pool.ExpectExec("name: AddRequiredQuery :exec").WithArgs(database.MustToDBUUID(update.ID), database.MustToDBUUID((*update.RequiredQueryIDs)[0]), pgxmock.AnyArg()).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectExec("name: AddRequiredQuery :exec").WithArgs(database.MustToDBUUID(update.ID), database.MustToDBUUID((*update.RequiredQueryIDs)[1]), pgxmock.AnyArg()).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectExec("name: RemoveRequiredQuery :exec").WithArgs(pgxmock.AnyArg(), database.MustToDBUUID((*q.RequiredQueryIDs)[1]), database.MustToDBUUID(update.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectExec("name: RemoveRequiredQuery :exec").WithArgs(pgxmock.AnyArg(), database.MustToDBUUID((*q.RequiredQueryIDs)[2]), database.MustToDBUUID(update.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectExec("name: UpdateQuery :exec").WithArgs(q.ActiveVersion, int32(3), database.MustToDBUUID(update.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectCommit()
|
||||
|
||||
err = svc.submitUpdate(ctx, &q, update)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestSubmitUpdateActiveVersion(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
pool, err := pgxmock.NewPool()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open pgxmock database: %v", err)
|
||||
}
|
||||
queries := repository.New(pool)
|
||||
db := &database.Connection{
|
||||
Queries: queries,
|
||||
Pool: pool,
|
||||
}
|
||||
svc := New(db)
|
||||
|
||||
q := Query{
|
||||
ID: uuid.New(),
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
}
|
||||
aV := int32(10)
|
||||
update := &queryprocessor.Update{
|
||||
ID: q.ID,
|
||||
ActiveVersion: &aV,
|
||||
}
|
||||
|
||||
pool.ExpectBeginTx(pgx.TxOptions{})
|
||||
pool.ExpectExec("name: UpdateQuery :exec").WithArgs(aV, int32(3), database.MustToDBUUID(update.ID)).
|
||||
WillReturnResult(pgxmock.NewResult("", 1))
|
||||
pool.ExpectCommit()
|
||||
|
||||
err = svc.submitUpdate(ctx, &q, update)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestSubmitUpdateNoChange(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
pool, err := pgxmock.NewPool()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open pgxmock database: %v", err)
|
||||
}
|
||||
queries := repository.New(pool)
|
||||
db := &database.Connection{
|
||||
Queries: queries,
|
||||
Pool: pool,
|
||||
}
|
||||
svc := New(db)
|
||||
|
||||
q := Query{
|
||||
ID: uuid.New(),
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
}
|
||||
update := &queryprocessor.Update{
|
||||
ID: q.ID,
|
||||
}
|
||||
|
||||
pool.ExpectBeginTx(pgx.TxOptions{})
|
||||
pool.ExpectRollback()
|
||||
|
||||
err = svc.submitUpdate(ctx, &q, update)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestGetSetDifference(t *testing.T) {
|
||||
commonUUID := uuid.New()
|
||||
listA := []uuid.UUID{uuid.New(), commonUUID}
|
||||
listB := []uuid.UUID{uuid.New(), commonUUID}
|
||||
|
||||
assert.ElementsMatch(t, []uuid.UUID{}, getSetDifference(nil, nil))
|
||||
assert.ElementsMatch(t, listA, getSetDifference(&listA, nil))
|
||||
assert.ElementsMatch(t, []uuid.UUID{}, getSetDifference(nil, &listB))
|
||||
assert.ElementsMatch(t, []uuid.UUID{listA[0]}, getSetDifference(&listA, &listB))
|
||||
assert.ElementsMatch(t, []uuid.UUID{listB[0]}, getSetDifference(&listB, &listA))
|
||||
assert.ElementsMatch(t, []uuid.UUID{}, getSetDifference(&listA, &listA))
|
||||
}
|
||||
|
||||
func TestNormalizeUpdate(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
pool, err := pgxmock.NewPool()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open pgxmock database: %v", err)
|
||||
}
|
||||
queries := repository.New(pool)
|
||||
db := &database.Connection{
|
||||
Queries: queries,
|
||||
Pool: pool,
|
||||
}
|
||||
svc := New(db)
|
||||
|
||||
current := &Query{
|
||||
ID: uuid.New(),
|
||||
ActiveVersion: int32(1),
|
||||
LatestVersion: int32(2),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
}
|
||||
cfg := "{}"
|
||||
aV := int32(2)
|
||||
update := &queryprocessor.Update{
|
||||
ID: current.ID,
|
||||
Config: &cfg,
|
||||
ActiveVersion: &aV,
|
||||
RequiredQueryIDs: &[]uuid.UUID{},
|
||||
}
|
||||
|
||||
dbids := database.MustToDBUUIDArray(*update.RequiredQueryIDs)
|
||||
|
||||
pool.ExpectQuery("name: AllQueriesExist :one").WithArgs(dbids).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"all_exist"}).
|
||||
AddRow(true),
|
||||
)
|
||||
|
||||
err = svc.normalizeUpdate(ctx, current, update)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualExportedValues(t, queryprocessor.Update{
|
||||
ID: current.ID,
|
||||
ActiveVersion: &aV,
|
||||
Config: nil,
|
||||
RequiredQueryIDs: nil,
|
||||
}, *update)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user