mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
495 lines
15 KiB
Go
495 lines
15 KiB
Go
// Copyright 2021 Molecula Corp. All rights reserved.
|
|
// package ctl contains all pilosa subcommands other than 'server'. These are
|
|
// generally administration, testing, and debugging tools.
|
|
|
|
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/molecula/featurebase/v3/pb"
|
|
)
|
|
|
|
// QueryResponse types.
|
|
const (
|
|
QueryResultTypeNil uint32 = iota
|
|
QueryResultTypeRow
|
|
QueryResultTypePairs
|
|
QueryResultTypePairsField
|
|
QueryResultTypeValCount
|
|
QueryResultTypeUint64
|
|
QueryResultTypeBool
|
|
QueryResultTypeRowIDs // this is not used by the client
|
|
QueryResultTypeGroupCounts
|
|
QueryResultTypeRowIdentifiers
|
|
QueryResultTypePair
|
|
QueryResultTypePairField
|
|
QueryResultTypeSignedRow
|
|
)
|
|
|
|
// QueryResponse represents the response from a Pilosa query.
|
|
type QueryResponse struct {
|
|
ResultList []QueryResult `json:"results,omitempty"`
|
|
ErrorMessage string `json:"error-message,omitempty"`
|
|
Success bool `json:"success,omitempty"`
|
|
}
|
|
|
|
func newQueryResponseFromInternal(response *pb.QueryResponse) (*QueryResponse, error) {
|
|
if response.Err != "" {
|
|
return &QueryResponse{
|
|
ErrorMessage: response.Err,
|
|
Success: false,
|
|
}, nil
|
|
}
|
|
results := make([]QueryResult, 0, len(response.Results))
|
|
for _, r := range response.Results {
|
|
result, err := newQueryResultFromInternal(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
results = append(results, result)
|
|
}
|
|
|
|
return &QueryResponse{
|
|
ResultList: results,
|
|
Success: true,
|
|
}, nil
|
|
}
|
|
|
|
// Results returns all results in the response.
|
|
func (qr *QueryResponse) Results() []QueryResult {
|
|
return qr.ResultList
|
|
}
|
|
|
|
// Result returns the first result or nil.
|
|
func (qr *QueryResponse) Result() QueryResult {
|
|
if len(qr.ResultList) == 0 {
|
|
return nil
|
|
}
|
|
return qr.ResultList[0]
|
|
}
|
|
|
|
// QueryResult represents one of the results in the response.
|
|
type QueryResult interface {
|
|
Type() uint32
|
|
Row() RowResult
|
|
CountItems() []CountResultItem
|
|
CountItem() CountResultItem
|
|
Count() int64
|
|
Value() int64
|
|
Changed() bool
|
|
GroupCounts() []GroupCount
|
|
RowIdentifiers() RowIdentifiersResult
|
|
}
|
|
|
|
func newQueryResultFromInternal(result *pb.QueryResult) (QueryResult, error) {
|
|
switch result.Type {
|
|
case QueryResultTypeNil:
|
|
return NilResult{}, nil
|
|
case QueryResultTypeRow:
|
|
return newRowResultFromInternal(result.Row)
|
|
case QueryResultTypePairs:
|
|
return countItemsFromInternal(result.Pairs), nil
|
|
case QueryResultTypePairsField:
|
|
return countItemsFromInternal(result.PairsField.Pairs), nil
|
|
case QueryResultTypeValCount:
|
|
return &ValCountResult{
|
|
Val: result.ValCount.Val,
|
|
Cnt: result.ValCount.Count,
|
|
}, nil
|
|
case QueryResultTypeUint64:
|
|
return IntResult(result.N), nil
|
|
case QueryResultTypeBool:
|
|
return BoolResult(result.Changed), nil
|
|
case QueryResultTypeRowIdentifiers:
|
|
return &RowIdentifiersResult{
|
|
IDs: result.RowIdentifiers.Rows,
|
|
Keys: result.RowIdentifiers.Keys,
|
|
}, nil
|
|
case QueryResultTypeGroupCounts:
|
|
return groupCountsFromInternal(result.GroupCounts), nil
|
|
case QueryResultTypePair:
|
|
return CountItem{CountResultItem: countItemFromInternal(result.Pairs[0])}, nil
|
|
case QueryResultTypePairField:
|
|
return CountItem{CountResultItem: countItemFromInternal(result.PairField.Pair)}, nil
|
|
}
|
|
|
|
return nil, ErrUnknownType
|
|
}
|
|
|
|
// CountResultItem represents a result from TopN call.
|
|
type CountResultItem struct {
|
|
ID uint64 `json:"id"`
|
|
Key string `json:"key,omitempty"`
|
|
Count uint64 `json:"count"`
|
|
}
|
|
|
|
func (c *CountResultItem) String() string {
|
|
if c.Key != "" {
|
|
return fmt.Sprintf("%s:%d", c.Key, c.Count)
|
|
}
|
|
return fmt.Sprintf("%d:%d", c.ID, c.Count)
|
|
}
|
|
|
|
type CountItem struct {
|
|
CountResultItem
|
|
}
|
|
|
|
// Type is the type of this result.
|
|
func (CountItem) Type() uint32 { return QueryResultTypePairField }
|
|
|
|
// Row returns a RowResult.
|
|
func (CountItem) Row() RowResult { return RowResult{} }
|
|
|
|
// CountItems returns a CountResultItem slice.
|
|
func (t CountItem) CountItems() []CountResultItem { return []CountResultItem{t.CountResultItem} }
|
|
|
|
// CountItem returns a CountResultItem
|
|
func (t CountItem) CountItem() CountResultItem { return t.CountResultItem }
|
|
|
|
// Count returns the result of a Count call.
|
|
func (CountItem) Count() int64 { return 0 }
|
|
|
|
// Value returns the result of a Min, Max or Sum call.
|
|
func (CountItem) Value() int64 { return 0 }
|
|
|
|
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
|
|
func (CountItem) Changed() bool { return false }
|
|
|
|
// GroupCounts returns the result of a GroupBy call.
|
|
func (CountItem) GroupCounts() []GroupCount { return nil }
|
|
|
|
// RowIdentifiers returns the result of a Rows call.
|
|
func (CountItem) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
|
|
|
|
func countItemFromInternal(item *pb.Pair) CountResultItem {
|
|
return CountResultItem{ID: item.ID, Key: item.Key, Count: item.Count}
|
|
}
|
|
|
|
func countItemsFromInternal(items []*pb.Pair) TopNResult {
|
|
result := make([]CountResultItem, 0, len(items))
|
|
for _, v := range items {
|
|
result = append(result, countItemFromInternal(v))
|
|
}
|
|
return TopNResult(result)
|
|
}
|
|
|
|
// TopNResult is returned from TopN call.
|
|
type TopNResult []CountResultItem
|
|
|
|
// Type is the type of this result.
|
|
func (TopNResult) Type() uint32 { return QueryResultTypePairsField }
|
|
|
|
// Row returns a RowResult.
|
|
func (TopNResult) Row() RowResult { return RowResult{} }
|
|
|
|
// CountItems returns a CountResultItem slice.
|
|
func (t TopNResult) CountItems() []CountResultItem { return t }
|
|
|
|
// CountItem returns a CountResultItem
|
|
func (t TopNResult) CountItem() CountResultItem {
|
|
if len(t) >= 1 {
|
|
return t[0]
|
|
}
|
|
return CountResultItem{}
|
|
}
|
|
|
|
// Count returns the result of a Count call.
|
|
func (TopNResult) Count() int64 { return 0 }
|
|
|
|
// Value returns the result of a Min, Max or Sum call.
|
|
func (TopNResult) Value() int64 { return 0 }
|
|
|
|
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
|
|
func (TopNResult) Changed() bool { return false }
|
|
|
|
// GroupCounts returns the result of a GroupBy call.
|
|
func (TopNResult) GroupCounts() []GroupCount { return nil }
|
|
|
|
// RowIdentifiers returns the result of a Rows call.
|
|
func (TopNResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
|
|
|
|
// RowResult represents a result from Row, Union, Intersect, Difference and Range PQL calls.
|
|
type RowResult struct {
|
|
Columns []uint64 `json:"columns"`
|
|
Keys []string `json:"keys"`
|
|
}
|
|
|
|
func newRowResultFromInternal(row *pb.Row) (*RowResult, error) {
|
|
return &RowResult{
|
|
Columns: row.Columns,
|
|
Keys: row.Keys,
|
|
}, nil
|
|
}
|
|
|
|
// Type is the type of this result.
|
|
func (RowResult) Type() uint32 { return QueryResultTypeRow }
|
|
|
|
// Row returns a RowResult.
|
|
func (b RowResult) Row() RowResult { return b }
|
|
|
|
// CountItems returns a CountResultItem slice.
|
|
func (RowResult) CountItems() []CountResultItem { return nil }
|
|
|
|
// CountItem returns a CountResultItem
|
|
func (RowResult) CountItem() CountResultItem { return CountResultItem{} }
|
|
|
|
// Count returns the result of a Count call.
|
|
func (RowResult) Count() int64 { return 0 }
|
|
|
|
// Value returns the result of a Min, Max or Sum call.
|
|
func (RowResult) Value() int64 { return 0 }
|
|
|
|
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
|
|
func (RowResult) Changed() bool { return false }
|
|
|
|
// GroupCounts returns the result of a GroupBy call.
|
|
func (RowResult) GroupCounts() []GroupCount { return nil }
|
|
|
|
// RowIdentifiers returns the result of a Rows call.
|
|
func (RowResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
|
|
|
|
// MarshalJSON serializes this row result.
|
|
func (b RowResult) MarshalJSON() ([]byte, error) {
|
|
columns := b.Columns
|
|
if columns == nil {
|
|
columns = []uint64{}
|
|
}
|
|
keys := b.Keys
|
|
if keys == nil {
|
|
keys = []string{}
|
|
}
|
|
return json.Marshal(struct {
|
|
Columns []uint64 `json:"columns"`
|
|
Keys []string `json:"keys"`
|
|
}{
|
|
Columns: columns,
|
|
Keys: keys,
|
|
})
|
|
}
|
|
|
|
// ValCountResult is returned from Min, Max and Sum calls.
|
|
type ValCountResult struct {
|
|
Val int64 `json:"val"`
|
|
Cnt int64 `json:"count"`
|
|
}
|
|
|
|
// Type is the type of this result.
|
|
func (ValCountResult) Type() uint32 { return QueryResultTypeValCount }
|
|
|
|
// Row returns a RowResult.
|
|
func (ValCountResult) Row() RowResult { return RowResult{} }
|
|
|
|
// CountItems returns a CountResultItem slice.
|
|
func (ValCountResult) CountItems() []CountResultItem { return nil }
|
|
|
|
// CountItem returns a CountResultItem
|
|
func (ValCountResult) CountItem() CountResultItem { return CountResultItem{} }
|
|
|
|
// Count returns the result of a Count call.
|
|
func (c ValCountResult) Count() int64 { return c.Cnt }
|
|
|
|
// Value returns the result of a Min, Max or Sum call.
|
|
func (c ValCountResult) Value() int64 { return c.Val }
|
|
|
|
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
|
|
func (ValCountResult) Changed() bool { return false }
|
|
|
|
// GroupCounts returns the result of a GroupBy call.
|
|
func (ValCountResult) GroupCounts() []GroupCount { return nil }
|
|
|
|
// RowIdentifiers returns the result of a Rows call.
|
|
func (ValCountResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
|
|
|
|
// IntResult is returned from Count call.
|
|
type IntResult int64
|
|
|
|
// Type is the type of this result.
|
|
func (IntResult) Type() uint32 { return QueryResultTypeUint64 }
|
|
|
|
// Row returns a RowResult.
|
|
func (IntResult) Row() RowResult { return RowResult{} }
|
|
|
|
// CountItems returns a CountResultItem slice.
|
|
func (IntResult) CountItems() []CountResultItem { return nil }
|
|
|
|
// CountItem returns a CountResultItem
|
|
func (IntResult) CountItem() CountResultItem { return CountResultItem{} }
|
|
|
|
// Count returns the result of a Count call.
|
|
func (i IntResult) Count() int64 { return int64(i) }
|
|
|
|
// Value returns the result of a Min, Max or Sum call.
|
|
func (IntResult) Value() int64 { return 0 }
|
|
|
|
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
|
|
func (IntResult) Changed() bool { return false }
|
|
|
|
// GroupCounts returns the result of a GroupBy call.
|
|
func (IntResult) GroupCounts() []GroupCount { return nil }
|
|
|
|
// RowIdentifiers returns the result of a Rows call.
|
|
func (IntResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
|
|
|
|
// BoolResult is returned from Set and Clear calls.
|
|
type BoolResult bool
|
|
|
|
// Type is the type of this result.
|
|
func (BoolResult) Type() uint32 { return QueryResultTypeBool }
|
|
|
|
// Row returns a RowResult.
|
|
func (BoolResult) Row() RowResult { return RowResult{} }
|
|
|
|
// CountItems returns a CountResultItem slice.
|
|
func (BoolResult) CountItems() []CountResultItem { return nil }
|
|
|
|
// CountItem returns a CountResultItem
|
|
func (BoolResult) CountItem() CountResultItem { return CountResultItem{} }
|
|
|
|
// Count returns the result of a Count call.
|
|
func (BoolResult) Count() int64 { return 0 }
|
|
|
|
// Value returns the result of a Min, Max or Sum call.
|
|
func (BoolResult) Value() int64 { return 0 }
|
|
|
|
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
|
|
func (b BoolResult) Changed() bool { return bool(b) }
|
|
|
|
// GroupCounts returns the result of a GroupBy call.
|
|
func (BoolResult) GroupCounts() []GroupCount { return nil }
|
|
|
|
// RowIdentifiers returns the result of a Rows call.
|
|
func (BoolResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
|
|
|
|
// NilResult is returned from calls which don't return a value.
|
|
type NilResult struct{}
|
|
|
|
// Type is the type of this result.
|
|
func (NilResult) Type() uint32 { return QueryResultTypeNil }
|
|
|
|
// Row returns a RowResult.
|
|
func (NilResult) Row() RowResult { return RowResult{} }
|
|
|
|
// CountItems returns a CountResultItem slice.
|
|
func (NilResult) CountItems() []CountResultItem { return nil }
|
|
|
|
// CountItem returns a CountResultItem
|
|
func (NilResult) CountItem() CountResultItem { return CountResultItem{} }
|
|
|
|
// Count returns the result of a Count call.
|
|
func (NilResult) Count() int64 { return 0 }
|
|
|
|
// Value returns the result of a Min, Max or Sum call.
|
|
func (NilResult) Value() int64 { return 0 }
|
|
|
|
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
|
|
func (NilResult) Changed() bool { return false }
|
|
|
|
// GroupCounts returns the result of a GroupBy call.
|
|
func (NilResult) GroupCounts() []GroupCount { return nil }
|
|
|
|
// RowIdentifiers returns the result of a Rows call.
|
|
func (NilResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
|
|
|
|
// FieldRow represents a Group in a GroupBy call result.
|
|
type FieldRow struct {
|
|
FieldName string `json:"field"`
|
|
RowID uint64 `json:"rowID"`
|
|
RowKey string `json:"rowKey"`
|
|
Value *int64 `json:"value,omitempty"`
|
|
}
|
|
|
|
// GroupCount contains groups and their count in a GroupBy call result.
|
|
type GroupCount struct {
|
|
Groups []FieldRow `json:"groups"`
|
|
Count int64 `json:"count"`
|
|
Agg int64 `json:"agg"`
|
|
}
|
|
|
|
// GroupCountResult is returned from GroupBy call.
|
|
type GroupCountResult []GroupCount
|
|
|
|
// Type is the type of this result.
|
|
func (GroupCountResult) Type() uint32 { return QueryResultTypeGroupCounts }
|
|
|
|
// Row returns a RowResult.
|
|
func (GroupCountResult) Row() RowResult { return RowResult{} }
|
|
|
|
// CountItems returns a CountResultItem slice.
|
|
func (GroupCountResult) CountItems() []CountResultItem { return nil }
|
|
|
|
// CountItem returns a CountResultItem
|
|
func (GroupCountResult) CountItem() CountResultItem { return CountResultItem{} }
|
|
|
|
// Count returns the result of a Count call.
|
|
func (GroupCountResult) Count() int64 { return 0 }
|
|
|
|
// Value returns the result of a Min, Max or Sum call.
|
|
func (GroupCountResult) Value() int64 { return 0 }
|
|
|
|
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
|
|
func (GroupCountResult) Changed() bool { return false }
|
|
|
|
// GroupCounts returns the result of a GroupBy call.
|
|
func (r GroupCountResult) GroupCounts() []GroupCount { return r }
|
|
|
|
// RowIdentifiers returns the result of a Rows call.
|
|
func (GroupCountResult) RowIdentifiers() RowIdentifiersResult { return RowIdentifiersResult{} }
|
|
|
|
// RowIdentifiersResult is returned from a Rows call.
|
|
type RowIdentifiersResult struct {
|
|
IDs []uint64 `json:"ids"`
|
|
Keys []string `json:"keys,omitempty"`
|
|
}
|
|
|
|
// Type is the type of this result.
|
|
func (RowIdentifiersResult) Type() uint32 { return QueryResultTypeRowIdentifiers }
|
|
|
|
// Row returns a RowResult.
|
|
func (RowIdentifiersResult) Row() RowResult { return RowResult{} }
|
|
|
|
// CountItems returns a CountResultItem slice.
|
|
func (RowIdentifiersResult) CountItems() []CountResultItem { return nil }
|
|
|
|
// CountItem returns a CountResultItem
|
|
func (RowIdentifiersResult) CountItem() CountResultItem { return CountResultItem{} }
|
|
|
|
// Count returns the result of a Count call.
|
|
func (RowIdentifiersResult) Count() int64 { return 0 }
|
|
|
|
// Value returns the result of a Min, Max or Sum call.
|
|
func (RowIdentifiersResult) Value() int64 { return 0 }
|
|
|
|
// Changed returns whether the corresponding Set or Clear call changed the value of a bit.
|
|
func (RowIdentifiersResult) Changed() bool { return false }
|
|
|
|
// GroupCounts returns the result of a GroupBy call.
|
|
func (RowIdentifiersResult) GroupCounts() []GroupCount { return nil }
|
|
|
|
// RowIdentifiers returns the result of a Rows call.
|
|
func (r RowIdentifiersResult) RowIdentifiers() RowIdentifiersResult { return r }
|
|
|
|
func groupCountsFromInternal(items *pb.GroupCounts) GroupCountResult {
|
|
result := make([]GroupCount, 0, len(items.Groups))
|
|
for _, g := range items.Groups {
|
|
groups := make([]FieldRow, 0, len(g.Group))
|
|
for _, f := range g.Group {
|
|
fr := FieldRow{
|
|
FieldName: f.Field,
|
|
RowID: f.RowID,
|
|
RowKey: f.RowKey,
|
|
}
|
|
if f.Value != nil {
|
|
fr.Value = &f.Value.Value
|
|
}
|
|
groups = append(groups, fr)
|
|
}
|
|
result = append(result, GroupCount{
|
|
Groups: groups,
|
|
Count: int64(g.Count),
|
|
Agg: int64(g.Agg),
|
|
})
|
|
}
|
|
return GroupCountResult(result)
|
|
}
|