mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
update parser to handle row keys on SetRowAttrs()
This commit is contained in:
parent
ada9857f35
commit
dfd529b2f5
7 changed files with 1181 additions and 1015 deletions
|
|
@ -1256,7 +1256,7 @@ func (e *executor) executeBulkSetRowAttrs(ctx context.Context, index string, cal
|
|||
|
||||
rowID, ok, err := c.UintArg("_" + rowLabel)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading SetRowAttrs() row: %v", rowLabel)
|
||||
return nil, errors.Wrap(err, "reading SetRowAttrs() row")
|
||||
} else if !ok {
|
||||
return nil, fmt.Errorf("SetRowAttrs row field '%v' required", rowLabel)
|
||||
}
|
||||
|
|
@ -1550,6 +1550,10 @@ func (e *executor) translateCall(index string, idx *Index, c *pql.Call) error {
|
|||
colKey = "_" + columnLabel
|
||||
fieldName, _ = c.FieldArg()
|
||||
rowKey = fieldName
|
||||
} else if c.Name == "SetRowAttrs" {
|
||||
// Positional args in new PQL syntax require special handling here.
|
||||
rowKey = "_" + rowLabel
|
||||
fieldName = callArgString(c, "_field")
|
||||
} else {
|
||||
colKey = "col"
|
||||
fieldName = callArgString(c, "field")
|
||||
|
|
|
|||
|
|
@ -471,29 +471,59 @@ func TestExecutor_Execute_SetRowAttrs(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
} else if _, err := index.CreateFieldIfNotExists("xxx", pilosa.OptFieldTypeDefault()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Set two attrs on f/10.
|
||||
// Also set attrs on other bitmaps and fields to test isolation.
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `SetRowAttrs(f, 10, foo="bar")`}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `SetRowAttrs(f, 200, YYY=1)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `SetRowAttrs(xxx, 10, YYY=1)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `SetRowAttrs(f, 10, baz=123, bat=true)`}); err != nil {
|
||||
} else if _, err := index.CreateFieldIfNotExists("kf", pilosa.OptFieldTypeDefault(), pilosa.OptFieldKeys()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f := hldr.Field("i", "f")
|
||||
if m, err := f.RowAttrStore().Attrs(10); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(m, map[string]interface{}{"foo": "bar", "baz": int64(123), "bat": true}) {
|
||||
t.Fatalf("unexpected bitmap attr: %#v", m)
|
||||
}
|
||||
t.Run("rowID", func(t *testing.T) {
|
||||
// Set two attrs on f/10.
|
||||
// Also set attrs on other bitmaps and fields to test isolation.
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `SetRowAttrs(f, 10, foo="bar")`}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `SetRowAttrs(f, 200, YYY=1)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `SetRowAttrs(xxx, 10, YYY=1)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `SetRowAttrs(f, 10, baz=123, bat=true)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f := hldr.Field("i", "f")
|
||||
if m, err := f.RowAttrStore().Attrs(10); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(m, map[string]interface{}{"foo": "bar", "baz": int64(123), "bat": true}) {
|
||||
t.Fatalf("unexpected bitmap attr: %#v", m)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("rowKey", func(t *testing.T) {
|
||||
// Set two attrs on f/10.
|
||||
// Also set attrs on other bitmaps and fields to test isolation.
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `SetRowAttrs(kf, "row10", foo="bar")`}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `SetRowAttrs(kf, "row200", YYY=1)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `SetRowAttrs(kf, "row10", baz=123, bat=true)`}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `Row(kf="row10")`})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
spew.Dump(result)
|
||||
|
||||
if result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `Row(kf="row10")`}); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if attrs := result.Results[0].(*pilosa.Row).Attrs; !reflect.DeepEqual(attrs, map[string]interface{}{"foo": "bar", "baz": int64(123), "bat": true}) {
|
||||
t.Fatalf("unexpected attrs: %+v", attrs)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure a TopN() query can be executed.
|
||||
|
|
|
|||
12
index.go
12
index.go
|
|
@ -292,7 +292,7 @@ func (i *Index) CreateField(name string, opts ...FieldOption) (*Field, error) {
|
|||
}
|
||||
|
||||
// CreateFieldIfNotExists creates a field with the given options if it doesn't exist.
|
||||
func (i *Index) CreateFieldIfNotExists(name string, opts FieldOption) (*Field, error) {
|
||||
func (i *Index) CreateFieldIfNotExists(name string, opts ...FieldOption) (*Field, error) {
|
||||
i.mu.Lock()
|
||||
defer i.mu.Unlock()
|
||||
|
||||
|
|
@ -301,11 +301,13 @@ func (i *Index) CreateFieldIfNotExists(name string, opts FieldOption) (*Field, e
|
|||
return f, nil
|
||||
}
|
||||
|
||||
// Apply functional option.
|
||||
// Apply functional options.
|
||||
fo := FieldOptions{}
|
||||
err := opts(&fo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "applying option")
|
||||
for _, opt := range opts {
|
||||
err := opt(&fo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "applying option")
|
||||
}
|
||||
}
|
||||
|
||||
return i.createField(name, fo)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ type PQL Peg {
|
|||
|
||||
Calls <- sp (Call sp)* !.
|
||||
Call <- 'Set' {p.startCall("Set")} open col comma args (comma timestamp)? close {p.endCall()}
|
||||
/ 'SetRowAttrs' {p.startCall("SetRowAttrs")} open posfield comma uintrow comma args close {p.endCall()}
|
||||
/ 'SetRowAttrs' {p.startCall("SetRowAttrs")} open posfield comma row comma args close {p.endCall()}
|
||||
/ 'SetColumnAttrs' {p.startCall("SetColumnAttrs")} open col comma args close {p.endCall()}
|
||||
/ 'Clear' {p.startCall("Clear")} open col comma args close {p.endCall()}
|
||||
/ 'TopN' {p.startCall("TopN")} open posfield (comma allargs)? close {p.endCall()}
|
||||
|
|
@ -60,6 +60,10 @@ col <- ( <uint> {p.addPosNum("_col", buffer[begin:end])}
|
|||
/ '\'' <singlequotedstring> '\'' {p.addPosStr("_col", buffer[begin:end])}
|
||||
/ '"' <doublequotedstring> '"' {p.addPosStr("_col", buffer[begin:end])}
|
||||
)
|
||||
row <- ( <uint> {p.addPosNum("_row", buffer[begin:end])}
|
||||
/ '\'' <singlequotedstring> '\'' {p.addPosStr("_row", buffer[begin:end])}
|
||||
/ '"' <doublequotedstring> '"' {p.addPosStr("_row", buffer[begin:end])}
|
||||
)
|
||||
|
||||
open <- '(' sp
|
||||
close <- ')' sp
|
||||
|
|
|
|||
2040
pql/pql.peg.go
2040
pql/pql.peg.go
File diff suppressed because it is too large
Load diff
|
|
@ -160,6 +160,14 @@ func TestPEGWorking(t *testing.T) {
|
|||
name: "SetRowAttrs2args",
|
||||
input: "SetRowAttrs(blah, 9, a=47, b=bval)",
|
||||
ncalls: 1},
|
||||
{
|
||||
name: "SetRowAttrsWithRowKeySingleQuote",
|
||||
input: "SetRowAttrs(blah, 'rowKey', a=47)",
|
||||
ncalls: 1},
|
||||
{
|
||||
name: "SetRowAttrsWithRowKeyDoubleQuote",
|
||||
input: `SetRowAttrs(blah, "rowKey", a=47)`,
|
||||
ncalls: 1},
|
||||
{
|
||||
name: "SetColumnAttrs",
|
||||
input: "SetColumnAttrs(9, a=47)",
|
||||
|
|
@ -168,6 +176,14 @@ func TestPEGWorking(t *testing.T) {
|
|||
name: "SetColumnAttrs2args",
|
||||
input: "SetColumnAttrs(9, a=47, b=bval)",
|
||||
ncalls: 1},
|
||||
{
|
||||
name: "SetColumnAttrsWithColKeySingleQuote",
|
||||
input: "SetColumnAttrs('colKey', a=47)",
|
||||
ncalls: 1},
|
||||
{
|
||||
name: "SetColumnAttrsWithColKeyDoubleQuote",
|
||||
input: `SetColumnAttrs("colKey", a=47)`,
|
||||
ncalls: 1},
|
||||
{
|
||||
name: "Clear",
|
||||
input: "Clear(1, a=53)",
|
||||
|
|
@ -330,6 +346,28 @@ func TestPQLDeepEquality(t *testing.T) {
|
|||
"_row": int64(9),
|
||||
},
|
||||
}},
|
||||
{
|
||||
name: "SetRowAttrsWithRowKeySingleQuote",
|
||||
call: "SetRowAttrs(myfield, 'rowKey', z=4)",
|
||||
exp: &Call{
|
||||
Name: "SetRowAttrs",
|
||||
Args: map[string]interface{}{
|
||||
"z": int64(4),
|
||||
"_field": "myfield",
|
||||
"_row": "rowKey",
|
||||
},
|
||||
}},
|
||||
{
|
||||
name: "SetRowAttrsWithRowKeyDoubleQuote",
|
||||
call: `SetRowAttrs(myfield, "rowKey", z=4)`,
|
||||
exp: &Call{
|
||||
Name: "SetRowAttrs",
|
||||
Args: map[string]interface{}{
|
||||
"z": int64(4),
|
||||
"_field": "myfield",
|
||||
"_row": "rowKey",
|
||||
},
|
||||
}},
|
||||
{
|
||||
name: "SetColumnAttrs",
|
||||
call: "SetColumnAttrs(9, z=4)",
|
||||
|
|
@ -340,6 +378,26 @@ func TestPQLDeepEquality(t *testing.T) {
|
|||
"_col": int64(9),
|
||||
},
|
||||
}},
|
||||
{
|
||||
name: "SetColumnAttrsWithColKeySingleQuote",
|
||||
call: "SetColumnAttrs('colKey', z=4)",
|
||||
exp: &Call{
|
||||
Name: "SetColumnAttrs",
|
||||
Args: map[string]interface{}{
|
||||
"z": int64(4),
|
||||
"_col": "colKey",
|
||||
},
|
||||
}},
|
||||
{
|
||||
name: "SetColumnAttrsWithColKeyDoubleQuote",
|
||||
call: `SetColumnAttrs("colKey", z=4)`,
|
||||
exp: &Call{
|
||||
Name: "SetColumnAttrs",
|
||||
Args: map[string]interface{}{
|
||||
"z": int64(4),
|
||||
"_col": "colKey",
|
||||
},
|
||||
}},
|
||||
{
|
||||
name: "Clear",
|
||||
call: "Clear(1, a=7)",
|
||||
|
|
|
|||
|
|
@ -83,8 +83,8 @@ func (i *Index) CreateField(name string, opts ...pilosa.FieldOption) (*Field, er
|
|||
}
|
||||
|
||||
// CreateFieldIfNotExists creates a field with the given options if it doesn't exist.
|
||||
func (i *Index) CreateFieldIfNotExists(name string, opts pilosa.FieldOption) (*Field, error) {
|
||||
f, err := i.Index.CreateFieldIfNotExists(name, opts)
|
||||
func (i *Index) CreateFieldIfNotExists(name string, opts ...pilosa.FieldOption) (*Field, error) {
|
||||
f, err := i.Index.CreateFieldIfNotExists(name, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue