forked from TrueCloudLab/frostfs-node
[#46] Make SELECT attribute optional
Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
719075ca97
commit
d7c53debb5
4 changed files with 55 additions and 14 deletions
|
@ -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 *)
|
||||||
;
|
;
|
||||||
|
|
|
@ -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)?`
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 *
|
||||||
|
|
Loading…
Reference in a new issue