diff --git a/executor.go b/executor.go index 8b07f9c9c..3529995f5 100644 --- a/executor.go +++ b/executor.go @@ -722,29 +722,6 @@ func (e *executor) executeMinShard(ctx context.Context, index string, c *pql.Cal }, nil } -// executeMinRowShard returns the minimum row ID for a shard. -func (e *executor) executeMinRowShard(ctx context.Context, index string, c *pql.Call, shard uint64) (Pair, error) { - fieldName, _ := c.Args["field"].(string) - field := e.Holder.Field(index, fieldName) - if field == nil { - return Pair{}, nil - } - - fragment := e.Holder.fragment(index, fieldName, viewStandard, shard) - if fragment == nil { - return Pair{}, nil - } - - count := uint64(1) - if !fragment.hasRowID { - count = 0 - } - return Pair{ - ID: fragment.minRowID, - Count: count, - }, nil -} - // executeMaxShard calculates the max for bsiGroups on a shard. func (e *executor) executeMaxShard(ctx context.Context, index string, c *pql.Call, shard uint64) (ValCount, error) { var filter *Row @@ -783,6 +760,29 @@ func (e *executor) executeMaxShard(ctx context.Context, index string, c *pql.Cal }, nil } +// executeMinRowShard returns the minimum row ID for a shard. +func (e *executor) executeMinRowShard(ctx context.Context, index string, c *pql.Call, shard uint64) (Pair, error) { + fieldName, _ := c.Args["field"].(string) + field := e.Holder.Field(index, fieldName) + if field == nil { + return Pair{}, nil + } + + fragment := e.Holder.fragment(index, fieldName, viewStandard, shard) + if fragment == nil { + return Pair{}, nil + } + + count := uint64(1) + if !fragment.hasRowID { + count = 0 + } + return Pair{ + ID: fragment.minRowID, + Count: count, + }, nil +} + // executeMaxRowShard returns the minimum row ID for a shard. func (e *executor) executeMaxRowShard(ctx context.Context, index string, c *pql.Call, shard uint64) (Pair, error) { fieldName, _ := c.Args["field"].(string) diff --git a/executor_test.go b/executor_test.go index 3565c40fd..be10b80bb 100644 --- a/executor_test.go +++ b/executor_test.go @@ -1415,6 +1415,103 @@ func TestExecutor_Execute_MinMax(t *testing.T) { }) } +// Ensure MinRow() and MaxRow() queries can be executed. +func TestExecutor_Execute_MinMaxRow(t *testing.T) { + t.Run("RowID", func(t *testing.T) { + c := test.MustRunCluster(t, 1) + defer c.Close() + hldr := test.Holder{Holder: c[0].Server.Holder()} + + idx, err := hldr.CreateIndex("i", pilosa.IndexOptions{}) + if err != nil { + t.Fatal(err) + } + + if _, err := idx.CreateField("f", pilosa.OptFieldTypeDefault()); err != nil { + t.Fatal(err) + } + + if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: ` + Set(0, f=7000) + Set(3, f=50) + Set(` + strconv.Itoa(ShardWidth+1) + `, f=10000) + Set(1000, f=1) + Set(` + strconv.Itoa(ShardWidth+2) + `, f=5000) + `}); err != nil { + t.Fatal(err) + } + + t.Run("MinRow", func(t *testing.T) { + result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: "MinRow(field=f)"}) + if err != nil { + t.Fatal(err) + } + target := pilosa.Pair{ID: 1, Count: 1} + if !reflect.DeepEqual(target, result.Results[0]) { + t.Fatalf("unexpected result %v != %v", target, result.Results[0]) + } + }) + + t.Run("MaxRow", func(t *testing.T) { + result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: "MaxRow(field=f)"}) + if err != nil { + t.Fatal(err) + } + target := pilosa.Pair{ID: 10000, Count: 1} + if !reflect.DeepEqual(target, result.Results[0]) { + t.Fatalf("unexpected result %v != %v", target, result.Results[0]) + } + }) + }) + + t.Run("RowKey", func(t *testing.T) { + c := test.MustRunCluster(t, 1) + defer c.Close() + hldr := test.Holder{Holder: c[0].Server.Holder()} + + idx, err := hldr.CreateIndex("i", pilosa.IndexOptions{}) + if err != nil { + t.Fatal(err) + } + + if _, err := idx.CreateField("f", pilosa.OptFieldKeys()); err != nil { + t.Fatal(err) + } + + if _, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: ` + Set(0, f="seven-thousand") + Set(3, f="fifty") + Set(` + strconv.Itoa(ShardWidth+1) + `, f="ten-thousand") + Set(1000, f="one") + Set(` + strconv.Itoa(ShardWidth+2) + `, f="five-thousand") + `}); err != nil { + t.Fatal(err) + } + + t.Run("MinRow", func(t *testing.T) { + result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: "MinRow(field=f)"}) + if err != nil { + t.Fatal(err) + } + target := pilosa.Pair{Key: "seven-thousand", ID: 1, Count: 1} + if !reflect.DeepEqual(target, result.Results[0]) { + t.Fatalf("unexpected result %v != %v", target, result.Results[0]) + } + }) + + t.Run("MaxRow", func(t *testing.T) { + result, err := c[0].API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: "MaxRow(field=f)"}) + if err != nil { + t.Fatal(err) + } + target := pilosa.Pair{Key: "five-thousand", ID: 5, Count: 1} + if !reflect.DeepEqual(target, result.Results[0]) { + t.Fatalf("unexpected result %v != %v", target, result.Results[0]) + } + }) + }) +} + // Ensure a Sum() query can be executed. func TestExecutor_Execute_Sum(t *testing.T) { t.Run("ColumnID", func(t *testing.T) {