diff --git a/aql/convertQuery.go b/aql/convertQuery.go index c9adaa57559e9b09bf9abefd4838c482fcb195b8..955e87ef02e22f1424c59eb7cb3288b04596cedd 100644 --- a/aql/convertQuery.go +++ b/aql/convertQuery.go @@ -8,6 +8,7 @@ package aql import ( "errors" "fmt" + "strconv" "git.science.uu.nl/graphpolaris/query-conversion/entity" ) @@ -49,7 +50,13 @@ func (s *Service) ConvertQuery(JSONQuery *entity.IncomingQueryJSON) (*string, er } } - result := createQuery(JSONQuery) + var result *string + if len(JSONQuery.Functions) == 0 { + result = createQuery(JSONQuery) + } else { + result = createQueryWithFunctions(JSONQuery) + } + return result, nil } @@ -336,3 +343,68 @@ func createRelationLetWithOnlyToEntity(relation *entity.QueryRelationStruct, nam ret := header + forStatement + optionStmtn + relationFilterStmnt + footer return &ret } + +type variableNameGeneratorToken struct { + token int +} + +func newVariableNameGeneratorToken() *variableNameGeneratorToken { + v := variableNameGeneratorToken{token: 0} + return &v +} + +func variableNameGenerator(vngt *variableNameGeneratorToken) string { + result := "variable_" + strconv.Itoa(vngt.token) + vngt.token++ + return result +} + +func createQueryWithFunctions(JSONQuery *entity.IncomingQueryJSON) *string { + result := "" + v := newVariableNameGeneratorToken() + for i := 0; i < len(JSONQuery.Functions); i++ { + if JSONQuery.Functions[i].Type == "groupBy" { + a := variableNameGenerator(v) + b := variableNameGenerator(v) + c := variableNameGenerator(v) + d := variableNameGenerator(v) + e := variableNameGenerator(v) + f := variableNameGenerator(v) + g := variableNameGenerator(v) + h := variableNameGenerator(v) + + result += "LET " + a + " = (FOR r IN " + + JSONQuery.Relations[i].Type + " LET " + b + + " = (FOR c IN " + JSONQuery.Entities[JSONQuery.Functions[i].GroupID].Type + + " FILTER c._id == r._to return c." + JSONQuery.Functions[i].GroupAttribute + ") " + + "LET " + c + " = " + b + "[0] LET " + d + " = (" + + "FOR p in " + JSONQuery.Entities[JSONQuery.Functions[i].ByID].Type + + " FILTER p._id == r._from return p." + JSONQuery.Functions[i].ByAttribute + ") " + + "LET " + e + " = " + d + "[0] RETURN {\"" + f + "\" : " + c + ", " + + "\"" + g + "\" : " + e + "}) " + + "FOR r in " + a + " COLLECT c = r." + f + " INTO groups = r." + g + " " + + "LET " + h + " = " + JSONQuery.Functions[i].AppliedModifier + "(groups) " + if len(JSONQuery.Functions[i].Constraints) > 0 { + result += "FILTER " + h + " " + wordsToLogicalSign(JSONQuery.Functions[i].Constraints[0].MatchType) + " " + JSONQuery.Functions[i].Constraints[0].Value + " " + } + result += "RETURN {" + JSONQuery.Functions[i].GroupAttribute + " : c, " + + JSONQuery.Functions[i].AppliedModifier + "_" + JSONQuery.Functions[i].ByAttribute + " : " + h + "}" + + } + } + return &result +} + +func wordsToLogicalSign(word string) string { + if word == "LT" { + return "<" + } else if word == "LTE" { + return "<=" + } else if word == "EQ" { + return "==" + } else if word == "GTE" { + return ">=" + } else { + return ">" + } +} diff --git a/entity/queryStruct.go b/entity/queryStruct.go index 7b6c2760ac2ad7c0b1a002c516559011a85cdd5d..4076320aa4debbe687b23c39d026518dde772467 100644 --- a/entity/queryStruct.go +++ b/entity/queryStruct.go @@ -6,6 +6,7 @@ type IncomingQueryJSON struct { Return QueryReturnStruct Entities []QueryEntityStruct Relations []QueryRelationStruct + Functions []QueryFunctionStruct // Limit is for limiting the amount of paths AQL will return in a relation let statement Limit int Modifiers []QueryModifierStruct @@ -33,6 +34,19 @@ type QueryRelationStruct struct { Constraints []QueryConstraintStruct } +type QueryFunctionStruct struct { + Type string + TypeID int + GroupType string + GroupID int + GroupAttribute string + ByType string + ByID int + ByAttribute string + AppliedModifier string + Constraints []QueryConstraintStruct +} + // QueryModifierStruct encapsulates a single modifier with its corresponding constraints type QueryModifierStruct struct { Type string // SUM COUNT AVG @@ -50,11 +64,12 @@ type QuerySearchDepthStruct struct { // QueryConstraintStruct holds the information of the constraint // Constraint datatypes // string MatchTypes: exact/contains/startswith/endswith -// int MatchTypes: GT/LT/EQ +// int MatchTypes: GT/LT/EQ/ // bool MatchTypes: EQ/NEQ type QueryConstraintStruct struct { - Attribute string - Value string - DataType string - MatchType string + Attribute string + Value string + DataType string + MatchType string + FunctionPointer int } diff --git a/main/main.go b/main/main.go index 82d24ee2943c9a682d2e6751d946286bb4dcf54e..784d051aa98908d24847b6d806460174fb8af958 100644 --- a/main/main.go +++ b/main/main.go @@ -20,63 +20,73 @@ func main() { queryservice := aql.NewService() js := []byte(`{ - "databaseName": "test", - "return": { - "entities": [ - 0, - 1, - 2, - 3 - ], - "relations": [ + "return": { + "entities": [ 0, 1 - ] - }, - "entities": [ - { - "type": "kamerleden", - "constraints": [] - }, - { - "type": "partijen", - "constraints": [] - } - , - { - "type": "kamerleden", - "constraints": [] - }, - { - "type": "commissies", - "constraints": [] - } ], "relations": [ - { - "type": "lid_van", + 0 + ] + }, + "entities": [ + { + "type": "parliament", + "constraints": [] + }, + { + "type": "commissions", + "constraints": [] + } + ], + "relations": [ + { + "type": "part_of", "depth": { - "min": 1, - "max": 1 + "min": 1, + "max": 1 }, "entityFrom": 0, "entityTo": 1, - "constraints": [] - }, - { - "type": "onderdeel_van", - "depth": { - "min": 1, - "max": 1 - }, - "entityFrom": 2, - "entityTo": 3, - "constraints": [] - } - ], - "limit": 5000, - "modifiers": [] - }`) + "constraints": [], + "functionPointer": { + "from": -1, + "to": -1 + } + + } + ], + "functions": [ + { + "type": "groupBy", + "typeID": 0, + "groupType": "entity", + "groupID": 1, + "groupAttribute": "name", + "byType": "entity", + "byID": 0, + "byAttribute": "age", + "appliedModifier": "AVG", + "constraints": [ + { + "attribute": "age", + "value": "45", + "dataType": "number", + "matchType": "GT", + "functionPointer": { + "from": -1, + "to": -1 + } + + } + ] + } + ], + "limit": 5000, + "modifiers": [], + "databaseName": "TweedeKamer" +} +`) var inc entity.IncomingQueryJSON json.Unmarshal(js, &inc)