diff --git a/aql/convertQuery.go b/aql/convertQuery.go index 9effc6e5329008057abf390378ab1aee49d5dd1f..707c09ed41c44bda19e7f176739543688603080c 100644 --- a/aql/convertQuery.go +++ b/aql/convertQuery.go @@ -48,10 +48,11 @@ func (s *Service) ConvertQuery(JSONQuery *entity.IncomingQueryJSON) (*string, er } } // 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 { - search(JSONQuery, 0) + listoflists = search(JSONQuery, 0) } - result := createQuery(JSONQuery) + result := createQuery(JSONQuery, listoflists) return result, nil } @@ -60,7 +61,7 @@ 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) *string { +func createQuery(JSONQuery *entity.IncomingQueryJSON, listoflists []entity.PdictList) *string { query := "" for list := range listoflists { for index := range listoflists[list] { diff --git a/aql/hierarchy.go b/aql/hierarchy.go index f61df5c66b159cb9b8a1b2cea8c6d1e165912780..7b78c759a0f6c937b5db71dd20900a74bfc22a77 100644 --- a/aql/hierarchy.go +++ b/aql/hierarchy.go @@ -7,14 +7,20 @@ import ( "git.science.uu.nl/graphpolaris/query-conversion/entity" ) -var listoflists []entity.PdictList +// 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 var relfuncdone map[int]bool var filterDone map[int]bool -func search(JSONQuery *entity.IncomingQueryJSON, index int) { +func search(JSONQuery *entity.IncomingQueryJSON, index int) []entity.PdictList { + var listoflists []entity.PdictList listoflists = []entity.PdictList{} reldone = make(map[int]bool) entdone = make(map[int]bool) @@ -25,14 +31,11 @@ func search(JSONQuery *entity.IncomingQueryJSON, index int) { //printSlice(s) //layercounter = 0 - initent := entity.Pdict{ - Typename: "entity", - Pointer: index, - } + initent := makePdict(ENTITYSTRING, index) s = append(s, initent) listoflists = append(listoflists, s) - entToRel(JSONQuery, initent) + listoflists = entToRel(JSONQuery, listoflists, initent) for i := range listoflists { for j := range listoflists[i] { @@ -40,9 +43,9 @@ func search(JSONQuery *entity.IncomingQueryJSON, index int) { } fmt.Println("") } - addFilters(JSONQuery) + listoflists = addFilters(JSONQuery, listoflists) fmt.Println(listoflists) - + return listoflists } /* @@ -51,7 +54,7 @@ Entities always get added IN FRONT OF their respective relation in the hierarchy JSONQuery: *entity.IncomingQueryJSON, the query in JSON format rel: pdict, the relation to find all connected entities for */ -func relToEnt(JSONQuery *entity.IncomingQueryJSON, rel entity.Pdict) { +func relToEnt(JSONQuery *entity.IncomingQueryJSON, listoflists []entity.PdictList, rel entity.Pdict) []entity.PdictList { var newlist entity.PdictList layercounter := findCurrentLayer(listoflists, rel) // Loop over all entities @@ -59,17 +62,11 @@ func relToEnt(JSONQuery *entity.IncomingQueryJSON, rel entity.Pdict) { // If an entity matches either the from or to in a relation we can add it to the newlist for i := range JSONQuery.Entities { if _, ok := entdone[i]; !ok { - if JSONQuery.Relations[rel.Pointer].FromID == i && JSONQuery.Relations[rel.Pointer].FromType == "entity" { - fromentity := entity.Pdict{ - Typename: "entity", - Pointer: i, - } + if JSONQuery.Relations[rel.Pointer].FromID == i && JSONQuery.Relations[rel.Pointer].FromType == ENTITYSTRING { + fromentity := makePdict(ENTITYSTRING, i) newlist = append(newlist, fromentity) - } else if JSONQuery.Relations[rel.Pointer].ToID == i && JSONQuery.Relations[rel.Pointer].ToType == "entity" { - toentity := entity.Pdict{ - Typename: "entity", - Pointer: i, - } + } else if JSONQuery.Relations[rel.Pointer].ToID == i && JSONQuery.Relations[rel.Pointer].ToType == ENTITYSTRING { + toentity := makePdict(ENTITYSTRING, i) newlist = append(newlist, toentity) } } @@ -88,11 +85,13 @@ func relToEnt(JSONQuery *entity.IncomingQueryJSON, rel entity.Pdict) { // So we recurse by calling EntToRel for i := range newlist { fmt.Println("EntToRel being called with index?: " + strconv.Itoa(newlist[i].Pointer)) - entToRel(JSONQuery, newlist[i]) + listoflists = entToRel(JSONQuery, listoflists, newlist[i]) } } + return listoflists + } /* @@ -101,7 +100,7 @@ Relation always get added BEHIND their respective entity in the hierarchy JSONQuery: *entity.IncomingQueryJSON, the query in JSON format ent: pdict, the entity to find all connected relations for */ -func entToRel(JSONQuery *entity.IncomingQueryJSON, ent entity.Pdict) { +func entToRel(JSONQuery *entity.IncomingQueryJSON, listoflists []entity.PdictList, ent entity.Pdict) []entity.PdictList { var newlist entity.PdictList layercounter := findCurrentLayer(listoflists, ent) // Loop over all relations @@ -109,17 +108,11 @@ func entToRel(JSONQuery *entity.IncomingQueryJSON, ent entity.Pdict) { // If a relation matches either the from or to with the entity we can add it to the newlist for i := range JSONQuery.Relations { if _, ok := reldone[i]; !ok { - if JSONQuery.Relations[i].FromID == ent.Pointer && JSONQuery.Relations[i].FromType == "entity" { - rel := entity.Pdict{ - Typename: "relation", - Pointer: i, - } + if JSONQuery.Relations[i].FromID == ent.Pointer && JSONQuery.Relations[i].FromType == ENTITYSTRING { + rel := makePdict(RELATIONSTRING, i) newlist = append(newlist, rel) - } else if JSONQuery.Relations[i].ToID == ent.Pointer && JSONQuery.Relations[i].ToType == "entity" { - rel := entity.Pdict{ - Typename: "relation", - Pointer: i, - } + } else if JSONQuery.Relations[i].ToID == ent.Pointer && JSONQuery.Relations[i].ToType == ENTITYSTRING { + rel := makePdict(RELATIONSTRING, i) newlist = append(newlist, rel) } } @@ -138,12 +131,13 @@ func entToRel(JSONQuery *entity.IncomingQueryJSON, ent entity.Pdict) { // So we recurse by calling RelToEnt and RelToAllFunc for i := range newlist { fmt.Println("RelToEnt being called with index?: " + strconv.Itoa(newlist[i].Pointer)) - relToEnt(JSONQuery, newlist[i]) + listoflists = relToEnt(JSONQuery, listoflists, newlist[i]) fmt.Println("RelToAllFunc being called with index?: " + strconv.Itoa(newlist[i].Pointer)) - relToAllFunc(JSONQuery, newlist[i]) + listoflists = relToAllFunc(JSONQuery, listoflists, newlist[i]) } } + return listoflists } /* @@ -154,7 +148,7 @@ If a function is connected to a relation (relation uses the results from the fun JSONQuery: *entity.IncomingQueryJSON, the query in JSON format rel: pdict, the relation to find all connected functions for */ -func relToAllFunc(JSONQuery *entity.IncomingQueryJSON, rel entity.Pdict) { +func relToAllFunc(JSONQuery *entity.IncomingQueryJSON, listoflists []entity.PdictList, rel entity.Pdict) []entity.PdictList { var funcappliedtosubquery entity.PdictList var functowhichrelapplies entity.PdictList layercounter := findCurrentLayer(listoflists, rel) @@ -167,27 +161,18 @@ func relToAllFunc(JSONQuery *entity.IncomingQueryJSON, rel entity.Pdict) { if _, ok := relfuncdone[rel.Pointer]; !ok { if _, ok := funcdone[i]; !ok { if JSONQuery.GroupBys[i].RelationID == rel.Pointer { - relfunc := entity.Pdict{ - Typename: "groupBy", - Pointer: i, - } + relfunc := makePdict(GROUPBYSTRING, i) funcappliedtosubquery = append(funcappliedtosubquery, relfunc) fmt.Println("I AM HERE 1") } - if JSONQuery.Relations[rel.Pointer].FromID == i && JSONQuery.Relations[rel.Pointer].FromType == "groupBy" { - fromfunc := entity.Pdict{ - Typename: "groupBy", - Pointer: i, - } + if JSONQuery.Relations[rel.Pointer].FromID == i && JSONQuery.Relations[rel.Pointer].FromType == GROUPBYSTRING { + fromfunc := makePdict(GROUPBYSTRING, i) functowhichrelapplies = append(functowhichrelapplies, fromfunc) fmt.Println("I AM HERE 2") - } else if JSONQuery.Relations[rel.Pointer].ToID == i && JSONQuery.Relations[rel.Pointer].ToType == "groupBy" { - tofunc := entity.Pdict{ - Typename: "groupBy", - Pointer: i, - } + } else if JSONQuery.Relations[rel.Pointer].ToID == i && JSONQuery.Relations[rel.Pointer].ToType == GROUPBYSTRING { + tofunc := makePdict(GROUPBYSTRING, i) functowhichrelapplies = append(functowhichrelapplies, tofunc) fmt.Println("I AM HERE 3") @@ -206,7 +191,7 @@ func relToAllFunc(JSONQuery *entity.IncomingQueryJSON, rel entity.Pdict) { for i := range functowhichrelapplies { fmt.Println("FuncToAllRell being called with index?: " + strconv.Itoa(functowhichrelapplies[i].Pointer)) - funcToAllRel(JSONQuery, functowhichrelapplies[i]) + listoflists = funcToAllRel(JSONQuery, listoflists, functowhichrelapplies[i]) } } @@ -217,10 +202,10 @@ func relToAllFunc(JSONQuery *entity.IncomingQueryJSON, rel entity.Pdict) { for i := range funcappliedtosubquery { fmt.Println("FuncToAllRel being called with index?: " + strconv.Itoa(funcappliedtosubquery[i].Pointer)) - funcToAllRel(JSONQuery, funcappliedtosubquery[i]) + listoflists = funcToAllRel(JSONQuery, listoflists, funcappliedtosubquery[i]) } } - + return listoflists } /* @@ -231,7 +216,7 @@ If a relation is connected to a function, we add the relation BEHIND its respect JSONQuery: *entity.IncomingQueryJSON, the query in JSON format function: pdict, the function to find all connected relations for */ -func funcToAllRel(JSONQuery *entity.IncomingQueryJSON, function entity.Pdict) { +func funcToAllRel(JSONQuery *entity.IncomingQueryJSON, listoflists []entity.PdictList, function entity.Pdict) []entity.PdictList { var funcappliedtosubquery entity.PdictList var relattachedtofunc entity.PdictList layercounter := findCurrentLayer(listoflists, function) @@ -240,26 +225,17 @@ func funcToAllRel(JSONQuery *entity.IncomingQueryJSON, function entity.Pdict) { if _, ok := relfuncdone[i]; !ok { // The func is attached to this relation if JSONQuery.GroupBys[function.Pointer].RelationID == i { - funcrel := entity.Pdict{ - Typename: "relation", - Pointer: i, - } + funcrel := makePdict(RELATIONSTRING, i) funcappliedtosubquery = append(funcappliedtosubquery, funcrel) } - if JSONQuery.Relations[i].FromID == function.Pointer && JSONQuery.Relations[i].FromType == "groupBy" { - fromrel := entity.Pdict{ - Typename: "relation", - Pointer: i, - } + if JSONQuery.Relations[i].FromID == function.Pointer && JSONQuery.Relations[i].FromType == GROUPBYSTRING { + fromrel := makePdict(RELATIONSTRING, i) relattachedtofunc = append(relattachedtofunc, fromrel) - } else if JSONQuery.Relations[i].ToID == function.Pointer && JSONQuery.Relations[i].ToType == "groupBy" { - torel := entity.Pdict{ - Typename: "relation", - Pointer: i, - } + } else if JSONQuery.Relations[i].ToID == function.Pointer && JSONQuery.Relations[i].ToType == GROUPBYSTRING { + torel := makePdict(RELATIONSTRING, i) relattachedtofunc = append(relattachedtofunc, torel) } @@ -277,9 +253,9 @@ func funcToAllRel(JSONQuery *entity.IncomingQueryJSON, function entity.Pdict) { for i := range funcappliedtosubquery { fmt.Println("RelToEnt being called with index?: " + strconv.Itoa(funcappliedtosubquery[i].Pointer)) - relToEnt(JSONQuery, funcappliedtosubquery[i]) + listoflists = relToEnt(JSONQuery, listoflists, funcappliedtosubquery[i]) fmt.Println("RelToAllFunc being called with index?: " + strconv.Itoa(funcappliedtosubquery[i].Pointer)) - relToAllFunc(JSONQuery, funcappliedtosubquery[i]) + listoflists = relToAllFunc(JSONQuery, listoflists, funcappliedtosubquery[i]) } } @@ -289,49 +265,42 @@ func funcToAllRel(JSONQuery *entity.IncomingQueryJSON, function entity.Pdict) { for i := range relattachedtofunc { fmt.Println("RelToEnt being called with index?: " + strconv.Itoa(relattachedtofunc[i].Pointer)) - relToEnt(JSONQuery, relattachedtofunc[i]) + listoflists = relToEnt(JSONQuery, listoflists, relattachedtofunc[i]) fmt.Println("RelToAllFunc being called with index?: " + strconv.Itoa(relattachedtofunc[i].Pointer)) - relToAllFunc(JSONQuery, relattachedtofunc[i]) + listoflists = relToAllFunc(JSONQuery, listoflists, relattachedtofunc[i]) } } + return listoflists } -func addFilters(JSONQuery *entity.IncomingQueryJSON) { +func addFilters(JSONQuery *entity.IncomingQueryJSON, listoflists []entity.PdictList) []entity.PdictList { for i, filter := range JSONQuery.Filters { if _, ok := filterDone[i]; !ok { - p := entity.Pdict{ - Typename: filter.FromType, - Pointer: filter.FromID, - } - f := entity.Pdict{ - Typename: "filter", - Pointer: filter.ID, - } - addOneFilter(f, JSONQuery, p, &filterDone) + p := makePdict(filter.FromType, filter.FromID) + f := makePdict(FILTERSTRING, filter.ID) + listoflists = addOneFilter(f, JSONQuery, listoflists, p, &filterDone) } } + return listoflists } -func addOneFilter(filterPDict entity.Pdict, JSONQuery *entity.IncomingQueryJSON, p entity.Pdict, filterDone *map[int]bool) { - if p.Typename == "filter" && (*filterDone)[p.Pointer] { +func addOneFilter(filterPDict entity.Pdict, JSONQuery *entity.IncomingQueryJSON, listoflists []entity.PdictList, p entity.Pdict, filterDone *map[int]bool) []entity.PdictList { + if p.Typename == FILTERSTRING && (*filterDone)[p.Pointer] { l := findCurrentLayer(listoflists, p) k := entity.PdictList{filterPDict} - if len(listoflists) > l+1 && listoflists[l+1][0].Typename == "filter" { + if len(listoflists) > l+1 && listoflists[l+1][0].Typename == FILTERSTRING { listoflists[l+1] = append(listoflists[l+1], filterPDict) } else { listoflists = filterAppend(listoflists, l, k) } (*filterDone)[filterPDict.Pointer] = true - } else if p.Typename == "filter" { - pnew := entity.Pdict{ - Typename: JSONQuery.Filters[p.Pointer].FromType, - Pointer: JSONQuery.Filters[p.Pointer].FromID, - } - addOneFilter(p, JSONQuery, pnew, filterDone) + } else if p.Typename == FILTERSTRING { + pnew := makePdict(JSONQuery.Filters[p.Pointer].FromType, JSONQuery.Filters[p.Pointer].FromID) + addOneFilter(p, JSONQuery, listoflists, pnew, filterDone) l := findCurrentLayer(listoflists, p) k := entity.PdictList{filterPDict} - if len(listoflists) > l+1 && listoflists[l+1][0].Typename == "filter" { + if len(listoflists) > l+1 && listoflists[l+1][0].Typename == FILTERSTRING { listoflists[l+1] = append(listoflists[l+1], filterPDict) } else { listoflists = filterAppend(listoflists, l, k) @@ -340,55 +309,56 @@ func addOneFilter(filterPDict entity.Pdict, JSONQuery *entity.IncomingQueryJSON, } else { l := findCurrentLayer(listoflists, p) k := entity.PdictList{filterPDict} - if len(listoflists) > l+1 && listoflists[l+1][0].Typename == "filter" { + if len(listoflists) > l+1 && listoflists[l+1][0].Typename == FILTERSTRING { listoflists[l+1] = append(listoflists[l+1], filterPDict) } else { listoflists = filterAppend(listoflists, l, k) } (*filterDone)[filterPDict.Pointer] = true } + return listoflists } // A function that appends 1 level above (if index is 0 this won't work) -func aboveAppend(lists []entity.PdictList, index int, values entity.PdictList) []entity.PdictList { +func aboveAppend(listoflists []entity.PdictList, index int, values entity.PdictList) []entity.PdictList { if index == 0 { - return prepend(lists, values) + return prepend(listoflists, values) } else { index-- for i := range values { - lists[index] = append(lists[index], values[i]) + listoflists[index] = append(listoflists[index], values[i]) } - return lists + return listoflists } } // A function that appends 1 level below -func belowAppend(lists []entity.PdictList, index int, values entity.PdictList) []entity.PdictList { +func belowAppend(listoflists []entity.PdictList, index int, values entity.PdictList) []entity.PdictList { if index == len(listoflists)-1 { - lists = append(listoflists, values) - return lists + listoflists = append(listoflists, values) + return listoflists } else { index++ for i := range values { - lists[index] = append(lists[index], values[i]) + listoflists[index] = append(listoflists[index], values[i]) } - return lists + return listoflists } } -func filterAppend(lists []entity.PdictList, index int, values entity.PdictList) []entity.PdictList { - if len(lists)-1 == index { // nil or empty slice or after last element - return append(lists, values) +func filterAppend(listoflists []entity.PdictList, index int, values entity.PdictList) []entity.PdictList { + if len(listoflists)-1 == index { // nil or empty slice or after last element + return append(listoflists, values) } - k := make([]entity.PdictList, len(lists[index+1:])) - copy(k, lists[index+1:]) - l := make([]entity.PdictList, len(lists[:index+1])) - copy(l, lists[:index+1]) - lists = append(l, values) // index < len(a) - return append(lists, k...) + k := make([]entity.PdictList, len(listoflists[index+1:])) + copy(k, listoflists[index+1:]) + l := make([]entity.PdictList, len(listoflists[:index+1])) + copy(l, listoflists[:index+1]) + listoflists = append(l, values) // index < len(a) + return append(listoflists, k...) } @@ -413,13 +383,21 @@ func findCurrentLayer(list []entity.PdictList, element entity.Pdict) int { // See XToY functions for example usage func prepend(list []entity.PdictList, element entity.PdictList) []entity.PdictList { var dummylist entity.PdictList - dummy := entity.Pdict{ - Typename: "dummy", - Pointer: -1, - } + dummy := makePdict("dummy", -1) dummylist = append(dummylist, dummy) list = append(list, dummylist) copy(list[1:], list) list[0] = element return list } + +/* +makePdict makes a pdict based on a typename and pointer +*/ +func makePdict(typeName string, pointer int) entity.Pdict { + return entity.Pdict{ + Typename: typeName, + Pointer: pointer, + } + +} diff --git a/aql/hierarchy_test.go b/aql/hierarchy_test.go index c65190e559450790b97ad94fb709339227ea66c9..4b5f5d20529d214c4abf79ef0e01b10a6a78d2f2 100644 --- a/aql/hierarchy_test.go +++ b/aql/hierarchy_test.go @@ -84,7 +84,7 @@ func TestHierarchyBasic(t *testing.T) { // Unmarshall the incoming message into an IncomingJSONQuery object var JSONQuery entity.IncomingQueryJSON json.Unmarshal(query, &JSONQuery) - search(&JSONQuery, 0) + listoflists := search(&JSONQuery, 0) // Assert that the result and the expected result are the same correctResult := `[[{entity 0} {entity 1}] [{filter 0}] [{relation 0}] [{filter 1}]]` @@ -173,7 +173,7 @@ func TestHierarchyRandomStart(t *testing.T) { correctResult[3] = entity.PdictList{{Typename: "filter", Pointer: 1}} for i := range JSONQuery.Entities { - search(&JSONQuery, i) + listoflists := search(&JSONQuery, i) sortedListOfLists := make([]entity.PdictList, len(listoflists)) for i, list := range listoflists { k := make(entity.PdictList, list.Len()) @@ -316,7 +316,7 @@ func TestHierarchyWithGroupby(t *testing.T) { correctResult[4] = entity.PdictList{{Typename: "relation", Pointer: 1}, {Typename: "relation", Pointer: 2}} for i := range JSONQuery.Entities { - search(&JSONQuery, i) + listoflists := search(&JSONQuery, i) fmt.Println(listoflists) sortedListOfLists := make([]entity.PdictList, len(listoflists))