Skip to content
Snippets Groups Projects
clustering.go 5.02 KiB
Newer Older
  • Learn to ignore specific revisions
  • Joris's avatar
    Joris committed
    package cypher
    
    import (
    	"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)
    
    Joris's avatar
    Joris committed
    	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
    
    Joris's avatar
    Joris committed
    			to := fmt.Sprintf("%v%v", string(JSONQuery.Relations[0].ToType[0]), JSONQuery.Relations[0].ToID)
    
    Joris's avatar
    Joris committed
    			cluster[to] = true
    		}
    
    		if JSONQuery.Relations[0].FromID != -1 {
    
    Joris's avatar
    Joris committed
    			from := fmt.Sprintf("%v%v", string(JSONQuery.Relations[0].FromType[0]), JSONQuery.Relations[0].FromID)
    
    Joris's avatar
    Joris committed
    			cluster[from] = true
    		}
    
    	} else if len(JSONQuery.GroupBys) > 0 {
    		gb := fmt.Sprintf("g%v", JSONQuery.GroupBys[0].ID)
    		cluster[gb] = true
    
    
    		// TODO: Does not check if the groupby is properly connected
    
    Joris's avatar
    Joris committed
    		group := fmt.Sprintf("%v%v", string(JSONQuery.GroupBys[0].GroupType[0]), JSONQuery.GroupBys[0].GroupID)
    
    Joris's avatar
    Joris committed
    		cluster[group] = true
    
    
    Joris's avatar
    Joris committed
    		by := fmt.Sprintf("%v%v", string(JSONQuery.GroupBys[0].ByType[0]), JSONQuery.GroupBys[0].ByID)
    
    Joris's avatar
    Joris committed
    		cluster[by] = true
    
    
    Joris's avatar
    Joris committed
    	} else {
    
    		// If there is no relation or groupby then there is no query cluster atm
    		// Needs to change when the summary pill is introduced
    
    Joris's avatar
    Joris committed
    		return nil, nil, false
    
    Joris's avatar
    Joris committed
    
    	for i := 0; i < 100; i++ {
    
    Joris's avatar
    Joris committed
    		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
    
    Joris's avatar
    Joris committed
    
    		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 {
    
    Joris's avatar
    Joris committed
    				to := fmt.Sprintf("%v%v", string(rel.ToType[0]), rel.ToID)
    
    Joris's avatar
    Joris committed
    
    				if cluster[to] {
    					partOfCluster = true
    				}
    			}
    
    			if rel.FromID != -1 {
    
    Joris's avatar
    Joris committed
    				from := fmt.Sprintf("%v%v", string(rel.FromType[0]), rel.FromID)
    
    Joris's avatar
    Joris committed
    
    				if cluster[from] {
    					partOfCluster = true
    				}
    			}
    
    			if partOfCluster {
    				if rel.ToID != -1 {
    
    Joris's avatar
    Joris committed
    					to := fmt.Sprintf("%v%v", string(rel.ToType[0]), rel.ToID)
    
    Joris's avatar
    Joris committed
    					cluster[to] = true
    				}
    
    				if rel.FromID != -1 {
    
    Joris's avatar
    Joris committed
    					from := fmt.Sprintf("%v%v", string(rel.FromType[0]), rel.FromID)
    
    Joris's avatar
    Joris committed
    					cluster[from] = true
    				}
    
    
    Joris's avatar
    Joris committed
    				cluster[rela] = true
    
    Joris's avatar
    Joris committed
    				stop = false
    			}
    
    Joris's avatar
    Joris committed
    		// 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)
    
    Joris's avatar
    Joris committed
    
    
    Joris's avatar
    Joris committed
    			for _, con := range ent.Constraints {
    				if con.InID != -1 {
    					in := fmt.Sprintf("%v%v", string(con.InType[0]), con.InID)
    
    Joris's avatar
    Joris committed
    
    
    Joris's avatar
    Joris committed
    					if cluster[in] {
    						cluster[self] = true
    						stop = false
    
    Joris's avatar
    Joris committed
    					}
    				}
    			}
    
    Joris's avatar
    Joris committed
    		}
    
    		// 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)
    
    
    Joris's avatar
    Joris committed
    			group := fmt.Sprintf("%v%v", string(gb.GroupType[0]), gb.GroupID)
    			by := fmt.Sprintf("%v%v", string(gb.ByType[0]), gb.ByID)
    
    Joris's avatar
    Joris committed
    
    			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
    }