Skip to content
Snippets Groups Projects
Commit da8b880b authored by Geurtjens,D. (Douwe Geurtjens)'s avatar Geurtjens,D. (Douwe Geurtjens)
Browse files

Merge branch 'Different-JSON-Format' of...

Merge branch 'Different-JSON-Format' of https://git.science.uu.nl/GravenvanPolaris/query-conversion into Different-JSON-Format
parents 3cd4555d ec3e24de
No related branches found
No related tags found
1 merge request!1Big merge
......@@ -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
}
/*
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
}
......@@ -28,7 +28,7 @@
]
},
{
"name": "commission",
"name": "commissions",
"ID": 1,
"constraints": []
},
......
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