Merged in feature/shorttestsanddirtidy (pull request #26)
Add short tests and Tidy internal directories * complete the tasks
This commit is contained in:
@@ -3,11 +3,11 @@ package query
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
contextfull "queryorchestration/internal/contextFull"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
jsonextractor "queryorchestration/internal/jsonExtractor"
|
||||
queryprocessor "queryorchestration/internal/queryProcessor"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
contextfull "queryorchestration/internal/query/types/contextFull"
|
||||
jsonextractor "queryorchestration/internal/query/types/jsonExtractor"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/query"
|
||||
queryprocessor "queryorchestration/internal/queryProcessor"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/queryProcessor"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package document
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/job/collector"
|
||||
queryqueue "queryorchestration/internal/query/queue"
|
||||
"queryorchestration/internal/query/result"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Document struct {
|
||||
ID uuid.UUID `json:"id" validate:"required,uuid"`
|
||||
JobID uuid.UUID `json:"jobId" validate:"required,uuid"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
CleanVersion int32 `json:"cleanVersion" validate:"required,gt=0"`
|
||||
TextVersion int32 `json:"textVersion" validate:"required,gt=0"`
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
db *database.Connection
|
||||
}
|
||||
|
||||
func New(db *database.Connection) *Service {
|
||||
return &Service{
|
||||
db,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) Sync(ctx context.Context, doc *Document) error {
|
||||
collector, err := collector.NewByJobId(ctx, s.db, doc.JobID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
results, err := s.getResults(ctx, doc.ID, collector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
queue, err := queryqueue.New(ctx, s.db, collector, results, doc.ID, doc.CleanVersion, doc.TextVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = queue.Execute(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) getResults(ctx context.Context, id uuid.UUID, coll *collector.Collector) ([]*result.Result, error) {
|
||||
docID := database.MustToDBUUID(id)
|
||||
|
||||
results, err := s.db.Queries.ListResultsByDocumentID(ctx, &repository.ListResultsByDocumentIDParams{
|
||||
Documentid: docID,
|
||||
Textversion: coll.MinTextVersion,
|
||||
Cleanversion: coll.MinCleanVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cleanResults := make([]*result.Result, len(results))
|
||||
for index, dbResult := range results {
|
||||
cleanResults[index] = result.Parse(dbResult)
|
||||
}
|
||||
|
||||
return cleanResults, nil
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package document_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/query/document"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSyncIsSynced(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,
|
||||
}
|
||||
|
||||
doc := document.Document{
|
||||
ID: uuid.New(),
|
||||
JobID: uuid.New(),
|
||||
Name: "document_name",
|
||||
}
|
||||
|
||||
dbCollectorId := database.MustToDBUUID(uuid.New())
|
||||
dbJobID := database.MustToDBUUID(doc.JobID)
|
||||
minCleanVersion := int32(1)
|
||||
minTextVersion := int32(1)
|
||||
qV := int32(1)
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorFromJobID :one").WithArgs(dbJobID).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "jobId", "minCleanVersion", "minTextVersion"}).
|
||||
AddRow(dbCollectorId, dbJobID, minCleanVersion, minTextVersion),
|
||||
)
|
||||
pool.ExpectQuery("name: ListResultsByDocumentID :many").WithArgs(database.MustToDBUUID(doc.ID), minCleanVersion, minTextVersion).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "queryVersion"}).
|
||||
AddRow(pgtype.UUID{}, pgtype.UUID{}, qV),
|
||||
)
|
||||
pool.ExpectQuery("name: GetCollectorQueries :many").WithArgs(dbCollectorId).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"collectorId", "queryId", "type", "queryVersion", "requiredIds"}).
|
||||
AddRow(dbCollectorId, pgtype.UUID{}, repository.NullQuerytype{Querytype: repository.QuerytypeJsonExtractor, Valid: true}, &qV, []pgtype.UUID{}),
|
||||
)
|
||||
|
||||
docSvc := document.New(db)
|
||||
err = docSvc.Sync(ctx, &doc)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestSyncDBFail(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,
|
||||
}
|
||||
|
||||
doc := document.Document{
|
||||
ID: uuid.New(),
|
||||
JobID: uuid.New(),
|
||||
Name: "document_name",
|
||||
}
|
||||
|
||||
dbCollectorId := database.MustToDBUUID(uuid.New())
|
||||
dbJobID := database.MustToDBUUID(doc.JobID)
|
||||
dbQueryID := database.MustToDBUUID(uuid.New())
|
||||
minCleanVersion := int32(1)
|
||||
minTextVersion := int32(1)
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorFromJobID :one").WithArgs(dbJobID).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "jobId", "minCleanVersion", "minTextVersion"}),
|
||||
)
|
||||
|
||||
docSvc := document.New(db)
|
||||
err = docSvc.Sync(ctx, &doc)
|
||||
assert.EqualError(t, err, "no rows in result set")
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorFromJobID :one").WithArgs(dbJobID).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "jobId", "minCleanVersion", "minTextVersion"}).
|
||||
AddRow(dbCollectorId, dbJobID, minCleanVersion, minTextVersion),
|
||||
)
|
||||
dbErr := "database failure"
|
||||
pool.ExpectQuery("name: ListResultsByDocumentID :many").WithArgs(database.MustToDBUUID(doc.ID), minCleanVersion, minTextVersion).
|
||||
WillReturnError(errors.New(dbErr))
|
||||
|
||||
docSvc = document.New(db)
|
||||
err = docSvc.Sync(ctx, &doc)
|
||||
assert.EqualError(t, err, dbErr)
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorFromJobID :one").WithArgs(dbJobID).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "jobId", "minCleanVersion", "minTextVersion"}).
|
||||
AddRow(dbCollectorId, dbJobID, minCleanVersion, minTextVersion),
|
||||
)
|
||||
pool.ExpectQuery("name: ListResultsByDocumentID :many").WithArgs(database.MustToDBUUID(doc.ID), minCleanVersion, minTextVersion).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "queryVersion"}),
|
||||
)
|
||||
dbErr = "database failure"
|
||||
pool.ExpectQuery("name: GetCollectorQueries :many").WithArgs(dbCollectorId).
|
||||
WillReturnError(errors.New(dbErr))
|
||||
|
||||
docSvc = document.New(db)
|
||||
err = docSvc.Sync(ctx, &doc)
|
||||
assert.EqualError(t, err, dbErr)
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorFromJobID :one").WithArgs(dbJobID).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "jobId", "minCleanVersion", "minTextVersion"}).
|
||||
AddRow(dbCollectorId, dbJobID, minCleanVersion, minTextVersion),
|
||||
)
|
||||
pool.ExpectQuery("name: ListResultsByDocumentID :many").WithArgs(database.MustToDBUUID(doc.ID), minCleanVersion, minTextVersion).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "queryVersion"}),
|
||||
)
|
||||
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{}),
|
||||
)
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs([]pgtype.UUID{}).
|
||||
WillReturnError(errors.New(dbErr))
|
||||
|
||||
docSvc = document.New(db)
|
||||
err = docSvc.Sync(ctx, &doc)
|
||||
assert.EqualError(t, err, dbErr)
|
||||
}
|
||||
|
||||
func TestSync(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,
|
||||
}
|
||||
|
||||
doc := document.Document{
|
||||
ID: uuid.New(),
|
||||
JobID: uuid.New(),
|
||||
Name: "document_name",
|
||||
}
|
||||
|
||||
dbCollectorId := database.MustToDBUUID(uuid.New())
|
||||
dbJobID := database.MustToDBUUID(doc.JobID)
|
||||
dbQueryID := database.MustToDBUUID(uuid.New())
|
||||
minCleanVersion := int32(1)
|
||||
minTextVersion := int32(1)
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorFromJobID :one").WithArgs(dbJobID).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "jobId", "minCleanVersion", "minTextVersion"}).
|
||||
AddRow(dbCollectorId, dbJobID, minCleanVersion, minTextVersion),
|
||||
)
|
||||
pool.ExpectQuery("name: ListResultsByDocumentID :many").WithArgs(database.MustToDBUUID(doc.ID), minCleanVersion, minTextVersion).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "queryVersion"}),
|
||||
)
|
||||
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{}),
|
||||
)
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs([]pgtype.UUID{}).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "value"}),
|
||||
)
|
||||
|
||||
docSvc := document.New(db)
|
||||
err = docSvc.Sync(ctx, &doc)
|
||||
assert.EqualError(t, err, "JSON Extraction requires 1 result")
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/queryProcessor"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/query"
|
||||
queryprocessor "queryorchestration/internal/queryProcessor"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/query"
|
||||
queryprocessor "queryorchestration/internal/queryProcessor"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/query"
|
||||
queryprocessor "queryorchestration/internal/queryProcessor"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package queryprocessor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
)
|
||||
|
||||
func ParseDBNullType(qType repository.NullQuerytype) (Type, error) {
|
||||
if !qType.Valid {
|
||||
return TypeJsonExtractor, fmt.Errorf("invalid database query type")
|
||||
}
|
||||
|
||||
return ParseDBType(qType.Querytype)
|
||||
}
|
||||
|
||||
func ParseDBType(qType repository.Querytype) (Type, error) {
|
||||
switch qType {
|
||||
case repository.QuerytypeJsonExtractor:
|
||||
return TypeJsonExtractor, nil
|
||||
case repository.QuerytypeContextFull:
|
||||
return TypeContextFull, nil
|
||||
default:
|
||||
return TypeJsonExtractor, fmt.Errorf("invalid database query type")
|
||||
}
|
||||
}
|
||||
|
||||
func ToDBQueryType(t Type) (repository.Querytype, error) {
|
||||
var dbType repository.Querytype
|
||||
|
||||
switch t {
|
||||
case TypeJsonExtractor:
|
||||
dbType = repository.QuerytypeJsonExtractor
|
||||
case TypeContextFull:
|
||||
dbType = repository.QuerytypeContextFull
|
||||
default:
|
||||
return repository.QuerytypeContextFull, fmt.Errorf("invalid database query type")
|
||||
}
|
||||
|
||||
return dbType, nil
|
||||
}
|
||||
|
||||
func ToDBQueryTypeArray(t []Type) ([]repository.Querytype, error) {
|
||||
arr := make([]repository.Querytype, len(t))
|
||||
for index, value := range t {
|
||||
v, err := ToDBQueryType(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
arr[index] = v
|
||||
}
|
||||
|
||||
return arr, nil
|
||||
}
|
||||
|
||||
func ToDBNullQueryType(t Type) (repository.NullQuerytype, error) {
|
||||
dbType, err := ToDBQueryType(t)
|
||||
if err != nil {
|
||||
return repository.NullQuerytype{}, err
|
||||
}
|
||||
|
||||
return repository.NullQuerytype{Querytype: dbType, Valid: true}, nil
|
||||
}
|
||||
|
||||
func ParseDBCollectorQuery(q *repository.GetCollectorQueriesRow) (*Query, error) {
|
||||
reqQueryIDs := database.MustToUUIDArray(q.Requiredids)
|
||||
|
||||
qType, err := ParseDBNullType(q.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Query{
|
||||
ID: database.MustToUUID(q.Queryid),
|
||||
Version: *q.Queryversion,
|
||||
Type: qType,
|
||||
RequiredQueryIDs: reqQueryIDs,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package queryprocessor_test
|
||||
|
||||
import (
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseDBCollectorQuery(t *testing.T) {
|
||||
qV := int32(0)
|
||||
dbResult := repository.GetCollectorQueriesRow{
|
||||
Collectorid: pgtype.UUID{},
|
||||
Queryid: pgtype.UUID{},
|
||||
Requiredids: []pgtype.UUID{},
|
||||
Type: repository.NullQuerytype{Valid: true, Querytype: repository.QuerytypeJsonExtractor},
|
||||
Queryversion: &qV,
|
||||
}
|
||||
value, err := queryprocessor.ParseDBCollectorQuery(&dbResult)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, uuid.Nil, value.ID)
|
||||
assert.Equal(t, []uuid.UUID{}, value.RequiredQueryIDs)
|
||||
assert.Equal(t, int32(0), value.Version)
|
||||
assert.Equal(t, queryprocessor.Type(queryprocessor.TypeJsonExtractor), value.Type)
|
||||
|
||||
dbResult.Type = repository.NullQuerytype{}
|
||||
_, err = queryprocessor.ParseDBCollectorQuery(&dbResult)
|
||||
assert.EqualError(t, err, "invalid database query type")
|
||||
}
|
||||
|
||||
func TestParseDBNullType(t *testing.T) {
|
||||
qType := repository.NullQuerytype{Valid: true, Querytype: repository.QuerytypeJsonExtractor}
|
||||
value, err := queryprocessor.ParseDBNullType(qType)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, queryprocessor.Type(queryprocessor.TypeJsonExtractor), value)
|
||||
|
||||
qType = repository.NullQuerytype{}
|
||||
_, err = queryprocessor.ParseDBNullType(qType)
|
||||
assert.EqualError(t, err, "invalid database query type")
|
||||
|
||||
qType = repository.NullQuerytype{Valid: true}
|
||||
_, err = queryprocessor.ParseDBNullType(qType)
|
||||
assert.EqualError(t, err, "invalid database query type")
|
||||
}
|
||||
|
||||
func TestParseDBType(t *testing.T) {
|
||||
qType := repository.QuerytypeJsonExtractor
|
||||
value, err := queryprocessor.ParseDBType(qType)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, queryprocessor.Type(queryprocessor.TypeJsonExtractor), value)
|
||||
|
||||
qType = repository.QuerytypeContextFull
|
||||
value, err = queryprocessor.ParseDBType(qType)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, queryprocessor.Type(queryprocessor.TypeContextFull), value)
|
||||
}
|
||||
|
||||
func TestToDBQueryType(t *testing.T) {
|
||||
dbQueryType := queryprocessor.Type(queryprocessor.TypeJsonExtractor)
|
||||
value, err := queryprocessor.ToDBQueryType(dbQueryType)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, repository.Querytype(repository.QuerytypeJsonExtractor), value)
|
||||
|
||||
dbQueryType = queryprocessor.Type(-1)
|
||||
_, err = queryprocessor.ToDBQueryType(dbQueryType)
|
||||
assert.EqualError(t, err, "invalid database query type")
|
||||
|
||||
dbQueryType = queryprocessor.Type(queryprocessor.TypeContextFull)
|
||||
value, err = queryprocessor.ToDBQueryType(dbQueryType)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, repository.Querytype(repository.QuerytypeContextFull), value)
|
||||
}
|
||||
|
||||
func TestToDBQueryTypeArray(t *testing.T) {
|
||||
inArr := []queryprocessor.Type{
|
||||
queryprocessor.TypeJsonExtractor,
|
||||
queryprocessor.TypeContextFull,
|
||||
}
|
||||
value, err := queryprocessor.ToDBQueryTypeArray(inArr)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []repository.Querytype{
|
||||
repository.QuerytypeJsonExtractor,
|
||||
repository.QuerytypeContextFull,
|
||||
}, value)
|
||||
|
||||
inArr = []queryprocessor.Type{
|
||||
queryprocessor.Type(-1),
|
||||
}
|
||||
_, err = queryprocessor.ToDBQueryTypeArray(inArr)
|
||||
assert.EqualError(t, err, "invalid database query type")
|
||||
}
|
||||
|
||||
func TestToDBNullQueryType(t *testing.T) {
|
||||
dbQueryType := queryprocessor.Type(queryprocessor.TypeJsonExtractor)
|
||||
value, err := queryprocessor.ToDBNullQueryType(dbQueryType)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, repository.NullQuerytype{Valid: true, Querytype: repository.QuerytypeJsonExtractor}, value)
|
||||
|
||||
dbQueryType = queryprocessor.Type(-1)
|
||||
_, err = queryprocessor.ToDBNullQueryType(dbQueryType)
|
||||
assert.EqualError(t, err, "invalid database query type")
|
||||
|
||||
dbQueryType = queryprocessor.Type(queryprocessor.TypeContextFull)
|
||||
value, err = queryprocessor.ToDBNullQueryType(dbQueryType)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, repository.NullQuerytype{Valid: true, Querytype: repository.QuerytypeContextFull}, value)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package queryprocessor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/query/result"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Type int
|
||||
|
||||
const (
|
||||
TypeJsonExtractor = iota
|
||||
TypeContextFull
|
||||
)
|
||||
|
||||
type Create struct {
|
||||
Type Type
|
||||
RequiredQueryIDs []uuid.UUID
|
||||
Config string
|
||||
}
|
||||
|
||||
type Update struct {
|
||||
ID uuid.UUID
|
||||
RequiredQueryIDs []uuid.UUID
|
||||
Config string
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
ID uuid.UUID
|
||||
Type Type
|
||||
Version int32
|
||||
RequiredQueryIDs []uuid.UUID
|
||||
Config string
|
||||
}
|
||||
|
||||
type Creator interface {
|
||||
Validate(ctx context.Context, entity *Create) error
|
||||
}
|
||||
|
||||
type Updator interface {
|
||||
Validate(ctx context.Context, current *Query, entity *Update) error
|
||||
}
|
||||
|
||||
type Processor interface {
|
||||
Process(ctx context.Context, query *Query, values []result.Value) (string, error)
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package queryqueue
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
)
|
||||
|
||||
func (q *Queue) getUnsyncedQueries() {
|
||||
for _, query := range q.collectorQueries {
|
||||
if q.isQuerySynced(query) {
|
||||
continue
|
||||
}
|
||||
|
||||
q.Add(query)
|
||||
}
|
||||
}
|
||||
|
||||
func (q *Queue) isQuerySynced(query *queryprocessor.Query) bool {
|
||||
for _, result := range q.results {
|
||||
if result.QueryID == query.ID && result.QueryVersion == query.Version {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Queue) getCollectorQueries(ctx context.Context) error {
|
||||
if c.collectorQueries != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
id := database.MustToDBUUID(c.collector.ID)
|
||||
|
||||
queries, err := c.db.Queries.GetCollectorQueries(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cleanQueries := make([]*queryprocessor.Query, len(queries))
|
||||
for index, dbQuery := range queries {
|
||||
cleanQuery, err := queryprocessor.ParseDBCollectorQuery(dbQuery)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cleanQueries[index] = cleanQuery
|
||||
}
|
||||
|
||||
c.collectorQueries = cleanQueries
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *Queue) Add(qu *queryprocessor.Query) {
|
||||
dependentQueries := []*queryprocessor.Query{}
|
||||
requiredIndex := -1
|
||||
|
||||
if q.unsyncedQueue == nil {
|
||||
q.unsyncedQueue = []*queryprocessor.Query{}
|
||||
} else {
|
||||
for index, entry := range q.unsyncedQueue {
|
||||
if entry.ID == qu.ID {
|
||||
return
|
||||
}
|
||||
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 requiredIndex != -1 {
|
||||
q.unsyncedQueue = append((q.unsyncedQueue)[:requiredIndex+1], append([]*queryprocessor.Query{qu}, (q.unsyncedQueue)[requiredIndex+1:]...)...)
|
||||
} else {
|
||||
q.unsyncedQueue = append([]*queryprocessor.Query{qu}, q.unsyncedQueue...)
|
||||
}
|
||||
|
||||
for _, entry := range dependentQueries {
|
||||
q.Add(entry)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package queryqueue
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/job/collector"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"queryorchestration/internal/query/result"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetUnsyncedQueries(t *testing.T) {
|
||||
queryOne := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Version: int32(1),
|
||||
}
|
||||
svc := Queue{
|
||||
collectorQueries: []*queryprocessor.Query{
|
||||
queryOne,
|
||||
},
|
||||
results: []*result.Result{
|
||||
{ID: uuid.New(), QueryID: queryOne.ID, QueryVersion: queryOne.Version},
|
||||
},
|
||||
}
|
||||
|
||||
svc.getUnsyncedQueries()
|
||||
assert.EqualExportedValues(t, []*queryprocessor.Query(nil), svc.unsyncedQueue)
|
||||
|
||||
svc.results = []*result.Result{}
|
||||
svc.unsyncedQueue = []*queryprocessor.Query{}
|
||||
|
||||
svc.getUnsyncedQueries()
|
||||
assert.EqualExportedValues(t, []*queryprocessor.Query{queryOne}, svc.unsyncedQueue)
|
||||
}
|
||||
|
||||
func TestGetCollectorQueries(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 := Queue{
|
||||
db: db,
|
||||
collector: &collector.Collector{
|
||||
ID: uuid.New(),
|
||||
},
|
||||
}
|
||||
dbCollectorID := database.MustToDBUUID(svc.collector.ID)
|
||||
|
||||
collectorQueries := []*queryprocessor.Query{
|
||||
{ID: uuid.New(), Type: queryprocessor.TypeContextFull, RequiredQueryIDs: []uuid.UUID{}, 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)
|
||||
ty, err := queryprocessor.ToDBNullQueryType(q.Type)
|
||||
assert.Nil(t, err)
|
||||
rows = rows.
|
||||
AddRow(dbCollectorID, dbID, ty, &q.Version, dbReqIDs)
|
||||
}
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorQueries :many").WithArgs(dbCollectorID).WillReturnRows(rows)
|
||||
|
||||
err = svc.getCollectorQueries(ctx)
|
||||
assert.Nil(t, err)
|
||||
assert.EqualExportedValues(t, collectorQueries, svc.collectorQueries)
|
||||
}
|
||||
|
||||
func TestIsQuerySynced(t *testing.T) {
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Version: int32(1),
|
||||
}
|
||||
svc := Queue{
|
||||
results: []*result.Result{
|
||||
{QueryID: query.ID, QueryVersion: query.Version},
|
||||
},
|
||||
}
|
||||
|
||||
isSynced := svc.isQuerySynced(query)
|
||||
assert.True(t, isSynced)
|
||||
}
|
||||
|
||||
func TestIsQuerySyncedNoResult(t *testing.T) {
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Version: int32(1),
|
||||
}
|
||||
svc := Queue{
|
||||
results: []*result.Result{},
|
||||
}
|
||||
|
||||
isSynced := svc.isQuerySynced(query)
|
||||
assert.False(t, isSynced)
|
||||
}
|
||||
|
||||
func TestIsQuerySyncedOldResult(t *testing.T) {
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Version: int32(1),
|
||||
}
|
||||
svc := Queue{
|
||||
results: []*result.Result{
|
||||
{QueryID: query.ID, QueryVersion: query.Version - 1},
|
||||
},
|
||||
}
|
||||
|
||||
isSynced := svc.isQuerySynced(query)
|
||||
assert.False(t, isSynced)
|
||||
}
|
||||
|
||||
func TestIsQuerySyncedNewResult(t *testing.T) {
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Version: int32(1),
|
||||
}
|
||||
svc := Queue{
|
||||
results: []*result.Result{
|
||||
{QueryID: query.ID, QueryVersion: query.Version + 1},
|
||||
},
|
||||
}
|
||||
|
||||
isSynced := svc.isQuerySynced(query)
|
||||
assert.False(t, isSynced)
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package queryqueue
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"queryorchestration/internal/query/result"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func (q *Queue) Execute(ctx context.Context) error {
|
||||
if q.unsyncedQueue == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, query := range q.unsyncedQueue {
|
||||
err := q.executeQuery(ctx, query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
q.unsyncedQueue = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package queryqueue_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/job/collector"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
queryqueue "queryorchestration/internal/query/queue"
|
||||
"queryorchestration/internal/query/result"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestExecute(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,
|
||||
}
|
||||
jobID := uuid.New()
|
||||
dbJobID := database.MustToDBUUID(jobID)
|
||||
collectorID := uuid.New()
|
||||
dbCollectorID := database.MustToDBUUID(collectorID)
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorFromJobID :one").WithArgs(dbJobID).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "jobId", "minCleanVersion", "minTextVersion"}).
|
||||
AddRow(dbCollectorID, dbJobID, int32(1), int32(1)),
|
||||
)
|
||||
|
||||
coll, err := collector.NewByJobId(ctx, db, jobID)
|
||||
assert.Nil(t, err)
|
||||
|
||||
queryOneID := uuid.New()
|
||||
queryOneVersion := int32(1)
|
||||
queryTwoID := uuid.New()
|
||||
queryTwoVersion := int32(2)
|
||||
queryThreeID := uuid.New()
|
||||
queryThreeVersion := int32(3)
|
||||
queryFourID := uuid.New()
|
||||
queryFourVersion := int32(4)
|
||||
queryFiveID := uuid.New()
|
||||
queryFiveVersion := int32(5)
|
||||
querySixID := uuid.New()
|
||||
querySixVersion := int32(6)
|
||||
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},
|
||||
}
|
||||
|
||||
rows := pgxmock.NewRows([]string{"collectorId", "queryId", "type", "queryVersion", "requiredIds"})
|
||||
for _, q := range collectorQueries {
|
||||
dbID := database.MustToDBUUID(q.ID)
|
||||
dbReqIDs := database.MustToDBUUIDArray(q.RequiredQueryIDs)
|
||||
ty, err := queryprocessor.ToDBNullQueryType(q.Type)
|
||||
assert.Nil(t, err)
|
||||
rows = rows.
|
||||
AddRow(dbCollectorID, dbID, ty, &q.Version, dbReqIDs)
|
||||
}
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorQueries :many").WithArgs(dbCollectorID).WillReturnRows(rows)
|
||||
|
||||
contextResultID := uuid.New()
|
||||
results := []*result.Result{
|
||||
{ID: contextResultID, QueryID: contextID, QueryVersion: contextVersion},
|
||||
{ID: uuid.New(), QueryID: queryFourID, QueryVersion: queryFourVersion},
|
||||
{ID: uuid.New(), QueryID: querySixID, QueryVersion: querySixVersion - 1},
|
||||
{ID: uuid.New(), QueryID: queryOneID, QueryVersion: queryOneVersion - 1},
|
||||
}
|
||||
|
||||
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},
|
||||
}
|
||||
|
||||
docID := uuid.New()
|
||||
cleanVersion := int32(1)
|
||||
textVersion := int32(1)
|
||||
|
||||
q, err := queryqueue.New(ctx, db, coll, results, docID, cleanVersion, textVersion)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expectedQueries, q.GetQueue())
|
||||
|
||||
keyLayerOne := "key"
|
||||
keyLayerTwo := "key5"
|
||||
valueLayerTwo := "value"
|
||||
valueLayerOne := fmt.Sprintf("{\"%s\":\"%s\"}", keyLayerTwo, valueLayerTwo)
|
||||
valueContext := fmt.Sprintf("{\"%s\":%s}", keyLayerOne, valueLayerOne)
|
||||
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs([]pgtype.UUID{database.MustToDBUUID(contextResultID)}).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "value"}).
|
||||
AddRow(database.MustToDBUUID(contextResultID), database.MustToDBUUID(contextID), valueContext),
|
||||
)
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(querySixID), querySixVersion).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(fmt.Sprintf("{\"path\":\"%s\"}", keyLayerOne))),
|
||||
)
|
||||
pool.ExpectQuery("name: SetResult :one").WithArgs(database.MustToDBUUID(querySixID), database.MustToDBUUID(docID), valueLayerOne, cleanVersion, textVersion, querySixVersion).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).AddRow(pgtype.UUID{}),
|
||||
)
|
||||
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs(pgxmock.AnyArg()).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "value"}).
|
||||
AddRow(pgtype.UUID{}, database.MustToDBUUID(querySixID), valueLayerOne),
|
||||
)
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(queryFiveID), queryFiveVersion).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(fmt.Sprintf("{\"path\":\"%s\"}", keyLayerTwo))),
|
||||
)
|
||||
pool.ExpectQuery("name: SetResult :one").WithArgs(database.MustToDBUUID(queryFiveID), database.MustToDBUUID(docID), valueLayerTwo, cleanVersion, textVersion, queryFiveVersion).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).AddRow(pgtype.UUID{}),
|
||||
)
|
||||
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs(pgxmock.AnyArg()).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "value"}).
|
||||
AddRow(database.MustToDBUUID(contextResultID), database.MustToDBUUID(contextID), valueContext),
|
||||
)
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(queryOneID), queryOneVersion).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(fmt.Sprintf("{\"path\":\"%s\"}", keyLayerOne))),
|
||||
)
|
||||
pool.ExpectQuery("name: SetResult :one").WithArgs(database.MustToDBUUID(queryOneID), database.MustToDBUUID(docID), valueLayerOne, cleanVersion, textVersion, queryOneVersion).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).AddRow(pgtype.UUID{}),
|
||||
)
|
||||
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs(pgxmock.AnyArg()).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "value"}).
|
||||
AddRow(pgtype.UUID{}, database.MustToDBUUID(queryOneID), valueLayerOne),
|
||||
)
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(queryThreeID), queryThreeVersion).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(fmt.Sprintf("{\"path\":\"%s\"}", keyLayerTwo))),
|
||||
)
|
||||
pool.ExpectQuery("name: SetResult :one").WithArgs(database.MustToDBUUID(queryThreeID), database.MustToDBUUID(docID), valueLayerTwo, cleanVersion, textVersion, queryThreeVersion).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).AddRow(pgtype.UUID{}),
|
||||
)
|
||||
|
||||
pool.ExpectQuery("name: ListResultValuesByID :many").WithArgs(pgxmock.AnyArg()).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "queryId", "value"}).
|
||||
AddRow(pgtype.UUID{}, database.MustToDBUUID(queryOneID), valueLayerOne),
|
||||
)
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(queryTwoID), queryTwoVersion).WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(fmt.Sprintf("{\"path\":\"%s\"}", keyLayerTwo))),
|
||||
)
|
||||
pool.ExpectQuery("name: SetResult :one").WithArgs(database.MustToDBUUID(queryTwoID), database.MustToDBUUID(docID), valueLayerTwo, cleanVersion, textVersion, queryTwoVersion).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).AddRow(pgtype.UUID{}),
|
||||
)
|
||||
|
||||
err = q.Execute(ctx)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package queryqueue
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestExecute(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,
|
||||
}
|
||||
|
||||
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)},
|
||||
}
|
||||
|
||||
q := &Queue{
|
||||
unsyncedQueue: expectedQueries,
|
||||
db: db,
|
||||
documentId: uuid.New(),
|
||||
cleanVersion: int32(1),
|
||||
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{}),
|
||||
)
|
||||
|
||||
err = q.Execute(ctx)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestExecuteQuery(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,
|
||||
}
|
||||
|
||||
qu := &queryprocessor.Query{ID: uuid.New(), Type: queryprocessor.TypeContextFull, RequiredQueryIDs: []uuid.UUID{}, Version: int32(1)}
|
||||
|
||||
q := &Queue{
|
||||
db: db,
|
||||
documentId: uuid.New(),
|
||||
cleanVersion: int32(1),
|
||||
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{}),
|
||||
)
|
||||
|
||||
err = q.executeQuery(ctx, qu)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package queryqueue
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"queryorchestration/internal/query/result"
|
||||
contextfull "queryorchestration/internal/query/types/contextFull"
|
||||
jsonextractor "queryorchestration/internal/query/types/jsonExtractor"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
value, err := processor.Process(ctx, qu, resultValues)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
id, err := result.Store(ctx, q.db.Queries, &result.ResultStore{
|
||||
QueryID: qu.ID,
|
||||
DocumentID: q.documentId,
|
||||
Value: value,
|
||||
CleanVersion: q.cleanVersion,
|
||||
TextVersion: q.textVersion,
|
||||
QueryVersion: qu.Version,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
q.results = append(q.results, &result.Result{
|
||||
ID: id,
|
||||
QueryID: qu.ID,
|
||||
QueryVersion: qu.Version,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *Queue) getProcessor(queryType queryprocessor.Type) (queryprocessor.Processor, error) {
|
||||
switch queryType {
|
||||
case queryprocessor.TypeJsonExtractor:
|
||||
return jsonextractor.NewExtractor(q.db), nil
|
||||
case queryprocessor.TypeContextFull:
|
||||
return contextfull.NewExtractor(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("attempting to process invalid query type")
|
||||
}
|
||||
}
|
||||
|
||||
func (q *Queue) getResultValue(res *repository.ListResultValuesByIDRow) (result.Value, error) {
|
||||
var queryType queryprocessor.Type
|
||||
for _, qu := range q.collectorQueries {
|
||||
if qu.ID == database.MustToUUID(res.Queryid) {
|
||||
queryType = qu.Type
|
||||
}
|
||||
}
|
||||
|
||||
switch queryType {
|
||||
case queryprocessor.TypeJsonExtractor:
|
||||
return jsonextractor.NewResult(res.Value), nil
|
||||
case queryprocessor.TypeContextFull:
|
||||
return contextfull.NewResult(res.Value), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("attempting to process invalid query type")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package queryqueue
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"queryorchestration/internal/query/result"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSetResult(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,
|
||||
}
|
||||
|
||||
q := &Queue{
|
||||
db: db,
|
||||
documentId: uuid.New(),
|
||||
cleanVersion: int32(1),
|
||||
textVersion: int32(2),
|
||||
}
|
||||
|
||||
qu := &queryprocessor.Query{ID: uuid.New(), Type: queryprocessor.TypeContextFull, RequiredQueryIDs: []uuid.UUID{}, 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).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).AddRow(pgtype.UUID{}),
|
||||
)
|
||||
|
||||
err = q.setResult(ctx, qu, resultValues)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestGetProcessor(t *testing.T) {
|
||||
q := Queue{}
|
||||
|
||||
qType := queryprocessor.Type(queryprocessor.TypeContextFull)
|
||||
|
||||
processor, err := q.getProcessor(qType)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, processor)
|
||||
}
|
||||
|
||||
func TestGetResultValue(t *testing.T) {
|
||||
result := &repository.ListResultValuesByIDRow{
|
||||
Queryid: database.MustToDBUUID(uuid.New()),
|
||||
Value: "EXAMPLE_VALUE",
|
||||
}
|
||||
|
||||
q := &Queue{
|
||||
collectorQueries: []*queryprocessor.Query{
|
||||
{ID: database.MustToUUID(result.Queryid), Type: queryprocessor.TypeContextFull},
|
||||
},
|
||||
}
|
||||
|
||||
value, err := q.getResultValue(result)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, value)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package queryqueue
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/job/collector"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"queryorchestration/internal/query/result"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Queue struct {
|
||||
unsyncedQueue []*queryprocessor.Query
|
||||
collectorQueries []*queryprocessor.Query
|
||||
results []*result.Result
|
||||
collector *collector.Collector
|
||||
db *database.Connection
|
||||
cleanVersion int32
|
||||
textVersion int32
|
||||
documentId uuid.UUID
|
||||
}
|
||||
|
||||
func New(ctx context.Context, db *database.Connection, coll *collector.Collector, results []*result.Result, docId uuid.UUID, cleanVersion int32, textVersion int32) (*Queue, error) {
|
||||
queue := Queue{
|
||||
db: db,
|
||||
results: results,
|
||||
collector: coll,
|
||||
documentId: docId,
|
||||
cleanVersion: cleanVersion,
|
||||
textVersion: textVersion,
|
||||
}
|
||||
|
||||
err := queue.getCollectorQueries(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
queue.getUnsyncedQueries()
|
||||
|
||||
return &queue, nil
|
||||
}
|
||||
|
||||
func (q *Queue) GetQueue() []*queryprocessor.Query {
|
||||
return q.unsyncedQueue
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package queryqueue_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/job/collector"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
queryqueue "queryorchestration/internal/query/queue"
|
||||
"queryorchestration/internal/query/result"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestService(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,
|
||||
}
|
||||
jobID := uuid.New()
|
||||
dbJobID := database.MustToDBUUID(jobID)
|
||||
collectorID := uuid.New()
|
||||
dbCollectorID := database.MustToDBUUID(collectorID)
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorFromJobID :one").WithArgs(dbJobID).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "jobId", "minCleanVersion", "minTextVersion"}).
|
||||
AddRow(dbCollectorID, dbJobID, int32(1), int32(1)),
|
||||
)
|
||||
|
||||
coll, err := collector.NewByJobId(ctx, db, jobID)
|
||||
assert.Nil(t, err)
|
||||
|
||||
queryOneID := uuid.New()
|
||||
queryOneVersion := int32(1)
|
||||
queryTwoID := uuid.New()
|
||||
queryTwoVersion := int32(2)
|
||||
queryThreeID := uuid.New()
|
||||
queryThreeVersion := int32(3)
|
||||
queryFourID := uuid.New()
|
||||
queryFourVersion := int32(4)
|
||||
queryFiveID := uuid.New()
|
||||
queryFiveVersion := int32(5)
|
||||
querySixID := uuid.New()
|
||||
querySixVersion := int32(6)
|
||||
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},
|
||||
}
|
||||
|
||||
rows := pgxmock.NewRows([]string{"collectorId", "queryId", "type", "queryVersion", "requiredIds"})
|
||||
for _, q := range collectorQueries {
|
||||
dbID := database.MustToDBUUID(q.ID)
|
||||
dbReqIDs := database.MustToDBUUIDArray(q.RequiredQueryIDs)
|
||||
ty, err := queryprocessor.ToDBNullQueryType(q.Type)
|
||||
assert.Nil(t, err)
|
||||
rows = rows.
|
||||
AddRow(dbCollectorID, dbID, ty, &q.Version, dbReqIDs)
|
||||
}
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorQueries :many").WithArgs(dbCollectorID).WillReturnRows(rows)
|
||||
|
||||
contextResultID := uuid.New()
|
||||
results := []*result.Result{
|
||||
{ID: contextResultID, QueryID: contextID, QueryVersion: contextVersion},
|
||||
{ID: uuid.New(), QueryID: queryFourID, QueryVersion: queryFourVersion},
|
||||
{ID: uuid.New(), QueryID: querySixID, QueryVersion: querySixVersion - 1},
|
||||
{ID: uuid.New(), QueryID: queryOneID, QueryVersion: queryOneVersion - 1},
|
||||
}
|
||||
|
||||
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},
|
||||
}
|
||||
|
||||
docID := uuid.New()
|
||||
cleanVersion := int32(1)
|
||||
textVersion := int32(1)
|
||||
|
||||
q, err := queryqueue.New(ctx, db, coll, results, docID, cleanVersion, textVersion)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expectedQueries, q.GetQueue())
|
||||
}
|
||||
|
||||
func TestQueueFail(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,
|
||||
}
|
||||
jobID := uuid.New()
|
||||
dbJobID := database.MustToDBUUID(jobID)
|
||||
collectorID := uuid.New()
|
||||
dbCollectorID := database.MustToDBUUID(collectorID)
|
||||
|
||||
pool.ExpectQuery("name: GetCollectorFromJobID :one").WithArgs(dbJobID).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "jobId", "minCleanVersion", "minTextVersion"}).
|
||||
AddRow(dbCollectorID, dbJobID, int32(1), int32(1)),
|
||||
)
|
||||
|
||||
coll, err := collector.NewByJobId(ctx, db, jobID)
|
||||
assert.Nil(t, err)
|
||||
|
||||
dbErr := "database failure"
|
||||
pool.ExpectQuery("name: GetCollectorQueries :many").WithArgs(dbCollectorID).
|
||||
WillReturnError(errors.New(dbErr))
|
||||
|
||||
results := []*result.Result{}
|
||||
|
||||
docID := uuid.New()
|
||||
cleanVersion := int32(1)
|
||||
textVersion := int32(1)
|
||||
|
||||
_, err = queryqueue.New(ctx, db, coll, results, docID, cleanVersion, textVersion)
|
||||
assert.EqualError(t, err, dbErr)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package result
|
||||
|
||||
import (
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
)
|
||||
|
||||
func Parse(dbQuery *repository.ListResultsByDocumentIDRow) *Result {
|
||||
return &Result{
|
||||
ID: database.MustToUUID(dbQuery.ID),
|
||||
QueryID: database.MustToUUID(dbQuery.Queryid),
|
||||
QueryVersion: dbQuery.Queryversion,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package result_test
|
||||
|
||||
import (
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/query/result"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseResultValue(t *testing.T) {
|
||||
dbResult := repository.ListResultsByDocumentIDRow{
|
||||
ID: pgtype.UUID{},
|
||||
Queryid: pgtype.UUID{},
|
||||
Queryversion: int32(1),
|
||||
}
|
||||
|
||||
value := result.Parse(&dbResult)
|
||||
assert.Equal(t, dbResult.Queryversion, value.QueryVersion)
|
||||
assert.Equal(t, uuid.Nil, value.ID)
|
||||
assert.Equal(t, uuid.Nil, value.QueryID)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package result
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Result struct {
|
||||
ID uuid.UUID
|
||||
QueryID uuid.UUID
|
||||
QueryVersion int32
|
||||
}
|
||||
|
||||
type Value interface {
|
||||
GetValue(ctx context.Context) (string, error)
|
||||
}
|
||||
|
||||
type ResultStore struct {
|
||||
QueryID uuid.UUID
|
||||
DocumentID uuid.UUID
|
||||
Value string
|
||||
CleanVersion int32
|
||||
TextVersion int32
|
||||
QueryVersion int32
|
||||
}
|
||||
|
||||
func Store(ctx context.Context, dbQueries *repository.Queries, res *ResultStore) (uuid.UUID, error) {
|
||||
dbId, err := dbQueries.SetResult(ctx, &repository.SetResultParams{
|
||||
Queryid: database.MustToDBUUID(res.QueryID),
|
||||
Documentid: database.MustToDBUUID(res.DocumentID),
|
||||
Value: res.Value,
|
||||
Cleanversion: res.CleanVersion,
|
||||
Textversion: res.TextVersion,
|
||||
Queryversion: res.QueryVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return uuid.Nil, err
|
||||
}
|
||||
|
||||
id := database.MustToUUID(dbId)
|
||||
|
||||
return id, nil
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package result_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/query/result"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStore(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)
|
||||
|
||||
resultStore := result.ResultStore{
|
||||
QueryID: uuid.New(),
|
||||
DocumentID: uuid.New(),
|
||||
Value: "val",
|
||||
CleanVersion: int32(1),
|
||||
TextVersion: int32(1),
|
||||
QueryVersion: int32(1),
|
||||
}
|
||||
|
||||
pool.ExpectQuery("name: SetResult :one").WithArgs(database.MustToDBUUID(resultStore.QueryID), database.MustToDBUUID(resultStore.DocumentID), resultStore.Value, resultStore.CleanVersion, resultStore.TextVersion, resultStore.QueryVersion).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id"}).AddRow(pgtype.UUID{}),
|
||||
)
|
||||
|
||||
id, err := result.Store(ctx, queries, &resultStore)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, id)
|
||||
|
||||
dbErr := "database failing"
|
||||
pool.ExpectQuery("name: SetResult :one").WithArgs(database.MustToDBUUID(resultStore.QueryID), database.MustToDBUUID(resultStore.DocumentID), resultStore.Value, resultStore.CleanVersion, resultStore.TextVersion, resultStore.QueryVersion).
|
||||
WillReturnError(errors.New(dbErr))
|
||||
|
||||
id, err = result.Store(ctx, queries, &resultStore)
|
||||
assert.EqualError(t, err, dbErr)
|
||||
assert.Equal(t, uuid.Nil, id)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package contextfull
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
)
|
||||
|
||||
type Creator struct {
|
||||
db *database.Connection
|
||||
}
|
||||
|
||||
func NewCreator(db *database.Connection) Creator {
|
||||
return Creator{db}
|
||||
}
|
||||
|
||||
func (s Creator) Validate(ctx context.Context, entity *queryprocessor.Create) error {
|
||||
// TODO
|
||||
// Type, RequiredQueryIDs, Config
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package contextfull_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
contextfull "queryorchestration/internal/query/types/contextFull"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreatorValidate(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 := contextfull.NewCreator(db)
|
||||
assert.NotNil(t, svc)
|
||||
|
||||
entity := &queryprocessor.Create{
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
}
|
||||
|
||||
err = svc.Validate(ctx, entity)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package contextfull_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"queryorchestration/internal/query/result"
|
||||
contextfull "queryorchestration/internal/query/types/contextFull"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestContextFull(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
extractor := contextfull.NewExtractor()
|
||||
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Version: int32(1),
|
||||
}
|
||||
|
||||
values := []result.Value{}
|
||||
|
||||
value, err := extractor.Process(ctx, query, values)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "", value)
|
||||
|
||||
values = []result.Value{
|
||||
contextfull.NewResult("example_result"),
|
||||
}
|
||||
|
||||
_, err = extractor.Process(ctx, query, values)
|
||||
assert.EqualError(t, err, "no requirements expected")
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package contextfull
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type Result struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func NewResult(value string) Result {
|
||||
return Result{value}
|
||||
}
|
||||
|
||||
func (r Result) GetValue(ctx context.Context) (string, error) {
|
||||
// TODO - get value from s3
|
||||
return r.value, nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package contextfull
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"queryorchestration/internal/query/result"
|
||||
)
|
||||
|
||||
type Extractor struct {
|
||||
}
|
||||
|
||||
func NewExtractor() Extractor {
|
||||
return Extractor{}
|
||||
}
|
||||
|
||||
func (e Extractor) Process(ctx context.Context, query *queryprocessor.Query, values []result.Value) (string, error) {
|
||||
if len(values) > 0 {
|
||||
return "", errors.New("no requirements expected")
|
||||
}
|
||||
// TODO
|
||||
|
||||
return "", nil
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package contextfull
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
)
|
||||
|
||||
type Updator struct {
|
||||
db *database.Connection
|
||||
}
|
||||
|
||||
func NewUpdator(db *database.Connection) Updator {
|
||||
return Updator{db}
|
||||
}
|
||||
|
||||
func (s Updator) Validate(ctx context.Context, current *queryprocessor.Query, entity *queryprocessor.Update) error {
|
||||
// TODO
|
||||
// Type, RequiredQueryIDs, Config
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package contextfull_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
contextfull "queryorchestration/internal/query/types/contextFull"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUpdatorValidate(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 := contextfull.NewUpdator(db)
|
||||
assert.NotNil(t, svc)
|
||||
|
||||
current := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeContextFull,
|
||||
Version: int32(1),
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
}
|
||||
|
||||
entity := &queryprocessor.Update{
|
||||
ID: current.ID,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
}
|
||||
|
||||
err = svc.Validate(ctx, current, entity)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package jsonextractor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
)
|
||||
|
||||
type Creator struct {
|
||||
db *database.Connection
|
||||
}
|
||||
|
||||
func NewCreator(db *database.Connection) Creator {
|
||||
return Creator{db}
|
||||
}
|
||||
|
||||
func (s Creator) Validate(ctx context.Context, entity *queryprocessor.Create) error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package jsonextractor_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
jsonextractor "queryorchestration/internal/query/types/jsonExtractor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreatorValidate(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 := jsonextractor.NewCreator(db)
|
||||
assert.NotNil(t, svc)
|
||||
|
||||
entity := &queryprocessor.Create{
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
}
|
||||
|
||||
err = svc.Validate(ctx, entity)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package jsonextractor_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"queryorchestration/internal/query/result"
|
||||
contextfull "queryorchestration/internal/query/types/contextFull"
|
||||
jsonextractor "queryorchestration/internal/query/types/jsonExtractor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestJSONProcess(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,
|
||||
}
|
||||
|
||||
extractor := jsonextractor.NewExtractor(db)
|
||||
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Version: int32(1),
|
||||
}
|
||||
entryValue := "value"
|
||||
|
||||
jsonString := fmt.Sprintf("{\"key\": \"%s\"}", entryValue)
|
||||
values := []result.Value{
|
||||
contextfull.NewResult(jsonString),
|
||||
}
|
||||
|
||||
config := "{\"path\":\"key\"}"
|
||||
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(query.ID), query.Version).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err := extractor.Process(ctx, query, values)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, entryValue, value)
|
||||
|
||||
entryValue = ""
|
||||
jsonString = fmt.Sprintf("{\"key\": \"%s\"}", entryValue)
|
||||
values = []result.Value{
|
||||
contextfull.NewResult(jsonString),
|
||||
}
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(query.ID), query.Version).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, entryValue, value)
|
||||
|
||||
entryValue = "1"
|
||||
jsonString = fmt.Sprintf("{\"key\": %s", entryValue)
|
||||
values = []result.Value{
|
||||
contextfull.NewResult(jsonString),
|
||||
}
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(query.ID), query.Version).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, entryValue, value)
|
||||
}
|
||||
|
||||
func TestJSONProcessJSON(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,
|
||||
}
|
||||
|
||||
extractor := jsonextractor.NewExtractor(db)
|
||||
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Version: int32(1),
|
||||
}
|
||||
entryValue := "value"
|
||||
|
||||
jsonString := fmt.Sprintf("{\"key\": \"%s\"}", entryValue)
|
||||
values := []result.Value{
|
||||
contextfull.NewResult(jsonString),
|
||||
}
|
||||
|
||||
config := "{\"path\":\"invalid_key\"}"
|
||||
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(query.ID), query.Version).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err := extractor.Process(ctx, query, values)
|
||||
assert.EqualError(t, err, "JSON path does not exist: invalid_key")
|
||||
assert.Empty(t, value)
|
||||
|
||||
config = ""
|
||||
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(query.ID), query.Version).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
assert.EqualError(t, err, "unexpected end of JSON input")
|
||||
assert.Empty(t, value)
|
||||
|
||||
config = "{\"path\":\"\"}"
|
||||
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(query.ID), query.Version).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
assert.EqualError(t, err, "JSON path does not exist: ")
|
||||
assert.Empty(t, value)
|
||||
|
||||
config = "{\"path\":}"
|
||||
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(query.ID), query.Version).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}).
|
||||
AddRow(pgtype.UUID{}, []byte(config)),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
assert.EqualError(t, err, "invalid character '}' looking for beginning of value")
|
||||
assert.Empty(t, value)
|
||||
|
||||
pool.ExpectQuery("name: GetQueryConfig :one").WithArgs(database.MustToDBUUID(query.ID), query.Version).
|
||||
WillReturnRows(
|
||||
pgxmock.NewRows([]string{"id", "config"}),
|
||||
)
|
||||
|
||||
value, err = extractor.Process(ctx, query, values)
|
||||
assert.EqualError(t, err, "no rows in result set")
|
||||
assert.Empty(t, value)
|
||||
}
|
||||
|
||||
func TestJSONProcessResults(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,
|
||||
}
|
||||
|
||||
extractor := jsonextractor.NewExtractor(db)
|
||||
|
||||
query := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Version: int32(1),
|
||||
}
|
||||
|
||||
results := []result.Value{}
|
||||
value, err := extractor.Process(ctx, query, results)
|
||||
assert.EqualError(t, err, "JSON Extraction requires 1 result")
|
||||
assert.Empty(t, value)
|
||||
|
||||
results = []result.Value{
|
||||
contextfull.NewResult(""),
|
||||
contextfull.NewResult(""),
|
||||
}
|
||||
value, err = extractor.Process(ctx, query, results)
|
||||
assert.EqualError(t, err, "JSON Extraction requires 1 result")
|
||||
assert.Empty(t, value)
|
||||
|
||||
results = []result.Value{
|
||||
contextfull.NewResult(""),
|
||||
contextfull.NewResult(""),
|
||||
contextfull.NewResult(""),
|
||||
}
|
||||
value, err = extractor.Process(ctx, query, results)
|
||||
assert.EqualError(t, err, "JSON Extraction requires 1 result")
|
||||
assert.Empty(t, value)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package jsonextractor
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type Result struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func NewResult(value string) Result {
|
||||
return Result{value}
|
||||
}
|
||||
|
||||
func (r Result) GetValue(ctx context.Context) (string, error) {
|
||||
return r.value, nil
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package jsonextractor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"queryorchestration/internal/query/result"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type Extractor struct {
|
||||
db *database.Connection
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
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 {
|
||||
return "", fmt.Errorf("JSON Extraction requires 1 result")
|
||||
}
|
||||
|
||||
value, err := values[0].GetValue(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
byteConfig, err := e.db.Queries.GetQueryConfig(ctx, &repository.GetQueryConfigParams{
|
||||
Queryid: database.MustToDBUUID(query.ID),
|
||||
Addedversion: query.Version,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var config Config
|
||||
err = json.Unmarshal(byteConfig.Config, &config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return e.extract(value, config.Path)
|
||||
}
|
||||
|
||||
func (e *Extractor) extract(jsonString string, path string) (string, error) {
|
||||
value := gjson.Get(jsonString, path)
|
||||
|
||||
if !value.Exists() {
|
||||
return "", fmt.Errorf("JSON path does not exist: %s", path)
|
||||
}
|
||||
|
||||
return value.String(), nil
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package jsonextractor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
)
|
||||
|
||||
type Updator struct {
|
||||
db *database.Connection
|
||||
}
|
||||
|
||||
func NewUpdator(db *database.Connection) Updator {
|
||||
return Updator{db}
|
||||
}
|
||||
|
||||
func (s Updator) Validate(ctx context.Context, current *queryprocessor.Query, entity *queryprocessor.Update) error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package jsonextractor_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
jsonextractor "queryorchestration/internal/query/types/jsonExtractor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pashagolub/pgxmock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUpdatorValidate(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 := jsonextractor.NewUpdator(db)
|
||||
assert.NotNil(t, svc)
|
||||
|
||||
current := &queryprocessor.Query{
|
||||
ID: uuid.New(),
|
||||
Type: queryprocessor.TypeJsonExtractor,
|
||||
Version: int32(1),
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
}
|
||||
|
||||
entity := &queryprocessor.Update{
|
||||
ID: current.ID,
|
||||
RequiredQueryIDs: []uuid.UUID{},
|
||||
Config: "",
|
||||
}
|
||||
|
||||
err = svc.Validate(ctx, current, entity)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package query
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
contextfull "queryorchestration/internal/contextFull"
|
||||
jsonextractor "queryorchestration/internal/jsonExtractor"
|
||||
queryprocessor "queryorchestration/internal/queryProcessor"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
contextfull "queryorchestration/internal/query/types/contextFull"
|
||||
jsonextractor "queryorchestration/internal/query/types/jsonExtractor"
|
||||
)
|
||||
|
||||
func (s *Service) Update(ctx context.Context, entity *queryprocessor.Update) error {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
"queryorchestration/internal/query"
|
||||
queryprocessor "queryorchestration/internal/queryProcessor"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"queryorchestration/internal/database"
|
||||
"queryorchestration/internal/database/repository"
|
||||
queryprocessor "queryorchestration/internal/queryProcessor"
|
||||
queryprocessor "queryorchestration/internal/query/processor"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
Reference in New Issue
Block a user