From 06b041029920ff197497dacc49bfd54b189b31fd Mon Sep 17 00:00:00 2001 From: Kieran van Gaalen <kieran.van.gaalen@casema.nl> Date: Fri, 12 Nov 2021 14:55:36 +0100 Subject: [PATCH] Replaced old convertQuery with new convertQuery, fixed parent -1 giving index out of range --- aql/convertQuery.go | 185 +++++++++++++++++++++++++++++++++++++++-- aql/convertQuery2.go | 192 ------------------------------------------- realtest.json | 2 +- 3 files changed, 177 insertions(+), 202 deletions(-) delete mode 100644 aql/convertQuery2.go diff --git a/aql/convertQuery.go b/aql/convertQuery.go index dfdcbc1..e6d5368 100644 --- a/aql/convertQuery.go +++ b/aql/convertQuery.go @@ -6,6 +6,7 @@ This program has been developed by students from the bachelor Computer Science a package aql import ( + "errors" "fmt" "strconv" @@ -22,19 +23,185 @@ ConvertQuery converts an IncomingQueryJSON object into AQL func (s *Service) ConvertQuery(JSONQuery *entity.IncomingQueryJSON) (*string, error) { // Check to make sure all indexes exist // The largest possible id for an entity - shitlist, _ := createHierarchy(JSONQuery) - for i, tree := range shitlist { - fmt.Println("I am triple(from,rel,to): " + strconv.Itoa(tree.Self.FromNode.ID) + "," + strconv.Itoa(tree.Self.Rel.ID) + "," + strconv.Itoa(tree.Self.ToNode.ID)) - fmt.Println("My relation contains the following nodes(from,to): " + strconv.Itoa(tree.Self.Rel.FromID) + "," + strconv.Itoa(tree.Self.Rel.ToID)) + largestEntityID := len(JSONQuery.Entities) - 1 + // The largest possible id for a relation + largestRelationID := len(JSONQuery.Relations) - 1 + + // Make sure no entity should be returned that is outside the range of that list + for _, e := range JSONQuery.Return.Entities { + // If this entity references an entity that is outside the range + if e > largestEntityID || e < 0 { + return nil, errors.New("non-existing entity referenced in return") + } + } + + // Make sure that no relation mentions a non-existing entity + for _, r := range JSONQuery.Relations { + if r.FromID > largestEntityID && r.FromType == "entity" || r.ToID > largestEntityID && r.ToType == "entity" { + return nil, errors.New("non-exisiting entity referenced in relation") + } + } + + // Make sure no non-existing relation is tried to be returned + for _, r := range JSONQuery.Return.Relations { + if r > largestRelationID || r < 0 { + return nil, errors.New("non-existing relation referenced in return") + } + } + // Don't run search if we are getting empty queries from unit tests + var tree []entity.Tree + var topNode entity.QueryEntityStruct + if len(JSONQuery.Entities) != 0 && len(JSONQuery.Relations) != 0 { + tree, topNode = createHierarchy(JSONQuery) + } + + for i, treeElement := range tree { + fmt.Println("I am triple(from,rel,to): " + strconv.Itoa(treeElement.Self.FromNode.ID) + "," + strconv.Itoa(treeElement.Self.Rel.ID) + "," + strconv.Itoa(treeElement.Self.ToNode.ID)) + fmt.Println("My relation contains the following nodes(from,to): " + strconv.Itoa(treeElement.Self.Rel.FromID) + "," + strconv.Itoa(treeElement.Self.Rel.ToID)) fmt.Println("My index is: " + strconv.Itoa(i)) - fmt.Println("My parent index is: " + strconv.Itoa(tree.Parent)) + fmt.Println("My parent index is: " + strconv.Itoa(treeElement.Parent)) fmt.Println("My children's indices are: ") - for j := range tree.Children { - fmt.Println(tree.Children[j]) + for j := range treeElement.Children { + fmt.Println(treeElement.Children[j]) } fmt.Println("Next please!") } - result := "" - return &result, nil + result := createQuery(JSONQuery, tree, topNode) + return result, nil +} + +/* +createQuery generates a query based on the json file provided + JSONQuery: *entity.IncomingQueryJSON, this is a parsedJSON struct holding all the data needed to form a query, + Return: *string, a string containing the corresponding AQL query and an error +*/ +func createQuery(JSONQuery *entity.IncomingQueryJSON, tree []entity.Tree, topNode entity.QueryEntityStruct) *string { + output := createLetFor("result", fmt.Sprintf("e_%v", topNode.ID), topNode.Name) + for constraint := range topNode.Constraints { + output += createFilter(topNode.Constraints[constraint], fmt.Sprintf("e_%v", topNode.ID)) + } + subQuery, subName := createQueryRecurse(JSONQuery, tree, 0, topNode) + subNames := []string{subName} + output += subQuery + output += createZeroFilter(append(subNames, fmt.Sprintf("e_%v", topNode.ID))) + output += createReturn(fmt.Sprintf("e_%v", topNode.ID), "", subNames) + output += "let nodes = union_distinct(flatten(result[**].nodes),[])\nlet edges = union_distinct(flatten(result[**].rel),[])\nreturn {\"vertices\":nodes,\"edges\":edges}" + return &output +} + +func createQueryRecurse(JSONQuery *entity.IncomingQueryJSON, tree []entity.Tree, currentindex int, topNode entity.QueryEntityStruct) (string, string) { + currentTree := tree[currentindex] + newNode := getTreeNewNode(currentTree, tree, topNode) + output := createLetFor(fmt.Sprintf("e%v", newNode.ID), fmt.Sprintf("e_%v", newNode.ID), newNode.Name) + output += fmt.Sprintf("FOR r%v IN %v", currentTree.Self.Rel.ID, currentTree.Self.Rel.Name) + for constraint := range newNode.Constraints { + output += createFilter(newNode.Constraints[constraint], fmt.Sprintf("e_%v", newNode.ID)) + } + for constraint := range currentTree.Self.Rel.QueryConstraintStruct { + output += createFilter(currentTree.Self.Rel.QueryConstraintStruct[constraint], fmt.Sprintf("r%v", currentTree.Self.Rel.ID)) + } + output += fmt.Sprintf("FILTER r%v._from == e_%v._id AND r%v._to == e_%v._id", currentTree.Self.Rel.ID, currentTree.Self.FromNode.ID, currentTree.Self.Rel.ID, currentTree.Self.ToNode.ID) + var subNames []string + for i := range currentTree.Children { + subQuery, subName := createQueryRecurse(JSONQuery, tree, currentTree.Children[i], topNode) + output += subQuery + subNames = append(subNames, subName) + } + output += createZeroFilter(append(subNames, fmt.Sprintf("e_%v", newNode.ID), fmt.Sprintf("r%v", currentTree.Self.Rel.ID))) + output += createReturn(fmt.Sprintf("e_%v", newNode.ID), fmt.Sprintf("r%v", currentTree.Self.Rel.ID), subNames) + return output, fmt.Sprintf("e%v", newNode.ID) +} + +func getTreeNewNode(currentTree entity.Tree, tree []entity.Tree, topNode entity.QueryEntityStruct) entity.QueryEntityStruct { + if currentTree.Parent < 0 { + if currentTree.Self.FromNode.ID == topNode.ID { + return currentTree.Self.ToNode + } else { + return currentTree.Self.FromNode + } + } else if currentTree.Self.FromNode.ID == tree[currentTree.Parent].Self.FromNode.ID || currentTree.Self.FromNode.ID == tree[currentTree.Parent].Self.ToNode.ID { + return currentTree.Self.ToNode + } else { + return currentTree.Self.FromNode + } +} + +func createLetFor(variableName string, forName string, enumerableName string) string { + return "LET " + variableName + " = (\n\tFOR " + forName + " IN " + enumerableName + "\n" +} + +func createFilter(constraint entity.QueryConstraintStruct, filtered string) string { + return "\tFILTER + " + filtered + constraint.Attribute + " " + wordsToLogicalSign(constraint) + " " + constraint.Value + " \n" +} + +func createZeroFilter(subNames []string) string { + output := "FILTER" + for i := range subNames { + output += fmt.Sprintf(" length(%v) != 0", subNames[i]) + if i < len(subNames)-1 { + output += " AND" + } + } + return output +} +func createReturn(nodeName string, relName string, subNames []string) string { + output := "RETURN {\"nodes\":union_distinct(" + for i := range subNames { + output += fmt.Sprintf("flatten(%v[**].nodes), ", subNames[i]) + } + output += "[" + nodeName + "]" + if len(subNames) == 0 { + output += ", []" + } + output += "), \"rel\": union_distinct(" + for i := range subNames { + output += fmt.Sprintf("flatten(%v[**].rel), ", subNames[i]) + } + output += "[" + relName + "]" + if len(subNames) == 0 { + output += ", []" + } + output += ")}\n)\n" + return output +} + +func wordsToLogicalSign(element entity.QueryConstraintStruct) string { + var match string + switch element.DataType { + case "string": + switch element.MatchType { + case "NEQ": + match = "!=" + case "contains": + match = "LIKE" + case "excludes": + match = "NOT LIKE" + default: //EQ + match = "==" + } + case "int": + switch element.MatchType { + case "NEQ": + match = "!=" + case "GT": + match = ">" + case "LT": + match = "<" + case "GET": + match = ">=" + case "LET": + match = "<=" + default: //EQ + match = "==" + } + default: /*bool*/ + switch element.MatchType { + case "NEQ": + match = "!=" + default: //EQ + match = "==" + } + } + return match } diff --git a/aql/convertQuery2.go b/aql/convertQuery2.go deleted file mode 100644 index 2170b4c..0000000 --- a/aql/convertQuery2.go +++ /dev/null @@ -1,192 +0,0 @@ -/* -This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course. -© Copyright Utrecht University (Department of Information and Computing Sciences) -*/ - -package aql - -import ( - "errors" - "fmt" - - "git.science.uu.nl/graphpolaris/query-conversion/entity" -) - -// Version 1.13 - -/* -ConvertQuery converts an IncomingQueryJSON object into AQL - JSONQuery: *entity.IncomingQueryJSON, the query to be converted to AQL - Returns: *string, the AQL query and a possible error -*/ -func (s *Service) ConvertQuery(JSONQuery *entity.IncomingQueryJSON) (*string, error) { - // Check to make sure all indexes exist - // The largest possible id for an entity - largestEntityID := len(JSONQuery.Entities) - 1 - // The largest possible id for a relation - largestRelationID := len(JSONQuery.Relations) - 1 - - // Make sure no entity should be returned that is outside the range of that list - for _, e := range JSONQuery.Return.Entities { - // If this entity references an entity that is outside the range - if e > largestEntityID || e < 0 { - return nil, errors.New("non-existing entity referenced in return") - } - } - - // Make sure that no relation mentions a non-existing entity - for _, r := range JSONQuery.Relations { - if r.FromID > largestEntityID && r.FromType == "entity" || r.ToID > largestEntityID && r.ToType == "entity" { - return nil, errors.New("non-exisiting entity referenced in relation") - } - } - - // Make sure no non-existing relation is tried to be returned - for _, r := range JSONQuery.Return.Relations { - if r > largestRelationID || r < 0 { - return nil, errors.New("non-existing relation referenced in return") - } - } - // Don't run search if we are getting empty queries from unit tests - var tree []entity.Tree - var topNode entity.QueryEntityStruct - if len(JSONQuery.Entities) != 0 && len(JSONQuery.Relations) != 0 { - tree, topNode = search(JSONQuery, 0) - } - result := createQuery(JSONQuery, tree, topNode) - return result, nil -} - -/* -createQuery generates a query based on the json file provided - JSONQuery: *entity.IncomingQueryJSON, this is a parsedJSON struct holding all the data needed to form a query, - Return: *string, a string containing the corresponding AQL query and an error -*/ -func createQuery(JSONQuery *entity.IncomingQueryJSON, tree []entity.Tree, topNode entity.QueryEntityStruct) *string { - output := createLetFor("result", fmt.Sprintf("e_%v", topNode.ID), topNode.Name) - for constraint := range topNode.Constraints { - output += createFilter(topNode.Constraints[constraint], fmt.Sprintf("e_%v", topNode.ID)) - } - subQuery, subName := createQueryRecurse(JSONQuery, tree, 0) - subNames := []string{subName} - output += subQuery - output += createZeroFilter(append(subNames, fmt.Sprintf("e_%v", topNode.ID))) - output += createReturn(fmt.Sprintf("e_%v", topNode.ID), "", subNames) - output += "let nodes = union_distinct(flatten(result[**].nodes),[])\nlet edges = union_distinct(flatten(result[**].rel),[])\nreturn {\"vertices\":nodes,\"edges\":edges}" - return &output -} - -func createQueryRecurse(JSONQuery *entity.IncomingQueryJSON, tree []entity.Tree, currentindex int) (string, string) { - currentTree := tree[currentindex] - newNode, oldNode := getTreeNewAndOldNode(currentTree, tree) - output := createLetFor(fmt.Sprintf("e%v", newNode.ID), fmt.Sprintf("e_%v", newNode.ID), newNode.Name) - output += fmt.Sprintf("FOR r%v IN %v", currentTree.Self.Rel.ID, currentTree.Self.Rel.Name) - for constraint := range newNode.Constraints { - output += createFilter(newNode.Constraints[constraint], fmt.Sprintf("e_%v", newNode.ID)) - } - for constraint := range currentTree.Self.Rel.QueryConstraintStruct { - output += createFilter(currentTree.Self.Rel.QueryConstraintStruct[constraint], fmt.Sprintf("r%v", currentTree.Self.Rel.ID)) - } - if currentTree.Self.Rel.FromID == newNode.ID { - output += fmt.Sprintf("FILTER r%v._from == e_%v._id AND r%v._to == e_%v._id", currentTree.Self.Rel.ID, newNode.ID, currentTree.Self.Rel.ID, oldNode.ID) - } else { - output += fmt.Sprintf("FILTER r%v._from == e_%v._id AND r%v._to == e_%v._id", currentTree.Self.Rel.ID, oldNode.ID, currentTree.Self.Rel.ID, newNode.ID) - } - var subNames []string - for i := range currentTree.Children { - subQuery, subName := createQueryRecurse(JSONQuery, tree, currentTree.Children[i]) - output += subQuery - subNames = append(subNames, subName) - } - output += createZeroFilter(append(subNames, fmt.Sprintf("e_%v", newNode.ID), fmt.Sprintf("r%v", currentTree.Self.Rel.ID))) - output += createReturn(fmt.Sprintf("e_%v", newNode.ID), fmt.Sprintf("r%v", currentTree.Self.Rel.ID), subNames) - return output, fmt.Sprintf("e%v", newNode.ID) -} - -func getTreeNewAndOldNode(currentTree entity.Tree, tree []entity.Tree) (entity.QueryEntityStruct, entity.QueryEntityStruct) { - if currentTree.Self.FromNode.ID == tree[currentTree.Parent].Self.FromNode.ID || currentTree.Self.FromNode.ID == tree[currentTree.Parent].Self.ToNode.ID { - return currentTree.Self.ToNode, currentTree.Self.FromNode - } else { - return currentTree.Self.FromNode, currentTree.Self.ToNode - } -} - -func createLetFor(variableName string, forName string, enumerableName string) string { - return "LET " + variableName + " = (\n\tFOR " + forName + " IN " + enumerableName + "\n" -} - -func createFilter(constraint entity.QueryConstraintStruct, filtered string) string { - return "\tFILTER + " + filtered + constraint.Attribute + " " + wordsToLogicalSign(constraint) + " " + constraint.Value + " \n" -} - -func createZeroFilter(subNames []string) string { - output := "FILTER" - for i := range subNames { - output += fmt.Sprintf(" length(%v) != 0", subNames[i]) - if i < len(subNames)-1 { - output += " AND" - } - } - return output -} - -func createReturn(nodeName string, relName string, subNames []string) string { - output := "RETURN {\"nodes\":union_distinct(" - for i := range subNames { - output += fmt.Sprintf("flatten(%v[**].nodes), ", subNames[i]) - } - output += "[" + nodeName + "]" - if len(subNames) == 0 { - output += ", []" - } - output += "), \"rel\": union_distinct(" - for i := range subNames { - output += fmt.Sprintf("flatten(%v[**].rel), ", subNames[i]) - } - output += "[" + relName + "]" - if len(subNames) == 0 { - output += ", []" - } - output += ")}\n)\n" - return output -} - -func wordsToLogicalSign(element entity.QueryConstraintStruct) string { - var match string - switch element.DataType { - case "string": - switch element.MatchType { - case "NEQ": - match = "!=" - case "contains": - match = "LIKE" - case "excludes": - match = "NOT LIKE" - default: //EQ - match = "==" - } - case "int": - switch element.MatchType { - case "NEQ": - match = "!=" - case "GT": - match = ">" - case "LT": - match = "<" - case "GET": - match = ">=" - case "LET": - match = "<=" - default: //EQ - match = "==" - } - default: /*bool*/ - switch element.MatchType { - case "NEQ": - match = "!=" - default: //EQ - match = "==" - } - } - return match -} diff --git a/realtest.json b/realtest.json index c007bf0..5b928f0 100644 --- a/realtest.json +++ b/realtest.json @@ -12,7 +12,7 @@ "constraints": [] }, { - "name": "commission", + "name": "commissions", "ID": 1, "constraints": [] }, -- GitLab