search: Add ValueMatches{Int,Float} to PermanodeConstraint.

Adds constraints for int- and float-valued attributes.

Change-Id: Ie8354f8ea12f604b45cf2fa6a7fb45170bab7e46
This commit is contained in:
Daniel Erat 2014-01-04 20:43:32 -08:00
parent 9c45ab99ad
commit 396c8a6211
2 changed files with 83 additions and 3 deletions

View File

@ -388,7 +388,7 @@ func (c *IntConstraint) intMatches(v int64) bool {
return true
}
// A FloatConstraint specifies constraints on an integer.
// A FloatConstraint specifies constraints on a float.
type FloatConstraint struct {
// Min and Max are both optional and inclusive bounds.
// Zero means don't check.
@ -574,6 +574,14 @@ type PermanodeConstraint struct {
// match the value against.
ValueMatches *StringConstraint `json:"valueMatches,omitempty"`
// ValueMatchesInt optionally specifies an IntConstraint to match
// the value against. Non-integer values will not match.
ValueMatchesInt *IntConstraint `json:"valueMatchesInt,omitempty"`
// ValueMatchesFloat optionally specifies a FloatConstraint to match
// the value against. Non-float values will not match.
ValueMatchesFloat *FloatConstraint `json:"valueMatchesFloat,omitempty"`
// ValueInSet optionally specifies a sub-query which the value
// (which must be a blobref) must be a part of.
ValueInSet *Constraint `json:"valueInSet,omitempty"`
@ -1008,11 +1016,15 @@ var numPermanodeFields = reflect.TypeOf(PermanodeConstraint{}).NumField()
// hasValueConstraint returns true if one or more constraints that check an attribute's value are set.
func (c *PermanodeConstraint) hasValueConstraint() bool {
// If a field has been added or removed, update this after adding the new field to the return statement if necessary.
const expectedFields = 12
const expectedFields = 14
if numPermanodeFields != expectedFields {
panic(fmt.Sprintf("PermanodeConstraint field count changed (now %v rather than %v)", numPermanodeFields, expectedFields))
}
return c.Value != "" || c.ValueMatches != nil || c.ValueInSet != nil
return c.Value != "" ||
c.ValueMatches != nil ||
c.ValueMatchesInt != nil ||
c.ValueMatchesFloat != nil ||
c.ValueInSet != nil
}
func (c *PermanodeConstraint) blobMatches(s *search, br blob.Ref, bm camtypes.BlobMeta) (ok bool, err error) {
@ -1145,6 +1157,16 @@ func (c *PermanodeConstraint) permanodeMatchesAttrVal(s *search, val string) (bo
if c.ValueMatches != nil && !c.ValueMatches.stringMatches(val) {
return false, nil
}
if c.ValueMatchesInt != nil {
if i, err := strconv.ParseInt(val, 10, 64); err != nil || !c.ValueMatchesInt.intMatches(i) {
return false, nil
}
}
if c.ValueMatchesFloat != nil {
if f, err := strconv.ParseFloat(val, 64); err != nil || !c.ValueMatchesFloat.floatMatches(f) {
return false, nil
}
}
if subc := c.ValueInSet; subc != nil {
br, ok := blob.Parse(val) // TODO: use corpus's parse, or keep this as blob.Ref in corpus attr
if !ok {

View File

@ -476,6 +476,64 @@ func TestQueryPermanodeAttrValueInSet(t *testing.T) {
})
}
// Tests PermanodeConstraint.ValueMatchesInt.
func TestQueryPermanodeValueMatchesInt(t *testing.T) {
testQuery(t, func(qt *queryTest) {
id := qt.id
p1 := id.NewPlannedPermanode("1")
p2 := id.NewPlannedPermanode("2")
p3 := id.NewPlannedPermanode("3")
p4 := id.NewPlannedPermanode("4")
p5 := id.NewPlannedPermanode("5")
id.SetAttribute(p1, "x", "-5")
id.SetAttribute(p2, "x", "0")
id.SetAttribute(p3, "x", "2")
id.SetAttribute(p4, "x", "10.0")
id.SetAttribute(p5, "x", "abc")
sq := &SearchQuery{
Constraint: &Constraint{
Permanode: &PermanodeConstraint{
Attr: "x",
ValueMatchesInt: &IntConstraint{
Min: -2,
},
},
},
}
qt.wantRes(sq, p2, p3)
})
}
// Tests PermanodeConstraint.ValueMatchesFloat.
func TestQueryPermanodeValueMatchesFloat(t *testing.T) {
testQuery(t, func(qt *queryTest) {
id := qt.id
p1 := id.NewPlannedPermanode("1")
p2 := id.NewPlannedPermanode("2")
p3 := id.NewPlannedPermanode("3")
p4 := id.NewPlannedPermanode("4")
id.SetAttribute(p1, "x", "2.5")
id.SetAttribute(p2, "x", "5.7")
id.SetAttribute(p3, "x", "10")
id.SetAttribute(p4, "x", "abc")
sq := &SearchQuery{
Constraint: &Constraint{
Permanode: &PermanodeConstraint{
Attr: "x",
ValueMatchesFloat: &FloatConstraint{
Max: 6.0,
},
},
},
}
qt.wantRes(sq, p1, p2)
})
}
// find permanodes matching a certain file query
func TestQueryFileConstraint(t *testing.T) {
testQuery(t, func(qt *queryTest) {