package cypher import ( "errors" "fmt" "git.science.uu.nl/graphpolaris/query-conversion/entity" ) // checkForQueryCluster will detect (and separate?) if there are multiple queries in the query panel and will try to sepate the queries. // Maybe also delete floating pills that have no connection (but that is a different function) func checkForQueryCluster(JSONQuery *entity.IncomingQueryJSON) (*entity.IncomingQueryJSON, *entity.IncomingQueryJSON, bool) { // cluster is a set for all pills (entities e0 e1 e2, relations r0 .., groub by g0 ..) cluster := make(map[string]bool) if len(JSONQuery.Relations) > 0 { rel := fmt.Sprintf("r%v", JSONQuery.Relations[0].ID) cluster[rel] = true if JSONQuery.Relations[0].ToID != -1 { // Take the first letter: entities with ID 0 -> e0 to := fmt.Sprintf("%v%v", string(JSONQuery.Relations[0].ToType[0]), JSONQuery.Relations[0].ToID) cluster[to] = true } if JSONQuery.Relations[0].FromID != -1 { from := fmt.Sprintf("%v%v", string(JSONQuery.Relations[0].FromType[0]), JSONQuery.Relations[0].FromID) cluster[from] = true } } else if len(JSONQuery.GroupBys) > 0 { gb := fmt.Sprintf("g%v", JSONQuery.GroupBys[0].ID) cluster[gb] = true group := fmt.Sprintf("%v%v", string(JSONQuery.GroupBys[0].GroupType[0]), JSONQuery.GroupBys[0].GroupID) cluster[group] = true by := fmt.Sprintf("%v%v", string(JSONQuery.GroupBys[0].ByType[0]), JSONQuery.GroupBys[0].ByID) cluster[by] = true } else { // If there is no relation or groupby then there is no query cluster atm // Needs to change when the summary pill is introduced return nil, nil, false } for i := 0; i < 100; i++ { stop := true // Iteratively check to see if something is connected to the cluster // It should have skips for when something has already been added to the cluster, but due to complex connections (like an IN or groupby attached to a relation) // It is easier to just try everything everytime (and its computationally insignificant) // The loop stops when nothing was added for a round for _, rel := range JSONQuery.Relations { rela := fmt.Sprintf("r%v", rel.ID) partOfCluster := false // Now comes the check to see if one of its endpoints is in the cluster, meaning everything is in the cluster if rel.ToID != -1 { to := fmt.Sprintf("%v%v", string(rel.ToType[0]), rel.ToID) if cluster[to] { partOfCluster = true } } if rel.FromID != -1 { from := fmt.Sprintf("%v%v", string(rel.FromType[0]), rel.FromID) if cluster[from] { partOfCluster = true } } if partOfCluster { if rel.ToID != -1 { to := fmt.Sprintf("%v%v", string(rel.ToType[0]), rel.ToID) cluster[to] = true } if rel.FromID != -1 { from := fmt.Sprintf("%v%v", string(rel.FromType[0]), rel.FromID) cluster[from] = true } cluster[rela] = true stop = false } } // Check to see if an entity is connected to the cluster via an 'IN' for _, ent := range JSONQuery.Entities { self := fmt.Sprintf("e%v", ent.ID) for _, con := range ent.Constraints { if con.InID != -1 { in := fmt.Sprintf("%v%v", string(con.InType[0]), con.InID) if cluster[in] { cluster[self] = true stop = false } } } } // Now the same for Group by's for _, gb := range JSONQuery.GroupBys { gby := fmt.Sprintf("g%v", gb.ID) // It should have been checked that the connections of the group by are valid, since a group by must have all connections filled (in contrary of a relation) group := fmt.Sprintf("%v%v", string(gb.GroupType[0]), gb.GroupID) by := fmt.Sprintf("%v%v", string(gb.ByType[0]), gb.ByID) if cluster[group] || cluster[by] { cluster[gby] = true cluster[group] = true cluster[by] = true stop = false } } if stop { // No new entities were added to the cluster, thus it is finished break } } // Now walk through the JSON and divide it into the cluster and rest restJSON := entity.IncomingQueryJSON{DatabaseName: JSONQuery.DatabaseName, Limit: JSONQuery.Limit} clusterJSON := entity.IncomingQueryJSON{DatabaseName: JSONQuery.DatabaseName, Limit: JSONQuery.Limit} isRest := false // Loop through entities for _, ent := range JSONQuery.Entities { name := fmt.Sprintf("e%v", ent.ID) if cluster[name] { clusterJSON.Entities = append(clusterJSON.Entities, ent) } else { restJSON.Entities = append(restJSON.Entities, ent) isRest = true } } // Loop through relations for _, rel := range JSONQuery.Relations { name := fmt.Sprintf("r%v", rel.ID) if cluster[name] { clusterJSON.Relations = append(clusterJSON.Relations, rel) } else { restJSON.Relations = append(restJSON.Relations, rel) isRest = true } } // Loop through groupby's for _, gb := range JSONQuery.GroupBys { name := fmt.Sprintf("g%v", gb.ID) if cluster[name] { clusterJSON.GroupBys = append(clusterJSON.GroupBys, gb) } else { restJSON.GroupBys = append(restJSON.GroupBys, gb) isRest = true } } return &clusterJSON, &restJSON, isRest } // checkNoDeadEnds checks to see if al from's and to's exist func checkNoDeadEnds(JSONQuery *entity.IncomingQueryJSON) (bool, error) { // Check for all the connections of a relation for _, rel := range JSONQuery.Relations { if rel.FromID != -1 { if rel.FromType == "entity" { ent := JSONQuery.FindE(rel.FromID) if ent == nil { return false, errors.New("Invalid query") } } else if rel.FromType == "groupBy" { gb := JSONQuery.FindG(rel.FromID) if gb == nil { return false, errors.New("Invalid query") } } } if rel.ToID != -1 { if rel.ToType == "entity" { ent := JSONQuery.FindE(rel.ToID) if ent == nil { return false, errors.New("Invalid query") } } else if rel.ToType == "groupBy" { gb := JSONQuery.FindG(rel.ToID) if gb == nil { return false, errors.New("Invalid query") } } } } // Check for all the connections of a group by for _, gb := range JSONQuery.GroupBys { if gb.GroupType == "entity" { ent := JSONQuery.FindE(gb.GroupID) if ent == nil { return false, errors.New("Invalid query") } } if gb.GroupType == "relation" { rel := JSONQuery.FindE(gb.GroupID) if rel == nil { return false, errors.New("Invalid query") } } if gb.ByType == "entity" { ent := JSONQuery.FindE(gb.ByID) if ent == nil { return false, errors.New("Invalid query") } } if gb.ByType == "relation" { rel := JSONQuery.FindE(gb.ByID) if rel == nil { return false, errors.New("Invalid query") } } } // Check all the connections of IN-statements for _, ent := range JSONQuery.Entities { if len(ent.Constraints) == 0 { continue } for _, cons := range ent.Constraints { if cons.InID == -1 { continue } gb := JSONQuery.FindG(cons.InID) if gb == nil { return false, errors.New("Invalid query") } } } return true, nil }