[#46] Make SELECT attribute optional

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgenii Stratonikov 2020-10-14 18:25:21 +03:00 committed by Alex Vanin
parent 719075ca97
commit d7c53debb5
4 changed files with 55 additions and 14 deletions

View file

@ -15,7 +15,7 @@ CbtStmt ::= 'CBF', Number1 (* container backup factor *)
SelectStmt ::= SelectStmt ::=
'SELECT', Number1, (* number of nodes to select without container backup factor *) 'SELECT', Number1, (* number of nodes to select without container backup factor *)
'IN', Clause?, Ident, (* bucket name *) ('IN', Clause?, Ident)?, (* bucket name *)
FROM, (Ident | '*'), (* filter reference or whole netmap *) FROM, (Ident | '*'), (* filter reference or whole netmap *)
('AS', Ident)? (* optional selector name *) ('AS', Ident)? (* optional selector name *)
; ;

View file

@ -28,8 +28,7 @@ type replicaStmt struct {
type selectorStmt struct { type selectorStmt struct {
Count uint32 `"SELECT" @Int` Count uint32 `"SELECT" @Int`
Clause string `"IN" @("SAME" | "DISTINCT")?` Bucket []string `("IN" @(("SAME" | "DISTINCT")? Ident))?`
Bucket string `@Ident`
Filter string `"FROM" @(Ident | "*")` Filter string `"FROM" @(Ident | "*")`
Name string `("AS" @Ident)?` Name string `("AS" @Ident)?`
} }

View file

@ -52,18 +52,16 @@ func Parse(s string) (*netmap.PlacementPolicy, error) {
return nil, fmt.Errorf("%w: '%s'", ErrUnknownFilter, qs.Filter) return nil, fmt.Errorf("%w: '%s'", ErrUnknownFilter, qs.Filter)
} }
s := new(netmap.Selector) s := new(netmap.Selector)
switch qs.Clause { switch len(qs.Bucket) {
case "SAME": case 1: // only bucket
s.SetClause(netmap.Same) s.SetAttribute(qs.Bucket[0])
case "DISTINCT": case 2: // clause + bucket
s.SetClause(netmap.Distinct) s.SetClause(clauseFromString(qs.Bucket[0]))
default: s.SetAttribute(qs.Bucket[1])
s.SetClause(netmap.UnspecifiedClause)
} }
s.SetName(qs.Name) s.SetName(qs.Name)
seenSelectors[qs.Name] = true seenSelectors[qs.Name] = true
s.SetFilter(qs.Filter) s.SetFilter(qs.Filter)
s.SetAttribute(qs.Bucket)
if qs.Count == 0 { if qs.Count == 0 {
return nil, fmt.Errorf("%w: SELECT", ErrInvalidNumber) return nil, fmt.Errorf("%w: SELECT", ErrInvalidNumber)
} }
@ -95,6 +93,17 @@ func Parse(s string) (*netmap.PlacementPolicy, error) {
return p, nil return p, nil
} }
func clauseFromString(s string) netmap.Clause {
switch strings.ToUpper(s) {
case "SAME":
return netmap.Same
case "DISTINCT":
return netmap.Distinct
default:
return netmap.UnspecifiedClause
}
}
func filterFromOrChain(expr *orChain, seen map[string]bool) (*netmap.Filter, error) { func filterFromOrChain(expr *orChain, seen map[string]bool) (*netmap.Filter, error) {
var fs []*netmap.Filter var fs []*netmap.Filter
for _, ac := range expr.Clauses { for _, ac := range expr.Clauses {

View file

@ -48,6 +48,39 @@ SELECT 1 IN City FROM * AS SPB`
require.Equal(t, expected, r) require.Equal(t, expected, r)
} }
// https://github.com/nspcc-dev/neofs-node/issues/46
func TestFromSelectNoAttribute(t *testing.T) {
t.Run("Simple", func(t *testing.T) {
q := `REP 2
SELECT 6 FROM *`
expected := new(netmap.PlacementPolicy)
expected.SetFilters([]*netmap.Filter{})
expected.SetSelectors([]*netmap.Selector{newSelector(6, netmap.UnspecifiedClause, "", "*", "")})
expected.SetReplicas([]*netmap.Replica{newReplica("", 2)})
r, err := Parse(q)
require.NoError(t, err)
require.Equal(t, expected, r)
})
t.Run("with filter", func(t *testing.T) {
q := `REP 2
SELECT 6 FROM F
FILTER StorageType EQ SSD AS F`
expected := new(netmap.PlacementPolicy)
expected.SetFilters([]*netmap.Filter{newFilter("F", "StorageType", "SSD", netmap.EQ)})
expected.SetSelectors([]*netmap.Selector{newSelector(6, netmap.UnspecifiedClause, "", "F", "")})
expected.SetReplicas([]*netmap.Replica{newReplica("", 2)})
r, err := Parse(q)
require.NoError(t, err)
require.Equal(t, expected, r)
})
}
func TestFromSelectClause(t *testing.T) { func TestFromSelectClause(t *testing.T) {
q := `REP 4 q := `REP 4
SELECT 3 IN Country FROM * SELECT 3 IN Country FROM *