Skip to content
Snippets Groups Projects
Commit aaafb923 authored by Geurtjens,D. (Douwe Geurtjens)'s avatar Geurtjens,D. (Douwe Geurtjens)
Browse files

Created a validator for JSON format, improved unit-testing

parent 12e74013
No related branches found
No related tags found
1 merge request!1Big merge
......@@ -22,42 +22,32 @@ ConvertQuery converts an IncomingQueryJSON object into AQL
Returns: *string, the AQL query and a possible error
*/
func (s *Service) ConvertQuery(JSONQuery *entity.IncomingQueryJSON) (*string, error) {
// TODO: MICHAEL WANT A SINGLE ENTITY TO RETURN A SUMMARY OF ATTRIBUTE VALUES (HISTOGRAM THINGIES)
// Check to make sure all indexes exist
// The largest possible id for an entity
largestEntityID := len(JSONQuery.Entities) - 1
entityCount := len(JSONQuery.Entities) - 1
// The largest possible id for a relation
largestRelationID := len(JSONQuery.Relations) - 1
if largestEntityID < 0 && largestRelationID < 0 {
relationCount := len(JSONQuery.Relations) - 1
// There are no entities or relations, our query is empty
if entityCount < 0 && relationCount < 0 {
fmt.Println("Empty query sent, returning default response")
defaultReturn := `LET nodes = first(RETURN UNION_DISTINCT([],[]))
LET edges = first(RETURN UNION_DISTINCT([],[]))
RETURN {"vertices":nodes, "edges":edges }`
return &defaultReturn, nil
return defaultReturn()
}
// Make sure no entity should be returned that is outside the range of that list
for _, e := range JSONQuery.Return.Entities {
// If this entity references an entity that is outside the range
if e > largestEntityID || e < 0 {
return nil, errors.New("non-existing entity referenced in return")
}
// There are no enities or there are no relations
if entityCount < 0 || relationCount < 0 {
fmt.Println("No relations or entities sent, returning default response")
return defaultReturn()
}
// Make sure that no relation mentions a non-existing entity
for _, r := range JSONQuery.Relations {
if r.FromID > largestEntityID && r.FromType == "entity" || r.ToID > largestEntityID && r.ToType == "entity" {
return nil, errors.New("non-exisiting entity referenced in relation")
potentialErrors := entity.ValidateStruct(*JSONQuery)
// If we find the JSONQuery to be invalid we return a error
if len(potentialErrors) != 0 {
for _, err := range potentialErrors {
fmt.Printf("err: %v\n", err)
}
return nil, errors.New("JSONQuery invalid")
}
// Make sure no non-existing relation is tried to be returned
for _, r := range JSONQuery.Return.Relations {
if r > largestRelationID || r < 0 {
return nil, errors.New("non-existing relation referenced in return")
}
}
// Don't run search if we are getting empty queries from unit tests
var tree []entity.Tree
var topNode entity.QueryEntityStruct
if len(JSONQuery.Entities) != 0 && len(JSONQuery.Relations) != 0 {
......@@ -303,3 +293,10 @@ func getModifierType(modifier entity.QueryModifierStruct) string {
}
return modifier.Type
}
func defaultReturn() (*string, error) {
defaultReturn := `LET nodes = first(RETURN UNION_DISTINCT([],[]))
LET edges = first(RETURN UNION_DISTINCT([],[]))
RETURN {"vertices":nodes, "edges":edges }`
return &defaultReturn, nil
}
This diff is collapsed.
......@@ -8,7 +8,6 @@ import (
const ENTITYSTRING = "entity"
const RELATIONSTRING = "relation"
const GROUPBYSTRING = "groupBy"
const FILTERSTRING = "filter"
var relationdone map[int]bool
......
package entity
import (
"errors"
"math"
)
const ENTITYSTRING = "entity"
const RELATIONSTRING = "relation"
const GROUPBYSTRING = "groupBy"
/*
sliceContains checks if a slice contains the input
JSONQuery: IncomingQueryJSON, the query in JSON to be validated
Return: []error, a list of specific transgression in this specific JSON query'
*/
func ValidateStruct(JSONQuery IncomingQueryJSON) []error {
ret := make([]error, 0)
minEntityID, maxEntityID := getMinAndMaxEntityID(JSONQuery.Entities)
minRelationID, maxRelationID := getMinAndMaxRelationID(JSONQuery.Relations)
minGroupByID, maxGroupByID := getMinAndMaxGroupByID(JSONQuery.GroupBys)
ret = append(ret, getIllegalToFromInRelation(JSONQuery, minEntityID, maxEntityID, minGroupByID, maxGroupByID)...)
if len(JSONQuery.GroupBys) != 0 {
ret = append(ret, getIllegalToFromInGroupBy(JSONQuery, minEntityID, maxEntityID, minRelationID, maxRelationID)...)
}
return ret
}
func getIllegalToFromInRelation(JSONQuery IncomingQueryJSON, minEntityID int, maxEntityID int, minGroupByID int, maxGroupByID int) []error {
ret := make([]error, 0)
for _, rel := range JSONQuery.Relations {
toEntityValid := relationToValid(rel, ENTITYSTRING, minEntityID, maxEntityID)
toGroupByValid := relationToValid(rel, GROUPBYSTRING, minGroupByID, maxGroupByID)
fromEntityValid := relationFromValid(rel, ENTITYSTRING, minEntityID, maxEntityID)
fromGroupByValid := relationFromValid(rel, GROUPBYSTRING, minGroupByID, maxGroupByID)
if !toEntityValid || !toGroupByValid {
err := errors.New("relation has invalid TO type and/or ID")
ret = append(ret, err)
}
if !fromEntityValid || !fromGroupByValid {
err := errors.New("relation has invalid FROM type and/or ID")
ret = append(ret, err)
}
}
return ret
}
func getIllegalToFromInGroupBy(JSONQuery IncomingQueryJSON, minEntityID int, maxEntityID int, minRelationID int, maxRelationID int) []error {
ret := make([]error, 0)
for _, groupBy := range JSONQuery.GroupBys {
groupEntityValid := groupByGroupValid(groupBy, ENTITYSTRING, minEntityID, maxEntityID)
groupRelationValid := groupByGroupValid(groupBy, RELATIONSTRING, minRelationID, maxRelationID)
byEntityValid := groupByByValid(groupBy, ENTITYSTRING, minEntityID, maxEntityID)
byRelationValid := groupByByValid(groupBy, RELATIONSTRING, minRelationID, maxRelationID)
if !groupEntityValid || !groupRelationValid {
err := errors.New("relation has invalid TO type and/or ID")
ret = append(ret, err)
}
if !byEntityValid || !byRelationValid {
err := errors.New("relation has invalid FROM type and/or ID")
ret = append(ret, err)
}
}
return ret
}
/*
Checks if a relation.ToType and relation.ToID are valid
Return: bool, whether the ToType and ToID are valid
*/
func relationToValid(rel QueryRelationStruct, typeString string, minID int, maxID int) bool {
if rel.ToType == typeString && rel.ToID >= minID || rel.ToType == typeString && rel.ToID <= maxID {
return true
}
return false
}
/*
Checks if a relation.FromType and relation.FromID are valid
Return: bool, whether the FromType and FromID are valid
*/
func relationFromValid(rel QueryRelationStruct, typeString string, minID int, maxID int) bool {
if rel.FromType == typeString && rel.FromID >= minID || rel.FromType == typeString && rel.FromID <= maxID {
return true
}
return false
}
func groupByGroupValid(groupBy QueryGroupByStruct, typeString string, minID int, maxID int) bool {
if groupBy.GroupType == typeString && groupBy.GroupID >= minID || groupBy.GroupType == typeString && groupBy.GroupID <= maxID {
return true
}
return false
}
func groupByByValid(groupBy QueryGroupByStruct, typeString string, minID int, maxID int) bool {
if groupBy.ByType == typeString && groupBy.ByID >= minID || groupBy.ByType == typeString && groupBy.ByID <= maxID {
return true
}
return false
}
func getMinAndMaxEntityID(entities []QueryEntityStruct) (int, int) {
min := math.MaxInt
max := math.MinInt
for _, e := range entities {
if e.ID < min {
min = e.ID
}
if e.ID > max {
max = e.ID
}
}
// If the min/max values didn't change the query would be invalid, and all consequent validationsteps will fail
return min, max
}
func getMinAndMaxRelationID(relations []QueryRelationStruct) (int, int) {
min := math.MaxInt
max := math.MinInt
for _, e := range relations {
if e.ID < min {
min = e.ID
}
if e.ID > max {
max = e.ID
}
}
// If the min/max values didn't change the query would be invalid, and all consequent validationsteps will fail
return min, max
}
func getMinAndMaxGroupByID(groupBys []QueryGroupByStruct) (int, int) {
min := math.MaxInt
max := math.MinInt
for _, e := range groupBys {
if e.ID < min {
min = e.ID
}
if e.ID > max {
max = e.ID
}
}
// If the min/max values didn't change the query would be invalid, and all consequent validationsteps will fail
return min, max
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment