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

testing hierarchy recursion

parent b2c6fe20
No related branches found
No related tags found
1 merge request!1Big merge
......@@ -6,8 +6,8 @@ This program has been developed by students from the bachelor Computer Science a
package aql
import (
"errors"
"fmt"
"strconv"
"git.science.uu.nl/graphpolaris/query-conversion/entity"
)
......@@ -22,299 +22,19 @@ 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
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 listoflists []entity.PdictList
if len(JSONQuery.Entities) != 0 && len(JSONQuery.Relations) != 0 {
listoflists = search(JSONQuery, 0)
}
result := createQuery(JSONQuery, listoflists)
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, listoflists []entity.PdictList) *string {
query := ""
for list := range listoflists {
for index := range listoflists[list] {
element := listoflists[list][index]
fmt.Println(element.Typename)
switch element.Typename {
case "entity":
entity := JSONQuery.Entities[element.Pointer]
query += entityToQuery(entity, JSONQuery)
case "relation":
relation := JSONQuery.Relations[element.Pointer]
query += relationToQuery(relation, JSONQuery)
case "groupBy":
function := JSONQuery.GroupBys[element.Pointer]
query += functionToQuery(function, JSONQuery, list == len(listoflists)-1)
case "filter":
filter := JSONQuery.Filters[element.Pointer]
query += filterToQuery(filter, JSONQuery)
}
}
}
unusedRelations := findUnusedRelations(JSONQuery)
if len(unusedRelations) >= 0 {
query += "LET nodes = first(RETURN UNION_DISTINCT("
for i := range unusedRelations {
query += "flatten(" + unusedRelations[i] + "[**].vertices),"
}
query += "[],[]))\n"
query += "LET edges = first(RETURN UNION_DISTINCT("
for i := range unusedRelations {
query += "flatten(" + unusedRelations[i] + "[**].edges),"
}
query += "[],[]))\nRETURN {\"vertices\":nodes, \"edges\":edges }"
}
return &query
}
func entityToQuery(element entity.QueryEntityStruct, JSONQuery *entity.IncomingQueryJSON) string {
thisname := fmt.Sprintf("e%v", element.ID)
ret := createLetFor(thisname, element.Name)
ret += "\tRETURN x\n)\n"
return ret
}
func relationToQuery(element entity.QueryRelationStruct, JSONQuery *entity.IncomingQueryJSON) string {
thisname := fmt.Sprintf("r%v", element.ID)
ret := createLetFor(thisname, element.Name)
filters := tryGetFilterTo("relation", element.ID, JSONQuery)
var ydefined bool = false
var zdefined bool = false
if len(filters) > 0 {
for i := range filters {
filter := filters[i]
filter2 := filter
for filter2.FromType == "filter" {
filters2 := tryGetFilterTo("filter", filter.ID, JSONQuery)
filter2 = filters2[0]
}
if filter2.FromType == element.FromType && filter2.FromID == element.FromID {
ret += fmt.Sprintf("\tFOR y in f%v\n", filter.ID)
ydefined = true
} else {
ret += fmt.Sprintf("\tFOR z in f%v\n", filter.ID)
zdefined = true
}
}
}
if !ydefined {
ret += fmt.Sprintf("\tFOR y in %v%v\n", typeToPrefix(element.FromType), element.FromID)
}
if !zdefined {
ret += fmt.Sprintf("\tFOR z in %v%v\n", typeToPrefix(element.ToType), element.ToID)
}
ret += "\tFILTER x._from == y._id AND x._to == z._id\n"
ret += "\tLET nodes = APPEND([], [y, z])\n"
ret += "\tRETURN DISTINCT {\n"
ret += "\t\"edges\": x,\n"
ret += "\t\"vertices\": nodes\n\t}\n)\n"
return ret
}
func functionToQuery(element entity.QueryGroupByStruct, JSONQuery *entity.IncomingQueryJSON, final bool) string {
ret := getTupleVar(element, JSONQuery)
if final {
ret += createFinalGroupBy(element, JSONQuery)
} else {
ret += createGroupBy(element, JSONQuery)
}
return ret
}
func filterToQuery(element entity.QueryFilterStruct, JSONQuery *entity.IncomingQueryJSON) string {
thisname := fmt.Sprintf("f%v", element.ID)
var filteredpill string
filters := tryGetFilterTo("filter", element.ID, JSONQuery)
if len(filters) > 0 {
filteredpill = fmt.Sprintf("f%v", filters[0].ID)
} else {
filteredpill = fmt.Sprintf("%v%v", typeToPrefix(element.FromType), element.FromID)
}
ret := createLetFor(thisname, filteredpill)
if element.FromType == "groupBy" {
ret += fmt.Sprintf("\tFILTER x.modifier %v %v\n", wordsToLogicalSign(element), element.Value)
} else {
ret += fmt.Sprintf("\tFILTER x.%v %v %v\n", element.Attribute, wordsToLogicalSign(element), element.Value)
}
ret += "\tRETURN x\n)\n"
return ret
}
func createLetFor(variableName string, enumerableName string) string {
return "LET " + variableName + " = (\n\tFOR x IN " + enumerableName + "\n"
}
func typeToPrefix(pillType string) string {
switch pillType {
case "entity":
return "e"
case "relation":
return "r"
case "groupBy":
return "g"
case "filter":
return "f"
default:
return ""
}
}
func tryGetFilterTo(toType string, toID int, JSONQuery *entity.IncomingQueryJSON) []entity.QueryFilterStruct {
var list []entity.QueryFilterStruct
for i := range JSONQuery.Filters {
filter := JSONQuery.Filters[i]
if filter.ToType == toType && filter.ToID == toID {
list = append(list, filter)
}
}
return list
}
func tryGetFilterFrom(fromType string, fromID int, JSONQuery *entity.IncomingQueryJSON) []entity.QueryFilterStruct {
var list []entity.QueryFilterStruct
for i := range JSONQuery.Filters {
filter := JSONQuery.Filters[i]
if filter.FromType == fromType && filter.FromID == fromID {
list = append(list, filter)
}
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))
fmt.Println("My index is: " + strconv.Itoa(i))
fmt.Println("My parent index is: " + strconv.Itoa(tree.Parent))
fmt.Println("My children's indices are: ")
for j := range tree.Children {
fmt.Println(tree.Children[j])
}
fmt.Println("Next please!")
}
return list
}
func wordsToLogicalSign(element entity.QueryFilterStruct) 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
}
func getTupleVar(element entity.QueryGroupByStruct, JSONQuery *entity.IncomingQueryJSON) string {
result := ""
thisname := fmt.Sprintf("gt%v", element.ID)
result += createLetFor(thisname, JSONQuery.Relations[element.RelationID].Name)
result += createSubVariable("variable_0", "variable_1", fmt.Sprintf("r%v[**].vertices[1]", element.RelationID), "_id", "x._to", "_id")
result += createSubVariable("variable_2", "variable_3", fmt.Sprintf("%v%v", typeToPrefix(element.GroupType), element.GroupID), "_id", "x._from", element.GroupAttribute)
result += "\tRETURN {\n\t\t\"variable_0\": variable_1, \n\t\t\"variable_1\": variable_3\n\t}\n)\n"
return result
}
return &result, nil
func createSubVariable(variableName string, variableName2 string, forName string, filter1 string, filter2 string, returnValue string) string {
result := "\tLET " + variableName + " = (\n\t\tFOR y IN " + forName + "\n"
return result + "\t\tFILTER y." + filter1 + " == " + filter2 + "\n\t\tRETURN y." + returnValue + "\n\t) " +
"\n\tLET " + variableName2 + " = " + variableName + "[0] \n"
}
func createGroupBy(element entity.QueryGroupByStruct, JSONQuery *entity.IncomingQueryJSON) string {
thisname := fmt.Sprintf("g%v", element.ID)
tuplename := fmt.Sprintf("gt%v", element.ID)
result := createLetFor(thisname, tuplename)
result += createCollect(element)
result += "\tRETURN {\n\t_id: c,\n\tmodifier: variable_0\n\t}\n)\n"
return result
}
func createFinalGroupBy(element entity.QueryGroupByStruct, JSONQuery *entity.IncomingQueryJSON) string {
tuplename := fmt.Sprintf("gt%v", element.ID)
result := "FOR x IN " + tuplename + "\n"
result += createCollect(element)
filters := tryGetFilterFrom("groupBy", element.ID, JSONQuery)
if len(filters) > 0 {
for i := range filters {
result += createFilter(filters[i])
}
}
result += fmt.Sprintf("\tRETURN {\n\tname: c,\n\t%v: variable_0\n\t}\n)\n", element.GroupAttribute)
return result
}
func createCollect(element entity.QueryGroupByStruct) string {
return "\tCOLLECT c = x.variable_0 INTO groups = x.variable_1\n\t" +
"LET variable_0 = " + element.AppliedModifier + "(groups) \n"
}
func createFilter(filter entity.QueryFilterStruct) string {
return "\tFILTER variable_0 " + wordsToLogicalSign(filter) + " " + filter.Value + " \n"
}
func findUnusedRelations(JSONQuery *entity.IncomingQueryJSON) []string {
var unused []string
for i := range JSONQuery.Relations {
relationUnused := true
relation := JSONQuery.Relations[i]
for j := range JSONQuery.GroupBys {
groupBy := JSONQuery.GroupBys[j]
if groupBy.RelationID == relation.ID {
relationUnused = false
}
}
if relationUnused {
unused = append(unused, fmt.Sprintf("r%v", relation.ID))
}
}
return unused
}
......@@ -8,11 +8,12 @@ import (
)
// We use consts to define string to prevent typos
/*
const ENTITYSTRING = "entity"
const RELATIONSTRING = "relation"
const GROUPBYSTRING = "groupBy"
const FILTERSTRING = "filter"
*/
var reldone map[int]bool
var entdone map[int]bool
var funcdone map[int]bool
......
package aql
import (
"git.science.uu.nl/graphpolaris/query-conversion/entity"
)
// We use consts to define string to prevent typos
const ENTITYSTRING = "entity"
const RELATIONSTRING = "relation"
const GROUPBYSTRING = "groupBy"
const FILTERSTRING = "filter"
var relationdone map[int]bool
func createHierarchy(JSONQuery *entity.IncomingQueryJSON) ([]entity.Tree, entity.QueryEntityStruct) {
var treeList []entity.Tree
relationdone = make(map[int]bool)
topNode := getTopNode(JSONQuery)
topTreeSelfTriple := getTripleFromNode(JSONQuery, topNode)
topTree := entity.Tree{
Self: topTreeSelfTriple,
Parent: -1,
Children: []int{},
}
treeList = append(treeList, topTree)
treeListIndex := len(treeList) - 1
treeList = getChildrenFromTree(JSONQuery, treeList, treeListIndex, 0)
return treeList, topNode
}
/*
Get a entity that has only 1 relation attached an return its index
*/
func getTopNode(JSONQuery *entity.IncomingQueryJSON) entity.QueryEntityStruct {
indexOfNodeToReturn := -1
for i, node := range JSONQuery.Entities {
connectionCount := 0
for _, relation := range JSONQuery.Relations {
if (relation.FromType == ENTITYSTRING && relation.FromID == node.ID) || (relation.ToType == ENTITYSTRING && relation.ToID == node.ID) {
connectionCount++
}
}
if connectionCount == 1 {
indexOfNodeToReturn = i
return JSONQuery.Entities[indexOfNodeToReturn]
}
}
return JSONQuery.Entities[indexOfNodeToReturn]
}
func getTripleFromNode(JSONQuery *entity.IncomingQueryJSON, node entity.QueryEntityStruct) entity.Triple {
var tripleToReturn entity.Triple
for _, relation := range JSONQuery.Relations {
// The initial node was our From so we set the Triple accordingly
// TODO
// If the To is not an entity we might have to do something different
if (relation.FromType == ENTITYSTRING && relation.FromID == node.ID) && relation.ToType == ENTITYSTRING {
tripleToReturn.FromNode = node
tripleToReturn.Rel = relation
tripleToReturn.ToNode = JSONQuery.Entities[relation.ToID]
} else if (relation.ToType == ENTITYSTRING && relation.ToID == node.ID) && relation.FromType == ENTITYSTRING {
tripleToReturn.FromNode = JSONQuery.Entities[relation.ToID]
tripleToReturn.Rel = relation
tripleToReturn.ToNode = node
}
}
relationdone[tripleToReturn.Rel.ID] = true
return tripleToReturn
}
func getTripleFromRelation(JSONQuery *entity.IncomingQueryJSON, relation entity.QueryRelationStruct) entity.Triple {
var tripleToReturn entity.Triple
tripleToReturn.FromNode = JSONQuery.Entities[relation.FromID]
tripleToReturn.Rel = relation
tripleToReturn.ToNode = JSONQuery.Entities[relation.ToID]
return tripleToReturn
}
func getChildrenFromTree(JSONQuery *entity.IncomingQueryJSON, treeList []entity.Tree, treeListIndex int, parentIndex int) []entity.Tree {
var childRelationTriples []entity.Triple
for i, relation := range JSONQuery.Relations {
// We found a relation that is not our parent relation so we can check if it matches on of our nodes
// If it matches one of the nodes we can add it
if _, ok := relationdone[i]; !ok {
if relation.FromType == ENTITYSTRING && relation.FromID == treeList[parentIndex].Self.FromNode.ID {
triple := getTripleFromRelation(JSONQuery, relation)
childRelationTriples = append(childRelationTriples, triple)
relationdone[i] = true
} else if relation.ToType == ENTITYSTRING && relation.ToID == treeList[parentIndex].Self.ToNode.ID {
triple := getTripleFromRelation(JSONQuery, relation)
childRelationTriples = append(childRelationTriples, triple)
relationdone[i] = true
}
}
}
// We now have all our children, so we can now make those trees and find their children
// We can now also add the indices to the list of children from the tree calling this function
if len(childRelationTriples) != 0 {
for _, triple := range childRelationTriples {
childTree := entity.Tree{
Self: triple,
Parent: treeListIndex,
Children: []int{},
}
treeList = append(treeList, childTree)
// We get the new treeListIndex, which we can now add to the list of children from the tree calling this function
treeListIndex = len(treeList) - 1
treeList[parentIndex].Children = append(treeList[parentIndex].Children, treeListIndex)
return getChildrenFromTree(JSONQuery, treeList, treeListIndex, treeListIndex)
}
}
return treeList
}
......@@ -8,9 +8,9 @@ type Pdict struct {
}
type Triple struct {
In int
Rel int
Out int
FromNode QueryEntityStruct
Rel QueryRelationStruct
ToNode QueryEntityStruct
}
type Tree struct {
......
......@@ -7,26 +7,86 @@
},
"entities": [
{
"name": "airports",
"ID": 0
"name": "parliament",
"ID": 0,
"constraints": []
},
{
"name": "commission",
"ID": 1,
"constraints": []
},
{
"name": "parliament",
"ID": 2,
"constraints": []
},
{
"name": "parties",
"ID": 3,
"constraints": []
}
,
{
"name": "resolutions",
"ID": 4,
"constraints": []
}
],
"groupBys": [],
"relations": [],
"filters": [
{
"ID": 0,
"fromType": "entity",
"fromID": 0,
"toType": "",
"toID": -1,
"attribute": "state",
"value": "HI",
"dataType": "string",
"matchType": "exact",
"inType": "",
"inID": -1
}
"relations": [
{
"ID": 0,
"name": "part_of",
"depth": {
"min": 1,
"max": 1
},
"fromType": "entity",
"fromId": 0,
"toType": "entity",
"toID": 1,
"constraints": []
},
{
"ID": 1,
"name": "part_of",
"depth": {
"min": 1,
"max": 1
},
"fromType": "entity",
"fromId": 2,
"toType": "entity",
"toID": 1,
"constraints": []
},
{
"ID": 2,
"name": "member_of",
"depth": {
"min": 1,
"max": 1
},
"fromType": "entity",
"fromId": 2,
"toType": "entity",
"toID": 3,
"constraints": []
},
{
"ID": 3,
"name": "submits",
"depth": {
"min": 1,
"max": 1
},
"fromType": "entity",
"fromId": 2,
"toType": "entity",
"toID": 4,
"constraints": []
}
],
"limit": 5000
}
\ No newline at end of file
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