From 186790555520835d280afd00a79422e82f61e521 Mon Sep 17 00:00:00 2001
From: Douwe <d.geurtjens@students.uu.nl>
Date: Tue, 26 Oct 2021 11:49:15 +0200
Subject: [PATCH] ADDED: Joes's changes pushed to the proper repository

---
 aql/convertQuery.go   |  74 ++++++++++++++++++++++++++++-
 entity/queryStruct.go |  25 ++++++++--
 main/main.go          | 108 +++++++++++++++++++++++-------------------
 3 files changed, 152 insertions(+), 55 deletions(-)

diff --git a/aql/convertQuery.go b/aql/convertQuery.go
index c9adaa5..955e87e 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 7b6c276..4076320 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 82d24ee..784d051 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)
-- 
GitLab