feat: quantification

This commit is contained in:
Alan Shaw
2024-08-21 08:44:17 +02:00
parent e30a776aaa
commit 6106054ed6
3 changed files with 103 additions and 3 deletions

View File

@@ -15,7 +15,7 @@ func Match(policy Policy, node ipld.Node) bool {
for _, stmt := range policy {
ok := matchStatement(stmt, node)
if !ok {
return ok
return false
}
}
return true
@@ -103,7 +103,33 @@ func matchStatement(statement Statement, node ipld.Node) bool {
return s.Value().Match(v)
}
case Kind_All:
if s, ok := statement.(QuantifierStatement); ok {
_, many, err := selector.Select(s.Selector(), node)
if err != nil || many == nil {
return false
}
for _, n := range many {
ok := Match(s.Value(), n)
if !ok {
return false
}
}
return true
}
case Kind_Any:
if s, ok := statement.(QuantifierStatement); ok {
_, many, err := selector.Select(s.Selector(), node)
if err != nil || many == nil {
return false
}
for _, n := range many {
ok := Match(s.Value(), n)
if ok {
return true
}
}
return false
}
}
panic(fmt.Errorf("unimplemented statement kind: %s", statement.Kind()))
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/gobwas/glob"
"github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
"github.com/ipld/go-ipld-prime/node/basicnode"
"github.com/storacha-network/go-ucanto/core/policy/literal"
@@ -331,4 +332,77 @@ func TestMatch(t *testing.T) {
}(s)
}
})
buildValueNode := func(v int64) ipld.Node {
np := basicnode.Prototype.Map
nb := np.NewBuilder()
ma, _ := nb.BeginMap(1)
ma.AssembleKey().AssignString("value")
ma.AssembleValue().AssignInt(v)
ma.Finish()
return nb.Build()
}
t.Run("quantification all", func(t *testing.T) {
np := basicnode.Prototype.List
nb := np.NewBuilder()
la, _ := nb.BeginList(5)
la.AssembleValue().AssignNode(buildValueNode(5))
la.AssembleValue().AssignNode(buildValueNode(10))
la.AssembleValue().AssignNode(buildValueNode(20))
la.AssembleValue().AssignNode(buildValueNode(50))
la.AssembleValue().AssignNode(buildValueNode(100))
la.Finish()
nd := nb.Build()
pol := Policy{
All(
selector.MustParse(".[]"),
GreaterThan(selector.MustParse(".value"), literal.Int(2)),
),
}
ok := Match(pol, nd)
require.True(t, ok)
pol = Policy{
All(
selector.MustParse(".[]"),
GreaterThan(selector.MustParse(".value"), literal.Int(20)),
),
}
ok = Match(pol, nd)
require.False(t, ok)
})
t.Run("quantification any", func(t *testing.T) {
np := basicnode.Prototype.List
nb := np.NewBuilder()
la, _ := nb.BeginList(5)
la.AssembleValue().AssignNode(buildValueNode(5))
la.AssembleValue().AssignNode(buildValueNode(10))
la.AssembleValue().AssignNode(buildValueNode(20))
la.AssembleValue().AssignNode(buildValueNode(50))
la.AssembleValue().AssignNode(buildValueNode(100))
la.Finish()
nd := nb.Build()
pol := Policy{
Any(
selector.MustParse(".[]"),
GreaterThan(selector.MustParse(".value"), literal.Int(10)),
LessThan(selector.MustParse(".value"), literal.Int(50)),
),
}
ok := Match(pol, nd)
require.True(t, ok)
pol = Policy{
Any(
selector.MustParse(".[]"),
GreaterThan(selector.MustParse(".value"), literal.Int(100)),
),
}
ok = Match(pol, nd)
require.False(t, ok)
})
}

View File

@@ -196,10 +196,10 @@ func (n quantifier) Value() Policy {
return n.policy
}
func All(selector selector.Selector, policy Policy) QuantifierStatement {
func All(selector selector.Selector, policy ...Statement) QuantifierStatement {
return quantifier{Kind_All, selector, policy}
}
func Any(selector selector.Selector, policy Policy) QuantifierStatement {
func Any(selector selector.Selector, policy ...Statement) QuantifierStatement {
return quantifier{Kind_Any, selector, policy}
}