package entity import ( "errors" ) 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)...) } if len(ret) == 0 { ret = append(ret, separatedChainExists(JSONQuery)...) } 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.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.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.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.ByID <= maxID { return true } return false } func getMinAndMaxEntityID(entities []QueryEntityStruct) (int, int) { min := 65535 max := -65535 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 := 65535 max := -65535 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 := 65535 max := -65535 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 } // Get chains that are not connected to the main chain func separatedChainExists(JSONQuery IncomingQueryJSON) []error { ret := make([]error, 0) entityCount := len(JSONQuery.Entities) relationCount := len(JSONQuery.Relations) // A relation always has 2 entities if it's on its own // If there is a chain (e-r-e-r-e) then there will be one more entity than relation // If there is two seperate chains you will always end up adding at least 2 entities more than relations // (e-r-e-r-e) and (e-r-e) has 3 relations but 5 entities, thus we know they are separate if relationCount != entityCount-1 { err := errors.New("separated chain found") ret = append(ret, err) } return ret }