diff --git a/cypher/convertQueryNew.go b/cypher/convertQueryNew.go index 3ffcd57945d2adbe5d3a790becacc4a3f3119ae7..885e169177d3d998f732b3656e5bef8a977fef26 100644 --- a/cypher/convertQueryNew.go +++ b/cypher/convertQueryNew.go @@ -12,40 +12,21 @@ import ( func (s *Service) ConvertQuery2(totalJSONQuery *entity.IncomingQueryJSON) (*string, error) { var finalCypher *string - // ** CHECK THAT THEY ARE NOT EQUAL IF RECURSED OTHERWISE FINAL RETURN WONT WORK queryJSON := totalJSONQuery - // Flattened out recursion on the JSON - // for { - - // Okay: er zou eigenlijk per cluster een aparte query gedaan moeten worden, maar voor nu pakt ie gewoon ff de eerste query, rest, isRest := checkForQueryCluster(queryJSON) - //fmt.Println(query) if isRest { fmt.Println("Rest:") fmt.Println(rest) - } - ok, err := checkEnoughReturn(query) - if ok { - finalCypher, err = createCypher(query) - if err != nil { - return nil, err - } - } else { - // do something with the error - fmt.Println(err) + // If something needs to be done with other query cluster, then add code here } - // if !isRest { - // break - // } else { - // queryJSON = rest - // } - // } - - //fmt.Println(*finalCypher) + finalCypher, err := createCypher(query) + if err != nil { + return nil, err + } return finalCypher, nil } @@ -53,8 +34,6 @@ func (s *Service) ConvertQuery2(totalJSONQuery *entity.IncomingQueryJSON) (*stri // createCypher creates queries without the return statement, due to the possibility of multiple disconnected queries func createCypher(JSONQuery *entity.IncomingQueryJSON) (*string, error) { - // ** NOTE: wat als er 2 clusters aan queries zijn, maar de een returned een tabel (want eindigt op een group by) en de ander is nodes en edges? - hierarchy, err := createQueryHierarchy(JSONQuery) if err != nil { //TODO @@ -63,14 +42,12 @@ func createCypher(JSONQuery *entity.IncomingQueryJSON) (*string, error) { cypher, err := formQuery(JSONQuery, hierarchy) if err != nil { - return nil, errors.New("") - //TODO + return nil, errors.New("Creation of query Cypher failed") } returnStatement, err := createReturnStatement(JSONQuery, hierarchy) if err != nil { - return nil, errors.New("") - //TODO + return nil, errors.New("Creation of return Cypher failed") } finalCypher := *cypher + *returnStatement @@ -78,35 +55,17 @@ func createCypher(JSONQuery *entity.IncomingQueryJSON) (*string, error) { return &finalCypher, nil } -type queryPart struct { - qType string // Eg if it is a relation or groupby - qID int // ID of said relation/gb - partID int // Custom ID used for dependency - dependencies []int // List of partID's that need to come before -} - -type query []queryPart - -func (q query) find(qID int, qType string) *queryPart { - for i := range q { - if q[i].qID == qID && q[i].qType == qType { - return &q[i] - } - } - return nil -} - // NOTE MOET MISSCHIEN ANDERS // createReturnStatement creates the final return statement, connecting all previous cypher together -func createReturnStatement(JSONQuery *entity.IncomingQueryJSON, parts query) (*string, error) { - // Hier dus weer de vraag of dingen boven een GROUP BY gereturned dienen te worden Lijkt mij niet +func createReturnStatement(JSONQuery *entity.IncomingQueryJSON, parts entity.Query) (*string, error) { + var retStatement string // First check to see if the return is a table (due to a groupby at the end) or if it is nodelink data numOfParts := len(parts) - if parts[numOfParts-1].qType == "groupBy" { + if parts[numOfParts-1].QType == "groupBy" { // Return is a table - groupBy := JSONQuery.FindG(parts[numOfParts-1].qID) + groupBy := JSONQuery.FindG(parts[numOfParts-1].QID) gName := fmt.Sprintf("%v_%v", groupBy.AppliedModifier, groupBy.GroupAttribute) by := fmt.Sprintf("%v%v.%v", string(groupBy.ByType[0]), groupBy.ByID, groupBy.ByAttribute) @@ -120,8 +79,8 @@ func createReturnStatement(JSONQuery *entity.IncomingQueryJSON, parts query) (*s lineStart := "" for i := numOfParts - 1; i >= 0; i-- { part := parts[i] - if part.qType == "relation" { - rel := JSONQuery.FindR(part.qID) + if part.QType == "relation" { + rel := JSONQuery.FindR(part.QID) retStatement += fmt.Sprintf("%v r%v", lineStart, rel.ID) lineStart = "," @@ -144,10 +103,11 @@ func createReturnStatement(JSONQuery *entity.IncomingQueryJSON, parts query) (*s retStatement += fmt.Sprintf("%v eg%v", lineStart, id) } } - } else if part.qType == "entity" { - // TODO + } else if part.QType == "entity" { + retStatement += fmt.Sprintf("%v e%v", lineStart, part.QID) + break - // Probably ends with a break to, since a single entity is always connected via an in? (maybe not in case of ONLY having an entity as the entire query) + // Probably ends with a break to, since a single entity is always connected via an IN to a groupby? (maybe not in case of ONLY having an entity as the entire query) } else { // Then it is a groupby which must not be returned, thus the returns are done. break @@ -160,16 +120,7 @@ func createReturnStatement(JSONQuery *entity.IncomingQueryJSON, parts query) (*s return &retStatement, nil } -func (q query) selectByID(ID int) *queryPart { - for _, part := range q { - if part.partID == ID { - return &part - } - } - return nil -} - -func createQueryHierarchy(JSONQuery *entity.IncomingQueryJSON) (query, error) { +func createQueryHierarchy(JSONQuery *entity.IncomingQueryJSON) (entity.Query, error) { // Pak de relations met de entities samen, en vorm groepjes van ent-rel-ent // Als A-rel-B-rel-C, dan wordt dat A-rel-B en B-rel-C, waarbij BC na AB moet komen, dus BC _depends_ on AB // Idee is dat je de hele lijst achterstevoren door kan lopen en dat je eerst een depend tegen komt en daarna het gene waarop gedepend wordt @@ -177,16 +128,16 @@ func createQueryHierarchy(JSONQuery *entity.IncomingQueryJSON) (query, error) { // ** HOUD NOG GEEN REKENING MET INS, MOET NOG WEL // maar is wat lastiger omdat dat wat extra checks vergt - var parts query + var parts entity.Query IDctr := 0 // Add them all to query parts for _, rel := range JSONQuery.Relations { - part := queryPart{ - qType: "relation", - qID: rel.ID, - partID: IDctr, - dependencies: make([]int, 0), + part := entity.QueryPart{ + QType: "relation", + QID: rel.ID, + PartID: IDctr, + Dependencies: make([]int, 0), } parts = append(parts, part) @@ -195,11 +146,11 @@ func createQueryHierarchy(JSONQuery *entity.IncomingQueryJSON) (query, error) { } for _, gb := range JSONQuery.GroupBys { - part := queryPart{ - qType: "groupBy", - qID: gb.ID, - partID: IDctr, - dependencies: make([]int, 0), + part := entity.QueryPart{ + QType: "groupBy", + QID: gb.ID, + PartID: IDctr, + Dependencies: make([]int, 0), } parts = append(parts, part) @@ -207,6 +158,30 @@ func createQueryHierarchy(JSONQuery *entity.IncomingQueryJSON) (query, error) { } + for _, ent := range JSONQuery.Entities { + + skip := true + for _, con := range ent.Constraints { + if con.InID != -1 { + skip = false + } + } + + if skip { + continue + } + + part := entity.QueryPart{ + QType: "entity", + QID: ent.ID, + PartID: IDctr, + Dependencies: make([]int, 0), + } + parts = append(parts, part) + + IDctr++ + } + // Check dependencies in a nice O(n^2) for _, rel := range JSONQuery.Relations { if rel.FromID == -1 { @@ -220,8 +195,8 @@ func createQueryHierarchy(JSONQuery *entity.IncomingQueryJSON) (query, error) { } if rel.FromID == rela.ToID && rel.FromType == rela.ToType { - part := parts.find(rel.ID, "relation") - part.dependencies = append(part.dependencies, parts.find(rela.ID, "relation").partID) + part := parts.Find(rel.ID, "relation") + part.Dependencies = append(part.Dependencies, parts.Find(rela.ID, "relation").PartID) } } @@ -233,9 +208,9 @@ func createQueryHierarchy(JSONQuery *entity.IncomingQueryJSON) (query, error) { // The GB always has priority for _, gb := range JSONQuery.GroupBys { if (rel.FromID == gb.ID && rel.FromType == "groupBy") || (rel.ToID == gb.ID && rel.ToType == "groupBy") { - part := parts.find(rel.ID, "relation") - gbID := parts.find(gb.ID, "groupBy").partID - part.dependencies = append(part.dependencies, gbID) + part := parts.Find(rel.ID, "relation") + gbID := parts.Find(gb.ID, "groupBy").PartID + part.Dependencies = append(part.Dependencies, gbID) } } } @@ -246,12 +221,12 @@ func createQueryHierarchy(JSONQuery *entity.IncomingQueryJSON) (query, error) { // Check if the gb is connected to the relation if (gb.ByID == rela.ID && gb.ByType == "relation") || // Is the By connected to a relation (gb.GroupID == rela.ID && gb.GroupType == "relation") || // is the Group connected to a relation - (gb.ByID == rela.FromID && gb.ByType == rela.FromType) || // Is the by connected to an entity connected to the relation - (gb.ByID == rela.ToID && gb.ByType == rela.ToType) || // Is the by connected to an entity connected to the relation - (gb.GroupID == rela.FromID && gb.GroupType == rela.FromType) || // Is the by connected to an entity connected to the relation - (gb.GroupID == rela.ToID && gb.GroupType == rela.ToType) { // Is the by connected to an entity connected to the relation - part := parts.find(gb.ID, "groupBy") - part.dependencies = append(part.dependencies, parts.find(rela.ID, "relation").partID) + (gb.ByID == rela.FromID && gb.ByType == rela.FromType) || // Is the by connected to an entity connected to the "From" of a relation + (gb.ByID == rela.ToID && gb.ByType == rela.ToType) || // Is the by connected to an entity connected to the "To" of a relation + (gb.GroupID == rela.FromID && gb.GroupType == rela.FromType) || // Is the group connected to an entity connected to the "From" of arelation + (gb.GroupID == rela.ToID && gb.GroupType == rela.ToType) { // Is the group connected to an entity connected to the "To" of a relation + part := parts.Find(gb.ID, "groupBy") + part.Dependencies = append(part.Dependencies, parts.Find(rela.ID, "relation").PartID) } } @@ -263,48 +238,58 @@ func createQueryHierarchy(JSONQuery *entity.IncomingQueryJSON) (query, error) { } if (gb.GroupID == grb.ID && gb.GroupType == "groupBy") || (gb.ByID == grb.ID && gb.ByType == "groupBy") { - part := parts.find(gb.ID, "groupBy") - part.dependencies = append(part.dependencies, parts.find(grb.ID, "groupBy").partID) + part := parts.Find(gb.ID, "groupBy") + part.Dependencies = append(part.Dependencies, parts.Find(grb.ID, "groupBy").PartID) + } + } + } + + for _, ent := range JSONQuery.Entities { + for _, con := range ent.Constraints { + if con.InID != -1 { + part := parts.Find(ent.ID, "entity") // Should always be groupBy + part.Dependencies = append(part.Dependencies, parts.Find(con.InID, con.InType).PartID) } } + } // Now we have a directed graph, meaning we can use some topological sort (Kahn's algorithm) - var sortedQuery query + var sortedQuery entity.Query incomingEdges := make(map[int]int) // Set all to 0 for _, p := range parts { - incomingEdges[p.partID] = 0 + incomingEdges[p.PartID] = 0 } // Count the incoming edges (dependencies) for _, p := range parts { - for _, dp := range p.dependencies { + for _, dp := range p.Dependencies { incomingEdges[dp]++ } } for { // While there is a someone where incomingEdges[someone] == 0 - part := queryPart{partID: -1} + part := entity.QueryPart{PartID: -1} // Select a node with no incoming edges for ID, edges := range incomingEdges { if edges == 0 { - part = *parts.selectByID(ID) + part = *parts.SelectByID(ID) } } // Check to see if there are parts withouth incoming edges left - if part.partID == -1 { + if part.PartID == -1 { break } // Remove it from the set - incomingEdges[part.partID] = -1 + incomingEdges[part.PartID] = -1 sortedQuery = append(sortedQuery, part) // Decrease incoming edges of other parts - for _, ID := range part.dependencies { + for _, ID := range part.Dependencies { incomingEdges[ID]-- } } @@ -322,11 +307,12 @@ func createQueryHierarchy(JSONQuery *entity.IncomingQueryJSON) (query, error) { return nil, errors.New("Cyclic query detected") } - //Reverse the list - retQuery := make([]queryPart, len(sortedQuery)) + // Reverse the list + retQuery := make([]entity.QueryPart, len(sortedQuery)) for i := 0; i < len(sortedQuery); i++ { retQuery[i] = sortedQuery[len(sortedQuery)-i-1] } + return retQuery, nil // ** HOUD NOG GEEN REKENING MET INS (van entities naar groupbys), MOET NOG WEL @@ -343,7 +329,7 @@ func createQueryHierarchy(JSONQuery *entity.IncomingQueryJSON) (query, error) { // om de query te maken } -func formQuery(JSONQuery *entity.IncomingQueryJSON, hierarchy query) (*string, error) { +func formQuery(JSONQuery *entity.IncomingQueryJSON, hierarchy entity.Query) (*string, error) { // ** NOTE: this does not create a return statement, that has yet to be made (which will also probably use the hierarchy) @@ -359,7 +345,7 @@ func formQuery(JSONQuery *entity.IncomingQueryJSON, hierarchy query) (*string, e var cypher *string var err error - switch entry.qType { + switch entry.QType { case "relation": cypher, err = createRelationCypher(JSONQuery, entry) if err != nil { @@ -375,6 +361,11 @@ func formQuery(JSONQuery *entity.IncomingQueryJSON, hierarchy query) (*string, e break case "entity": // This would be in case of an IN or if there was only 1 entity in the query builder + cypher, err = createInCypher(JSONQuery, entry) + if err != nil { + return nil, err + } + break default: // Should never be reached @@ -387,10 +378,41 @@ func formQuery(JSONQuery *entity.IncomingQueryJSON, hierarchy query) (*string, e return &totalQuery, nil } +func createInCypher(JSONQuery *entity.IncomingQueryJSON, part entity.QueryPart) (*string, error) { + ent := JSONQuery.FindE(part.QID) + eName := fmt.Sprintf("e%v", ent.ID) + + match := fmt.Sprintf("MATCH (%v:%v)\n", eName, ent.Name) + eConstraints := "" + newLineStatement := "\tWHERE" + + for _, con := range ent.Constraints { + if con.InID != -1 { + gby := JSONQuery.FindG(con.InID) // Because this could only be on a groupby + byName := fmt.Sprintf("%v%v", string(gby.ByType[0]), gby.ByID) + eConstraints += fmt.Sprintf("%v %v.%v IN %v_%v\n", newLineStatement, eName, con.Attribute, byName, gby.ByAttribute) + newLineStatement = "\tAND" + } + } + + for _, v := range ent.Constraints { + if v.InID != -1 { + continue + } + eConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, eName, false)) + } + + with := "WITH *\n" + retStatement := match + eConstraints + with + return &retStatement, nil + + // Should be able to test multiple IN statements from one entity, not sure if that will ever happen (maybe needs to be tested) +} + // createRelationCypher takes the json and a query part, finds the necessary entities and converts it into cypher -func createRelationCypher(JSONQuery *entity.IncomingQueryJSON, part queryPart) (*string, error) { +func createRelationCypher(JSONQuery *entity.IncomingQueryJSON, part entity.QueryPart) (*string, error) { - rel := JSONQuery.FindR(part.qID) + rel := JSONQuery.FindR(part.QID) if (rel.FromID == -1) && (rel.ToID == -1) { // Now there is only a relation, which we do not allow @@ -425,12 +447,12 @@ func createRelationCypher(JSONQuery *entity.IncomingQueryJSON, part queryPart) ( return nil, errors.New("Invalid connection type to relation") } - match = fmt.Sprintf("MATCH p%v = (%v:%v)-[:%v*%v..%v]-()\n", part.partID, eName, ent.Name, rel.Name, rel.Depth.Min, rel.Depth.Max) + match = fmt.Sprintf("MATCH p%v = (%v:%v)-[:%v*%v..%v]-()\n", part.PartID, eName, ent.Name, rel.Name, rel.Depth.Min, rel.Depth.Max) eConstraints = "" newLineStatement := "\tWHERE" for _, v := range ent.Constraints { - eConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, eName)) + eConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, eName, false)) newLineStatement = "\tAND" } @@ -463,12 +485,12 @@ func createRelationCypher(JSONQuery *entity.IncomingQueryJSON, part queryPart) ( return nil, errors.New("Invalid connection type to relation") } - match = fmt.Sprintf("MATCH p%v = ()-[:%v*%v..%v]-(%v:%v)\n", part.partID, rel.Name, rel.Depth.Min, rel.Depth.Max, eName, ent.Name) + match = fmt.Sprintf("MATCH p%v = ()-[:%v*%v..%v]-(%v:%v)\n", part.PartID, rel.Name, rel.Depth.Min, rel.Depth.Max, eName, ent.Name) eConstraints = "" newLineStatement := "\tWHERE" for _, v := range ent.Constraints { - eConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, eName)) + eConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, eName, false)) newLineStatement = "\tAND" } @@ -524,16 +546,16 @@ func createRelationCypher(JSONQuery *entity.IncomingQueryJSON, part queryPart) ( return nil, errors.New("Invalid connection type to relation") } - match = fmt.Sprintf("MATCH p%v = (%v:%v)-[:%v*%v..%v]-(%v:%v)\n", part.partID, eFName, entFrom.Name, rel.Name, rel.Depth.Min, rel.Depth.Max, eTName, entTo.Name) + match = fmt.Sprintf("MATCH p%v = (%v:%v)-[:%v*%v..%v]-(%v:%v)\n", part.PartID, eFName, entFrom.Name, rel.Name, rel.Depth.Min, rel.Depth.Max, eTName, entTo.Name) eConstraints = "" newLineStatement := "\tWHERE" for _, v := range entFrom.Constraints { - eConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, eFName)) + eConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, eFName, false)) newLineStatement = "\tAND" } for _, v := range entTo.Constraints { - eConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, eTName)) + eConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, eTName, false)) newLineStatement = "\tAND" } @@ -552,13 +574,13 @@ func createRelationCypher(JSONQuery *entity.IncomingQueryJSON, part queryPart) ( } } - rName := fmt.Sprintf("r%v", part.qID) - unwind = fmt.Sprintf("UNWIND relationships(p%v) as %v \nWITH *\n", part.partID, rName) + rName := fmt.Sprintf("r%v", part.QID) + unwind = fmt.Sprintf("UNWIND relationships(p%v) as %v \nWITH *\n", part.PartID, rName) rConstraints = "" newLineStatement := "\tWHERE" for _, v := range rel.Constraints { - rConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, rName)) + rConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, rName, false)) newLineStatement = "\tAND" } @@ -568,8 +590,8 @@ func createRelationCypher(JSONQuery *entity.IncomingQueryJSON, part queryPart) ( } // createGroupByCypher takes the json and a query part, finds the group by and converts it into cypher -func createGroupByCypher(JSONQuery *entity.IncomingQueryJSON, part queryPart) (*string, error) { - groupBy := JSONQuery.FindG(part.qID) +func createGroupByCypher(JSONQuery *entity.IncomingQueryJSON, part entity.QueryPart) (*string, error) { + groupBy := JSONQuery.FindG(part.QID) gName := fmt.Sprintf("%v_%v", groupBy.AppliedModifier, groupBy.GroupAttribute) by := fmt.Sprintf("%v%v.%v", string(groupBy.ByType[0]), groupBy.ByID, groupBy.ByAttribute) @@ -583,7 +605,7 @@ func createGroupByCypher(JSONQuery *entity.IncomingQueryJSON, part queryPart) (* gConstraints := "" newLineStatement := "\tWHERE" for _, v := range groupBy.Constraints { - gConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, gName)) + gConstraints += fmt.Sprintf("%v %v \n", newLineStatement, *createConstraintBoolExpression(&v, gName, true)) newLineStatement = "\tAND" } diff --git a/cypher/convertQueryNew_test.go b/cypher/convertQueryNew_test.go index c8560966b67399fdd0cf41d2fd288f8f390b4fdf..9a07ed8b2007a310ce9c29bdbe4cc601e73d67d7 100644 --- a/cypher/convertQueryNew_test.go +++ b/cypher/convertQueryNew_test.go @@ -561,3 +561,90 @@ func Test4(t *testing.T) { t.Fail() } +func Test5(t *testing.T) { + // Works, but, the AVG function is applied to a string, so that doesnt work, but the translation does :D + query := []byte(`{ + "databaseName": "Movies3", + "entities": [ + { + "id": 0, + "name": "Person", + "constraints": [] + }, + { + "id": 1, + "name": "Movie", + "constraints": [] + }, + { + "id": 2, + "name": "Person", + "constraints": [ + { + "attribute": "bornIn", + "value": "", + "dataType": "string", + "matchType": "", + "inID": 0, + "inType": "groupBy" + } + ] + } + ], + "relations": [ + { + "id": 0, + "name": "ACTED_IN", + "depth": { + "min": 1, + "max": 1 + }, + "fromType": "entity", + "fromID": 0, + "toType": "entity", + "toID": 1, + "constraints": [] + } + ], + "groupBys": [ + { + "id": 0, + "groupType": "entity", + "groupID": 1, + "groupAttribute": "imdbRating", + "byType": "entity", + "byID": 0, + "byAttribute": "bornIn", + "appliedModifier": "AVG", + "relationID": 0, + "constraints": [ + { + "attribute": "imdbRating", + "value": "7.5", + "dataType": "int", + "matchType": "GT", + "inID": -1, + "inType": "" + } + ] + } + ], + "machineLearning": [], + "limit": 5000 + } + `) + + var JSONQuery entity.IncomingQueryJSON + json.Unmarshal(query, &JSONQuery) + + s := NewService() + cypher, err := s.ConvertQuery2(&JSONQuery) + if err != nil { + fmt.Println(err) + } + + fmt.Println(*cypher) + + t.Fail() + +} diff --git a/cypher/createConstraints.go b/cypher/createConstraints.go index 6ec58a7be4cc70fd9210cb9f8e715dea189df463..33cd9f086176dd33b70f21ede8b794b7638526f2 100644 --- a/cypher/createConstraints.go +++ b/cypher/createConstraints.go @@ -22,7 +22,7 @@ func createConstraintStatements(constraints *[]entity.QueryConstraintStruct, nam newLineStatement := "\tWHERE" for _, v := range *constraints { - s += fmt.Sprintf("%v%v \n", newLineStatement, *createConstraintBoolExpression(&v, name)) + s += fmt.Sprintf("%v%v \n", newLineStatement, *createConstraintBoolExpression(&v, name, false)) newLineStatement = "\tAND" } @@ -38,7 +38,7 @@ isRelation is a boolean specifying if this constraint comes from a node or relat Return: a string containing an boolean expression of a single constraint */ -func createConstraintBoolExpression(constraint *entity.QueryConstraintStruct, name string) *string { +func createConstraintBoolExpression(constraint *entity.QueryConstraintStruct, name string, customAttribute bool) *string { var ( match string value string @@ -95,7 +95,12 @@ func createConstraintBoolExpression(constraint *entity.QueryConstraintStruct, na } } - line = fmt.Sprintf("%s %s.%s %s %s", neq, name, constraint.Attribute, match, value) + if customAttribute { + line = fmt.Sprintf("%s %s %s %s", neq, name, match, value) + } else { + + line = fmt.Sprintf("%s %s.%s %s %s", neq, name, constraint.Attribute, match, value) + } return &line } diff --git a/cypher/healthChecks.go b/cypher/healthChecks.go index 4c781cbee52a538832b4606f92ac43aef8bfee15..03466d40131cbe3772d71afd96c8461360b69130 100644 --- a/cypher/healthChecks.go +++ b/cypher/healthChecks.go @@ -1,7 +1,6 @@ package cypher import ( - "errors" "fmt" "git.science.uu.nl/graphpolaris/query-conversion/entity" @@ -164,10 +163,8 @@ func checkForQueryCluster(JSONQuery *entity.IncomingQueryJSON) (*entity.Incoming if cluster[name] { clusterJSON.Entities = append(clusterJSON.Entities, ent) - clusterJSON.Return.Entities = append(clusterJSON.Return.Entities, ent.ID) } else { restJSON.Entities = append(restJSON.Entities, ent) - restJSON.Return.Entities = append(restJSON.Return.Entities, ent.ID) isRest = true } } @@ -178,10 +175,8 @@ func checkForQueryCluster(JSONQuery *entity.IncomingQueryJSON) (*entity.Incoming if cluster[name] { clusterJSON.Relations = append(clusterJSON.Relations, rel) - clusterJSON.Return.Relations = append(clusterJSON.Return.Relations, rel.ID) } else { restJSON.Relations = append(restJSON.Relations, rel) - restJSON.Return.Relations = append(restJSON.Return.Relations, rel.ID) isRest = true } } @@ -192,10 +187,8 @@ func checkForQueryCluster(JSONQuery *entity.IncomingQueryJSON) (*entity.Incoming if cluster[name] { clusterJSON.GroupBys = append(clusterJSON.GroupBys, gb) - clusterJSON.Return.GroupBys = append(clusterJSON.Return.GroupBys, gb.ID) } else { restJSON.GroupBys = append(restJSON.GroupBys, gb) - restJSON.Return.GroupBys = append(restJSON.Return.GroupBys, gb.ID) isRest = true } } @@ -209,23 +202,3 @@ func checkForQueryCluster(JSONQuery *entity.IncomingQueryJSON) (*entity.Incoming // Return cluster, rest en een bool die zegt of er een cluster is // Wss is het in 99% van de gevallen maar 1 cluster of een cluster met een verdwaalde node, maar toch } - -// ** MOGELIJK OBSOLETE, hangt af van de hierarchiefunctie -/* checkEnoughReturn performs checks to see if the query is valid. - -Returns a boolean indicating if the query is valid, the error will containt a custom message saying what is wrong with the query. -It is obviously possible the query is still invalid, but that is for the database to find out. -*/ -func checkEnoughReturn(JSONQuery *entity.IncomingQueryJSON) (bool, error) { - - // The first test is to see if there are at least 2 returns, since only one return is not possible (we do not allow relation only queries) - ret := JSONQuery.Return - numOfReturns := len(ret.Entities) + len(ret.GroupBys) + len(ret.Relations) - if numOfReturns < 2 { - return false, errors.New("Insufficient return values") - } - - return true, nil - - // Wel nog hier de notitie dat als er bijv 1 entity is, dat er dan een zieke summary query moet komen -} diff --git a/entity/queryStruct.go b/entity/queryStruct.go index acffc45aba58274f8b7281a9eb14d9a10d77ddef..66b99a34db43a388b7878458cb4897332f236640 100644 --- a/entity/queryStruct.go +++ b/entity/queryStruct.go @@ -115,3 +115,30 @@ func (JSONQuery IncomingQueryJSON) FindG(qID int) *QueryGroupByStruct { } return nil } + +type QueryPart struct { + QType string // Eg if it is a relation or groupby + QID int // ID of said relation/gb + PartID int // Custom ID used for dependency + Dependencies []int // List of partID's that need to come before +} + +type Query []QueryPart + +func (q Query) Find(qID int, qType string) *QueryPart { + for i := range q { + if q[i].QID == qID && q[i].QType == qType { + return &q[i] + } + } + return nil +} + +func (q Query) SelectByID(ID int) *QueryPart { + for _, part := range q { + if part.PartID == ID { + return &part + } + } + return nil +}