diff --git a/internal/drivers/keyvaluedriver/keyvaluedriver.go b/internal/drivers/keyvaluedriver/keyvaluedriver.go index 15c3595072b3b1b4229cea9d48b58890f1931d59..9fc896bf20d7aaf7259ff3df8fae1826498d4a72 100644 --- a/internal/drivers/keyvaluedriver/keyvaluedriver.go +++ b/internal/drivers/keyvaluedriver/keyvaluedriver.go @@ -23,7 +23,6 @@ func NewRedisDriver() *KeyValueDriver { func (d *KeyValueDriver) Start() { // Grab the redis host and port from environment vars redisAddress := os.Getenv("REDIS_ADDRESS") - // redisPassword := os.Getenv("REDIS_PASSWORD") // Create redis client d.client = redis.NewClient(&redis.Options{ diff --git a/internal/entity/querystruct.go b/internal/entity/querystruct.go index 868722fd4fd8edb648fe1a06b90e3622a4c802a7..14ecebe354f5bca3e54998917e697f9419ca9cf2 100644 --- a/internal/entity/querystruct.go +++ b/internal/entity/querystruct.go @@ -35,8 +35,8 @@ type QueryRelationStruct struct { // QueryModifierStruct encapsulates a single modifier with its corresponding constraints type QueryModifierStruct struct { - Type string //SUM COUNT AVG - SelectedType string //node relation + Type string // SUM COUNT AVG + SelectedType string // node relation ID int // ID of the enitity or relation AttributeIndex int // = -1 if its the node or relation, = > -1 if an attribute is selected } @@ -47,14 +47,11 @@ type QuerySearchDepthStruct struct { Max int } -/* -QueryConstraintStruct holds the information of the constraint - -Constraint datatypes - text MatchTypes: exact/contains/startswith/endswith - number MatchTypes: GT/LT/EQ - bool MatchTypes: EQ/NEQ -*/ +// QueryConstraintStruct holds the information of the constraint +// Constraint datatypes +// text MatchTypes: exact/contains/startswith/endswith +// number MatchTypes: GT/LT/EQ +// bool MatchTypes: EQ/NEQ type QueryConstraintStruct struct { Attribute string Value string diff --git a/internal/usecases/consume/consume_test.go b/internal/usecases/consume/consume_test.go index cb8f06f2259d756d96ce9ab4983b8fd82c005902..8295bb0548943dc5399ae280b4c33c356db0acfe 100644 --- a/internal/usecases/consume/consume_test.go +++ b/internal/usecases/consume/consume_test.go @@ -14,23 +14,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestStart(t *testing.T) { - // // Create broker adapter - // brokerAdapter := brokeradapter.CreateGateway() - // // Create a mock broker - // mockBroker := mockbrokerdriver.CreateBroker(brokerAdapter) - // // Create mock key value store - // keyValueStore := mockkeyvaluedriver.CreateKeyValueStore() - // // Create new producer service - // producerService := produce.NewService(mockBroker, keyValueStore) - // // Create new convert query service - // convertQueryService := convertquery.NewService() - // // Create new request sender service - // requestSenderService := request.NewService() - // // Create new service - // service := NewService(mockBroker, producerService, convertQueryService, requestSenderService) -} - func TestHandleCorrectMessage(t *testing.T) { // Create broker adapter brokerAdapter := brokeradapter.CreateGateway() diff --git a/internal/usecases/consume/handlemessage.go b/internal/usecases/consume/handlemessage.go index 53ee5bdef2bba604afc3b07ff8bf00830c39dcba..e8160076cdc08f7d8962808252d3a8dcd4625f58 100644 --- a/internal/usecases/consume/handlemessage.go +++ b/internal/usecases/consume/handlemessage.go @@ -68,7 +68,7 @@ func (s *Service) HandleMessage(msg *brokeradapter.Message) { } // 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) if err != nil { errorMsg := make(map[string]string) diff --git a/internal/usecases/convertquery/aql.go b/internal/usecases/convertquery/aql.go index 2478a9f46e1827da9e388d50aa428cfb4c357fe7..1e804e9c25f236066dc3e01de563328a27716f25 100644 --- a/internal/usecases/convertquery/aql.go +++ b/internal/usecases/convertquery/aql.go @@ -17,18 +17,14 @@ func (s *Service) ConvertQuery(jsonMsg *[]byte) (*string, *string, error) { jsonStruct, err := convertJSONToStruct(jsonMsg) if err != nil { - fmt.Println(err) return nil, nil, err } - //fmt.Println("We made it past the initial error checking") // Check to make sure all indexes exist // How many entities are there numEntities := len(jsonStruct.Entities) - 1 // How many relations there are numRelations := len(jsonStruct.Relations) - 1 - // How many modifiers there are - //numModifiers := len(jsonStruct.Modifiers) - 1 // Make sure no entity should be returned that is outside the range of that list for _, e := range jsonStruct.Return.Entities { @@ -52,15 +48,7 @@ func (s *Service) ConvertQuery(jsonMsg *[]byte) (*string, *string, error) { } } - //Make sure no modifier should be returned that is outside the range of that list - // for _, m := range jsonStruct.Modifiers { - // // If this modifier references an modifier that is outside the range - // if m > numModifiers || m < 0 { - // return nil, nil, errors.New("non-existing modifier referenced") - // } - // } result := createQuery(jsonStruct) - //fmt.Print("test123" + *result) return result, &jsonStruct.DatabaseName, nil } @@ -85,42 +73,8 @@ Parameters: jsonQuery is a parsedJSON struct holding all the data needed to form Return: a string containing the corresponding AQL query and an error */ - -/* - -LET n0 = (FOR x IN airports FILTER x.city == "New York" RETURN x) -LET nodes = first(RETURN UNION_DISTINCT(n0,[],[])) -LET edges = first(RETURN UNION_DISTINCT([],[])) -RETURN {"vertices":nodes, "edges":edges } - - - -LET n0 = (FOR x IN airports FILTER x.city == "New York" RETURN x) -RETURN LENGTH(n0) - - - - -LET n0 = (FOR x IN airports FILTER x.city == "New York" RETURN x) -LET r0 = (FOR x IN n0 FOR v, e, p IN 1..1 OUTBOUND x flights OPTIONS { uniqueEdges: "path" }FILTER p.edges[*].Day ALL == 8 -LIMIT 5000 RETURN DISTINCT p ) -LET nodes = first(RETURN UNION_DISTINCT(flatten(r0[**].vertices), [],[])) -LET edges = first(RETURN UNION_DISTINCT(flatten(r0[**].edges), [],[])) -RETURN {"vertices":nodes, "edges":edges } - - -LET n0 = (FOR x IN airports FILTER x.city == "New York" RETURN x) -LET r0 = (FOR x IN n0 FOR v, e, p IN 1..1 OUTBOUND x flights OPTIONS { uniqueEdges: "path" }FILTER p.edges[*].Day ALL == 8 -RETURN DISTINCT p ) -RETURN COUNT(UNIQUE(r0[**].vertices[0])) - - -*/ - func createQuery(jsonQuery *entity.QueryParsedJSON) *string { - // GROTE SIDENOTE: - // Vrij zeker dat een query waar alléén edges worden opgevraagd (#4) - // niet wordt gesupport door zowel de result parser als de frontend receiver + // Note: Case #4, where there is an edge only query (without any entity), is not supported by frontend // If a modifier is used, disable the limit if len(jsonQuery.Modifiers) > 0 { @@ -255,22 +209,6 @@ func createQuery(jsonQuery *entity.QueryParsedJSON) *string { } } - // fmt.Println("Yes we do") - // switch modifier.Type { - // case "COUNT": - // if len(jsonQuery.Return.Relations) > 0 && modifier.SelectedType == "Entity" { - // ret += "RETURN COUNT(UNIQUE(r0[**].vertices[0]))" - // } else { - // ret += "RETURN LENGTH(n0)" - // } - // case "AVG": - // ret += "" - // case "SUM": - // ret += "" - // default: - // ret += "" - // } - } else { // Create UNION statements that create unique lists of all the nodes and relations @@ -381,216 +319,3 @@ func createRelationLetWithOnlyToEntity(relation *entity.QueryRelationStruct, nam ret := header + forStatement + optionStmtn + relationFilterStmnt + footer return &ret } - -// WIP TODO: nodes worden nog niet meegereturned, ff googlen hoe en wat -// func createEntitylessRelationLet(edge *relationStruct, name *string, onlyEdge bool) *string { -// var ( -// header string -// forEdge string -// forSecondNode string -// ) - -// footer := "\n\tLIMIT 100\n\tRETURN { vertices: p.vertices[*], edges: p.edges[*] }\n)\n" - -// // WICKED SWITCHES LETSAGO -// if edge.EntityFrom != -1 { -// // # 1 (2) Outbound only -// header = fmt.Sprintf("LET %v = (\n\tFOR x IN n%v \n", *name, edge.EntityFrom) -// forEdge = fmt.Sprintf("\tFOR v, e, p IN %v..%v OUTBOUND x %s \n", edge.Depth.Min, edge.Depth.Max, edge.Type) -// if edge.EntityTo != -1 { -// // # 2 Node Relation Node -// forSecondNode = fmt.Sprintf("\tFILTER v IN n%v \n", edge.EntityTo) -// } -// } else { -// if edge.EntityTo != -1 { -// // # 3 Inbound only -// header = fmt.Sprintf("LET %v = (\n\tFOR x IN n%v \n", *name, edge.EntityTo) -// forEdge = fmt.Sprintf("\tFOR v, e, p IN %v..%v INBOUND x %s \n", edge.Depth.Min, edge.Depth.Max, edge.Type) -// } else { -// // # 4 Relation with constraints only -// header = fmt.Sprintf("LET %v = (\n\tFOR x IN %v \n", *name, edge.Type) -// footer = "\tLIMIT 100\n\tRETURN x\n)\n" -// } -// } -// allStatement := true -// if onlyEdge { -// allStatement = false -// } - -// constraints := *createConstraintStatements(&edge.Constraints, *name, allStatement) - -// ret := header + forEdge + forSecondNode + constraints + footer -// return &ret -// } - -/* -#1 -{ - "Return": { - "Entities": [ - 0, - 1 - ], - "Relations": [ - 0 - ] - }, - "Entities": [ - { - "Type": "airports", - "Constraints": [] - }, - { - "Type": "airports", - "Constraints": [] - } - ], - "Relations": [ - { - "Type": "flights", - "Depth": { - "min": 1, - "max": 1 - }, - "EntityFrom": 0, - "EntityTo": 1, - "Constraints": [] - } - ] -} -*/ - -/* -#2 - -{ - "Return": { - "Entities": [ - 0 - ], - "Relations": [ - 0 - ] - }, - "Entities": [ - { - "Type": "airports", - "Constraints": [] - } - ], - "Relations": [ - { - "Type": "flights", - "Depth": { - "min": 1, - "max": 1 - }, - "EntityFrom": 0, - "EntityTo": -1, - "Constraints": [] - } - ] -} -*/ - -/* -#3 -{ - "Return": { - "Entities": [ - 0 - ], - "Relations": [ - 0 - ] - }, - "Entities": [ - { - "Type": "airports", - "Constraints": [] - } - ], - "Relations": [ - { - "Type": "flights", - "Depth": { - "min": 1, - "max": 1 - }, - "EntityFrom": -1, - "EntityTo": 0, - "Constraints": [] - } - ] -} -*/ - -/* -#4 -{ - "Return": { - "Entities": [], - "Relations": [ - 0 - ] - }, - "Entities": [], - "Relations": [ - { - "Type": "flights", - "Depth": { - "min": 1, - "max": 1 - }, - "EntityFrom": -1, - "EntityTo": -1, - "Constraints": [ - { - "Attribute": "Month", - "Value": "1", - "DataType": "number", - "MatchType": "EQ" - }, - { - "Attribute": "Day", - "Value": "15", - "DataType": "number", - "MatchType": "EQ" - } - ] - } - ] -} -*/ - -/* -#5 -{ - "Return": { - "Entities": [ - 0 - ], - "Relations": [] - }, - "Entities": [ - { - "Type": "airports", - "Constraints": [ - { - "Attribute": "city", - "Value": "New York", - "DataType": "text", - "MatchType": "exact" - }, - { - "Attribute": "country", - "Value": "USA", - "DataType": "text", - "MatchType": "exact" - } - ] - } - ], - "Relations": [] -} -*/ diff --git a/internal/usecases/convertquery/createConstraints.go b/internal/usecases/convertquery/createConstraints.go index a971a08b0772a13373456b6e23637e07d2143a4b..0f2a880c3082063d5784c7dc71469b04eaa130c9 100644 --- a/internal/usecases/convertquery/createConstraints.go +++ b/internal/usecases/convertquery/createConstraints.go @@ -46,8 +46,8 @@ func createConstraintBoolExpression(constraint *entity.QueryConstraintStruct, na // Constraint datatypes back end // text MatchTypes: EQ/NEQ/contains/excludes - // number MatchTypes: EQ/NEQ/GT/LT/GET/LET - // bool MatchTypes: EQ/NEQ + // number MatchTypes: EQ/NEQ/GT/LT/GET/LET + // bool MatchTypes: EQ/NEQ switch constraint.DataType { case "text": diff --git a/internal/usecases/convertquery/queryexamples.txt b/internal/usecases/convertquery/queryexamples.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac6b44d6540c00319b48d22e6d9d1dff4af240f8 --- /dev/null +++ b/internal/usecases/convertquery/queryexamples.txt @@ -0,0 +1,189 @@ + +#1 +{ + "Return": { + "Entities": [ + 0, + 1 + ], + "Relations": [ + 0 + ] + }, + "Entities": [ + { + "Type": "airports", + "Constraints": [] + }, + { + "Type": "airports", + "Constraints": [] + } + ], + "Relations": [ + { + "Type": "flights", + "Depth": { + "min": 1, + "max": 1 + }, + "EntityFrom": 0, + "EntityTo": 1, + "Constraints": [] + } + ] +} + +#2 + +{ + "Return": { + "Entities": [ + 0 + ], + "Relations": [ + 0 + ] + }, + "Entities": [ + { + "Type": "airports", + "Constraints": [] + } + ], + "Relations": [ + { + "Type": "flights", + "Depth": { + "min": 1, + "max": 1 + }, + "EntityFrom": 0, + "EntityTo": -1, + "Constraints": [] + } + ] +} + +#3 +{ + "Return": { + "Entities": [ + 0 + ], + "Relations": [ + 0 + ] + }, + "Entities": [ + { + "Type": "airports", + "Constraints": [] + } + ], + "Relations": [ + { + "Type": "flights", + "Depth": { + "min": 1, + "max": 1 + }, + "EntityFrom": -1, + "EntityTo": 0, + "Constraints": [] + } + ] +} + +#4 +{ + "Return": { + "Entities": [], + "Relations": [ + 0 + ] + }, + "Entities": [], + "Relations": [ + { + "Type": "flights", + "Depth": { + "min": 1, + "max": 1 + }, + "EntityFrom": -1, + "EntityTo": -1, + "Constraints": [ + { + "Attribute": "Month", + "Value": "1", + "DataType": "number", + "MatchType": "EQ" + }, + { + "Attribute": "Day", + "Value": "15", + "DataType": "number", + "MatchType": "EQ" + } + ] + } + ] +} + +#5 +{ + "Return": { + "Entities": [ + 0 + ], + "Relations": [] + }, + "Entities": [ + { + "Type": "airports", + "Constraints": [ + { + "Attribute": "city", + "Value": "New York", + "DataType": "text", + "MatchType": "exact" + }, + { + "Attribute": "country", + "Value": "USA", + "DataType": "text", + "MatchType": "exact" + } + ] + } + ], + "Relations": [] +} + +LET n0 = (FOR x IN airports FILTER x.city == "New York" RETURN x) +LET nodes = first(RETURN UNION_DISTINCT(n0,[],[])) +LET edges = first(RETURN UNION_DISTINCT([],[])) +RETURN {"vertices":nodes, "edges":edges } + + + +LET n0 = (FOR x IN airports FILTER x.city == "New York" RETURN x) +RETURN LENGTH(n0) + + + + +LET n0 = (FOR x IN airports FILTER x.city == "New York" RETURN x) +LET r0 = (FOR x IN n0 FOR v, e, p IN 1..1 OUTBOUND x flights OPTIONS { uniqueEdges: "path" }FILTER p.edges[*].Day ALL == 8 +LIMIT 5000 RETURN DISTINCT p ) +LET nodes = first(RETURN UNION_DISTINCT(flatten(r0[**].vertices), [],[])) +LET edges = first(RETURN UNION_DISTINCT(flatten(r0[**].edges), [],[])) +RETURN {"vertices":nodes, "edges":edges } + + +LET n0 = (FOR x IN airports FILTER x.city == "New York" RETURN x) +LET r0 = (FOR x IN n0 FOR v, e, p IN 1..1 OUTBOUND x flights OPTIONS { uniqueEdges: "path" }FILTER p.edges[*].Day ALL == 8 +RETURN DISTINCT p ) +RETURN COUNT(UNIQUE(r0[**].vertices[0])) + diff --git a/internal/usecases/request/request.go b/internal/usecases/request/request.go index fc9f971eeed1305c537d3ef4180008350fb0cf66..ce3b7d29219c1c8f95ad2b80b5ac8beabd685752 100644 --- a/internal/usecases/request/request.go +++ b/internal/usecases/request/request.go @@ -14,10 +14,6 @@ import ( "github.com/arangodb/go-driver/http" ) -//attr interface{} - -//map[1 , 2 , 3 map [ .. ]] - /* SendAQLQuery send AQL string query to database and returns a JSON object in a general format @@ -27,8 +23,6 @@ Return: a map with two entries: "nodes" with a list of vertices/nodes and "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) { - - //(*map[string][]entity.Document, error) = old return var queryResult = make(map[string][]entity.Document) conn, err := http.NewConnection(http.ConnectionConfig{ Endpoints: []string{fmt.Sprintf("%s:%d", hostname, port)}, @@ -68,7 +62,6 @@ func (s *Service) SendAQLQuery(query string, username string, password string, h isNum := false for { - //var doc map[string][]interface{} var doc interface{} _, err := cursor.ReadDocument(ctx, &doc) if driver.IsNoMoreDocuments(err) { @@ -117,8 +110,6 @@ listContainer is a struct containing the nodelist and edgelist that will be retu Return: Nothing because the result is stored in the listContainer */ func parseResult(doc map[string]interface{}, listContainer *entity.ListContainer) { - - //doc, ok := incomingDoc.(map[string][]interface{}) vertices := doc["vertices"].([]interface{}) edges := doc["edges"].([]interface{}) @@ -140,9 +131,7 @@ 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(d map[string]interface{}) entity.Document { - doc := d //.(map[string]interface{}) - +func parseEdge(doc map[string]interface{}) entity.Document { data := make(entity.Document) data["_id"] = doc["_id"] delete(doc, "_id") @@ -156,11 +145,6 @@ func parseEdge(d map[string]interface{}) entity.Document { delete(doc, "_to") data["attributes"] = doc - //delete(doc, "_key") - //data.rev = fmt.Sprintf("%v", doc["_rev"]) - - // delete(doc, "_rev") - // data.attr = doc return data } @@ -176,9 +160,7 @@ 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(d map[string]interface{}) entity.Document { - doc := d //.(map[string]interface{}) - +func parseNode(doc map[string]interface{}) entity.Document { data := make(entity.Document) data["_id"] = doc["_id"] delete(doc, "_id") @@ -188,10 +170,5 @@ func parseNode(d map[string]interface{}) entity.Document { delete(doc, "_rev") data["attributes"] = doc - //delete(doc, "_key") - //data.rev = fmt.Sprintf("%v", doc["_rev"]) - - // delete(doc, "_rev") - // data.attr = doc return data }