Skip to content
Snippets Groups Projects
Commit 9b165112 authored by thijsheijden's avatar thijsheijden
Browse files

Moved request sender into external package

parent fdfb7cda
No related branches found
No related tags found
No related merge requests found
...@@ -5,12 +5,12 @@ import ( ...@@ -5,12 +5,12 @@ import (
"query-service/internal/usecases/consume" "query-service/internal/usecases/consume"
"query-service/internal/usecases/databaseinfo" "query-service/internal/usecases/databaseinfo"
"query-service/internal/usecases/produce" "query-service/internal/usecases/produce"
"query-service/internal/usecases/request"
"query-service/pkg/logger" "query-service/pkg/logger"
"git.science.uu.nl/datastrophe/broker" "git.science.uu.nl/datastrophe/broker"
"git.science.uu.nl/datastrophe/keyvaluestore" "git.science.uu.nl/datastrophe/keyvaluestore"
"git.science.uu.nl/datastrophe/query-conversion/aql" "git.science.uu.nl/datastrophe/query-conversion/aql"
"git.science.uu.nl/datastrophe/query-execution/arangodb"
"github.com/thijsheijden/alice" "github.com/thijsheijden/alice"
) )
...@@ -33,11 +33,11 @@ func main() { ...@@ -33,11 +33,11 @@ func main() {
// MARK: Create relevant services for consuming a message // MARK: Create relevant services for consuming a message
convertQueryService := aql.NewService() convertQueryService := aql.NewService()
requestSenderService := request.NewService() requestSender := arangodb.NewService()
databaseInfoService := databaseinfo.NewService(rpcDriver) databaseInfoService := databaseinfo.NewService(rpcDriver)
consumeService := consume.NewService(broker, produceService, convertQueryService, requestSenderService, databaseInfoService) consumeService := consume.NewService(broker, produceService, convertQueryService, requestSender, databaseInfoService)
// MARK: Start services // MARK: Start services
keyValueStore.Connect() keyValueStore.Connect()
......
...@@ -6,6 +6,7 @@ require ( ...@@ -6,6 +6,7 @@ require (
git.science.uu.nl/datastrophe/broker v0.0.0-20210516094125-abbeaf96fd58 git.science.uu.nl/datastrophe/broker v0.0.0-20210516094125-abbeaf96fd58
git.science.uu.nl/datastrophe/keyvaluestore v0.0.0-20210517170603-34902cd5c90d git.science.uu.nl/datastrophe/keyvaluestore v0.0.0-20210517170603-34902cd5c90d
git.science.uu.nl/datastrophe/query-conversion v0.0.0-20210518093948-06ff65cdf577 git.science.uu.nl/datastrophe/query-conversion v0.0.0-20210518093948-06ff65cdf577
git.science.uu.nl/datastrophe/query-execution v0.0.0-20210518112715-043c7046dc7b
github.com/arangodb/go-driver v0.0.0-20210518064911-4985e8be3d90 github.com/arangodb/go-driver v0.0.0-20210518064911-4985e8be3d90
github.com/boumenot/gocover-cobertura v1.1.0 // indirect github.com/boumenot/gocover-cobertura v1.1.0 // indirect
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
...@@ -14,6 +15,6 @@ require ( ...@@ -14,6 +15,6 @@ require (
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
golang.org/x/tools v0.1.1 // indirect golang.org/x/tools v0.1.1 // indirect
google.golang.org/grpc v1.37.0 google.golang.org/grpc v1.37.1
google.golang.org/protobuf v1.26.0 google.golang.org/protobuf v1.26.0
) )
...@@ -11,6 +11,14 @@ git.science.uu.nl/datastrophe/query-conversion v0.0.0-20210518093728-9ee791a5281 ...@@ -11,6 +11,14 @@ git.science.uu.nl/datastrophe/query-conversion v0.0.0-20210518093728-9ee791a5281
git.science.uu.nl/datastrophe/query-conversion v0.0.0-20210518093728-9ee791a5281e/go.mod h1:6rvalwekoukmVu3SbWmZkj8wBZEm34wDbA4Ilxcb+jw= git.science.uu.nl/datastrophe/query-conversion v0.0.0-20210518093728-9ee791a5281e/go.mod h1:6rvalwekoukmVu3SbWmZkj8wBZEm34wDbA4Ilxcb+jw=
git.science.uu.nl/datastrophe/query-conversion v0.0.0-20210518093948-06ff65cdf577 h1:Xd9hpnnRhYWdAXzLFviA6fYWnQoFD/4NtzmEC7Ntc/U= git.science.uu.nl/datastrophe/query-conversion v0.0.0-20210518093948-06ff65cdf577 h1:Xd9hpnnRhYWdAXzLFviA6fYWnQoFD/4NtzmEC7Ntc/U=
git.science.uu.nl/datastrophe/query-conversion v0.0.0-20210518093948-06ff65cdf577/go.mod h1:6rvalwekoukmVu3SbWmZkj8wBZEm34wDbA4Ilxcb+jw= git.science.uu.nl/datastrophe/query-conversion v0.0.0-20210518093948-06ff65cdf577/go.mod h1:6rvalwekoukmVu3SbWmZkj8wBZEm34wDbA4Ilxcb+jw=
git.science.uu.nl/datastrophe/query-execution v0.0.0-20210518111902-8bcfa627876b h1:39vY4lrkwKjk0SjsysegghrLMRGmpdu0/HwmNLfKDhI=
git.science.uu.nl/datastrophe/query-execution v0.0.0-20210518111902-8bcfa627876b/go.mod h1:4YfKaCyadGlmAVbKOa6J2E2H56T7+RTF7xVCmcTCwmM=
git.science.uu.nl/datastrophe/query-execution v0.0.0-20210518112126-ffe0684babaf h1:9Zkb/ZsTI4Nf9QRGXUShElMK8MnA9dWzS32Gs/azv7M=
git.science.uu.nl/datastrophe/query-execution v0.0.0-20210518112126-ffe0684babaf/go.mod h1:4YfKaCyadGlmAVbKOa6J2E2H56T7+RTF7xVCmcTCwmM=
git.science.uu.nl/datastrophe/query-execution v0.0.0-20210518112422-120f15c7bbd9 h1:uUkLULN8WTFk4jBQQsF0yoe8Odg7SEpCOH2ouh8rfUA=
git.science.uu.nl/datastrophe/query-execution v0.0.0-20210518112422-120f15c7bbd9/go.mod h1:4YfKaCyadGlmAVbKOa6J2E2H56T7+RTF7xVCmcTCwmM=
git.science.uu.nl/datastrophe/query-execution v0.0.0-20210518112715-043c7046dc7b h1:mEuRIwUfpblTbk9DMkGwlD66bV7VSyCGXW+lgqGCoF8=
git.science.uu.nl/datastrophe/query-execution v0.0.0-20210518112715-043c7046dc7b/go.mod h1:4YfKaCyadGlmAVbKOa6J2E2H56T7+RTF7xVCmcTCwmM=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/arangodb/go-driver v0.0.0-20210506071742-64f314d85db7 h1:xRFEg4kM17h2fIOt3o4+mws3uRpw5rqWtemPYKfTURg= github.com/arangodb/go-driver v0.0.0-20210506071742-64f314d85db7 h1:xRFEg4kM17h2fIOt3o4+mws3uRpw5rqWtemPYKfTURg=
github.com/arangodb/go-driver v0.0.0-20210506071742-64f314d85db7/go.mod h1:3NUekcRLpgheFIGEwcOvxilEW73MV1queNKW58k7sdc= github.com/arangodb/go-driver v0.0.0-20210506071742-64f314d85db7/go.mod h1:3NUekcRLpgheFIGEwcOvxilEW73MV1queNKW58k7sdc=
......
...@@ -3,10 +3,10 @@ package consume ...@@ -3,10 +3,10 @@ package consume
import ( import (
"query-service/internal/usecases/databaseinfo" "query-service/internal/usecases/databaseinfo"
"query-service/internal/usecases/produce" "query-service/internal/usecases/produce"
"query-service/internal/usecases/request"
"git.science.uu.nl/datastrophe/broker" "git.science.uu.nl/datastrophe/broker"
"git.science.uu.nl/datastrophe/query-conversion" "git.science.uu.nl/datastrophe/query-conversion"
queryexecution "git.science.uu.nl/datastrophe/query-execution"
) )
// Service wraps consumer methods // Service wraps consumer methods
...@@ -15,17 +15,17 @@ type Service struct { ...@@ -15,17 +15,17 @@ type Service struct {
brokerDriver broker.Interface brokerDriver broker.Interface
producer produce.UseCase producer produce.UseCase
queryConverter query.Converter queryConverter query.Converter
requestSender request.UseCase requestSender queryexecution.Executor
databaseInfoService databaseinfo.UseCase databaseInfoService databaseinfo.UseCase
} }
// NewService creates a new service // NewService creates a new service
func NewService(broker broker.Interface, produceService produce.UseCase, queryConverter query.Converter, requestSenderService request.UseCase, databaseInfoService databaseinfo.UseCase) *Service { func NewService(broker broker.Interface, produceService produce.UseCase, queryConverter query.Converter, requestSender queryexecution.Executor, databaseInfoService databaseinfo.UseCase) *Service {
return &Service{ return &Service{
brokerDriver: broker, brokerDriver: broker,
producer: produceService, producer: produceService,
queryConverter: queryConverter, queryConverter: queryConverter,
requestSender: requestSenderService, requestSender: requestSender,
databaseInfoService: databaseInfoService, databaseInfoService: databaseInfoService,
} }
} }
......
...@@ -6,7 +6,6 @@ import ( ...@@ -6,7 +6,6 @@ import (
"query-service/internal/entity" "query-service/internal/entity"
"query-service/internal/usecases/databaseinfo/mockdatabaseinfo" "query-service/internal/usecases/databaseinfo/mockdatabaseinfo"
"query-service/internal/usecases/produce" "query-service/internal/usecases/produce"
"query-service/internal/usecases/request/mockrequest"
"testing" "testing"
...@@ -14,17 +13,18 @@ import ( ...@@ -14,17 +13,18 @@ import (
"git.science.uu.nl/datastrophe/keyvaluestore" "git.science.uu.nl/datastrophe/keyvaluestore"
"git.science.uu.nl/datastrophe/query-conversion" "git.science.uu.nl/datastrophe/query-conversion"
"git.science.uu.nl/datastrophe/query-conversion/aql" "git.science.uu.nl/datastrophe/query-conversion/aql"
queryexecution "git.science.uu.nl/datastrophe/query-execution"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type testSuite struct { type testSuite struct {
mockBroker *broker.MockDriver mockBroker *broker.MockDriver
mockKeyValueStore keyvaluestore.Interface mockKeyValueStore keyvaluestore.Interface
produceService *produce.Service produceService *produce.Service
queryConverter query.Converter queryConverter query.Converter
requestSenderService *mockrequest.Service requestSender *queryexecution.MockService
databaseInfoService *mockdatabaseinfo.Service databaseInfoService *mockdatabaseinfo.Service
service *Service service *Service
} }
var ts *testSuite var ts *testSuite
...@@ -39,14 +39,14 @@ func createTestSuite() { ...@@ -39,14 +39,14 @@ func createTestSuite() {
mockBroker := broker.NewMockDriver().(*broker.MockDriver) mockBroker := broker.NewMockDriver().(*broker.MockDriver)
mockKeyValueStore := keyvaluestore.NewMockDriver() mockKeyValueStore := keyvaluestore.NewMockDriver()
ts = &testSuite{ ts = &testSuite{
mockBroker: mockBroker, mockBroker: mockBroker,
mockKeyValueStore: mockKeyValueStore, mockKeyValueStore: mockKeyValueStore,
produceService: produce.NewService(mockBroker, mockKeyValueStore), produceService: produce.NewService(mockBroker, mockKeyValueStore),
queryConverter: aql.NewService(), queryConverter: aql.NewService(),
requestSenderService: mockrequest.NewService(), requestSender: queryexecution.NewMockService(),
databaseInfoService: mockdatabaseinfo.NewService(), databaseInfoService: mockdatabaseinfo.NewService(),
} }
ts.service = NewService(mockBroker, ts.produceService, ts.queryConverter, ts.requestSenderService, ts.databaseInfoService) ts.service = NewService(mockBroker, ts.produceService, ts.queryConverter, ts.requestSender, ts.databaseInfoService)
// Set routing in the mock keyvaluestore // Set routing in the mock keyvaluestore
ts.mockKeyValueStore.Set(context.Background(), "mock-session", "mock-queue") ts.mockKeyValueStore.Set(context.Background(), "mock-session", "mock-queue")
...@@ -188,7 +188,7 @@ func TestDatabaseErrorHandled(t *testing.T) { ...@@ -188,7 +188,7 @@ func TestDatabaseErrorHandled(t *testing.T) {
} }
// Make it so that the request sender service throws an error // Make it so that the request sender service throws an error
ts.requestSenderService.ToggleError() ts.requestSender.ToggleError()
// Assert that there have not been any messages sent yet // Assert that there have not been any messages sent yet
assert.Empty(t, ts.mockBroker.Messages) assert.Empty(t, ts.mockBroker.Messages)
...@@ -202,7 +202,7 @@ func TestDatabaseErrorHandled(t *testing.T) { ...@@ -202,7 +202,7 @@ func TestDatabaseErrorHandled(t *testing.T) {
assert.Equal(t, "query_database_error", errorMsg.Type) assert.Equal(t, "query_database_error", errorMsg.Type)
// Turn of error throwing in request service // Turn of error throwing in request service
ts.requestSenderService.ToggleError() ts.requestSender.ToggleError()
} }
func TestQueryConversionErrorHandled(t *testing.T) { func TestQueryConversionErrorHandled(t *testing.T) {
......
...@@ -89,7 +89,7 @@ func (s *Service) HandleMessage(msg *broker.Message) { ...@@ -89,7 +89,7 @@ func (s *Service) HandleMessage(msg *broker.Message) {
// execute and retrieve result // execute and retrieve result
// convert result to general (node-link) format // convert result to general (node-link) format
result, err := s.requestSender.SendAQLQuery(*query, databaseInfo.Username, databaseInfo.Password, databaseInfo.URL, databaseInfo.Port, databaseInfo.InternalDatabaseName) result, err := s.requestSender.ExecuteQuery(*query, databaseInfo.Username, databaseInfo.Password, databaseInfo.URL, databaseInfo.Port, databaseInfo.InternalDatabaseName)
if err != nil { if err != nil {
errorMsg := entity.MessageStruct{ errorMsg := entity.MessageStruct{
Type: "query_database_error", Type: "query_database_error",
......
package request
// UseCase is an interface describing the request usecases
type UseCase interface {
SendAQLQuery(query string, username string, password string, hostname string, port int, database string) (*[]byte, error)
}
package mockrequest
import (
"encoding/json"
"errors"
)
// A Service implements the request usecases (mock)
type Service struct {
throwError bool
}
// NewService creates a new service (mock)
func NewService() *Service {
return &Service{
throwError: false,
}
}
// SendAQLQuery sends the query to arangoDB and parses the result (mock)
func (s *Service) SendAQLQuery(query string, username string, password string, hostname string, port int, database string) (*[]byte, error) {
mockResult, _ := json.Marshal("test")
if !s.throwError {
return &mockResult, nil
}
return nil, errors.New("Database error")
}
// ToggleError decides whether the convert function throws an error
func (s *Service) ToggleError() {
s.throwError = !s.throwError
}
package request
import (
"context"
"crypto/tls"
"fmt"
"log"
"query-service/internal/entity"
"encoding/json"
"io/ioutil"
driver "github.com/arangodb/go-driver"
"github.com/arangodb/go-driver/http"
)
/*
SendAQLQuery send AQL string query to database and returns a JSON object in a general format
Parameters: AQLQuery is a string containing the query that will be send to the database
Return: a map with two entries: "nodes" with a list of vertices/nodes and "edges" with a list of edges
that will be returned to the frontend
*/
func (s *Service) SendAQLQuery(query string, username string, password string, hostname string, port int, database string) (*[]byte, error) {
var queryResult = make(map[string][]entity.Document)
conn, err := http.NewConnection(http.ConnectionConfig{
Endpoints: []string{fmt.Sprintf("%s:%d", hostname, port)},
TLSConfig: &tls.Config{InsecureSkipVerify: true},
})
if err != nil {
log.Println("could not connect to database") // Handle error
return nil, err
}
c, err := driver.NewClient(driver.ClientConfig{
Connection: conn,
Authentication: driver.BasicAuthentication(username, password),
})
if err != nil {
log.Println("Could not log in to the ArangoDB") // Handle error
return nil, err
}
ctx := context.Background()
db, err := c.Database(ctx, database)
if err != nil {
// handle error
log.Println(err)
return nil, err
}
cursor, err := db.Query(ctx, query, nil)
if err != nil {
log.Println("Invalid query") // handle error
return nil, err
}
defer cursor.Close()
//Loop through the resulting documents
listContainer := entity.ListContainer{}
num := -1.0
isNum := false
for {
var doc interface{}
_, err := cursor.ReadDocument(ctx, &doc)
if driver.IsNoMoreDocuments(err) {
break
} else if err != nil {
// handle other errors
fmt.Println(err)
return nil, err
}
// Switch on the type of return, to filter out the case of a single number
switch doc.(type) {
case float64:
num = doc.(float64)
isNum = true
break
case map[string]interface{}:
pdoc := doc.(map[string]interface{})
parseResult(pdoc, &listContainer)
break
default:
fmt.Println("Incompatible result type")
break
}
}
if !isNum {
// Return nodes and edges
queryResult["nodes"] = listContainer.NodeList
queryResult["edges"] = listContainer.EdgeList
jsonQ, err := json.Marshal(queryResult)
return &jsonQ, err
}
// Return just a number
numQ, err := json.Marshal(num)
return &numQ, err
}
/* parseResult takes the result of the query and translates this to two lists: a nodelist and an edgelist, stored in a listcontainer
Parameters: doc is the document with the nodes and vertices that came back from the database,
listContainer is a struct containing the nodelist and edgelist that will be returned to the frontend
Return: Nothing because the result is stored in the listContainer
*/
func parseResult(doc map[string]interface{}, listContainer *entity.ListContainer) {
vertices := doc["vertices"].([]interface{})
edges := doc["edges"].([]interface{})
for _, vertex := range vertices {
vertexDoc := vertex.(map[string]interface{})
(*listContainer).NodeList = append((*listContainer).NodeList, parseNode(vertexDoc))
}
for _, edge := range edges {
edgeDoc := edge.(map[string]interface{})
(*listContainer).EdgeList = append((*listContainer).EdgeList, parseEdge(edgeDoc))
}
}
/* parseEdge parses the data of an edge to an output-friendly format
Parameters: d is a single entry of an edge
Return: a document with almost the same structure as before, but the attributes are grouped
*/
func parseEdge(doc map[string]interface{}) entity.Document {
data := make(entity.Document)
data["_id"] = doc["_id"]
delete(doc, "_id")
data["_key"] = doc["_key"]
delete(doc, "_key")
data["_rev"] = doc["_rev"]
delete(doc, "_rev")
data["_from"] = doc["_from"]
delete(doc, "_from")
data["_to"] = doc["_to"]
delete(doc, "_to")
data["attributes"] = doc
return data
}
// writeJSON writes a json file for testing purposes
func writeJSON(queryResult map[string][]entity.Document) {
file, _ := json.MarshalIndent(queryResult, "", " ")
_ = ioutil.WriteFile("result.json", file, 0644)
}
/* parseEdge parses the data of a node to an output-friendly format
Parameters: d is a single entry of an node
Return: a document with almost the same structure as before, but the attributes are grouped
*/
func parseNode(doc map[string]interface{}) entity.Document {
data := make(entity.Document)
data["_id"] = doc["_id"]
delete(doc, "_id")
data["_key"] = doc["_key"]
delete(doc, "_key")
data["_rev"] = doc["_rev"]
delete(doc, "_rev")
data["attributes"] = doc
return data
}
package request
// Service is a struct used to store this use case in
type Service struct {
}
// NewService creates a new instantion of this use case
func NewService() *Service {
return &Service{}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment