mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 02:44:59 +00:00
Fix PQL distinct in dax (#2360)
* Fix PQL distinct in dax
When issuing a PQL Distinct() call (or any other call with a "index=" arg),
this commit will attempt to convert the value in the index arg with a
TableKeyer.
* Apply change to call.Children as well
* Add some PQL Distinct (join) test coverage
(cherry picked from commit 4e8fe488de)
This commit is contained in:
parent
211c3b759d
commit
99e3fd14d7
3 changed files with 67 additions and 4 deletions
|
|
@ -2530,7 +2530,21 @@ func (o *orchestrator) translateCall(ctx context.Context, c *pql.Call, tableKeye
|
|||
// This also applies to all child calls.
|
||||
if callIndex := c.CallIndex(); callIndex != "" {
|
||||
index = callIndex
|
||||
tableKeyer = dax.StringTableKeyer(index)
|
||||
// TODO(tlt): checking for prefix like this is bad form. Ideally, the
|
||||
// argument stored in the Call.Args map would be of type TableKey
|
||||
// (currently they are restricted to type: string). In that case we
|
||||
// could just pass it through without doing this conversion. (This would
|
||||
// require changing the logic in Queryer.convertIndex() to set "index"
|
||||
// to a TableKeyer).
|
||||
if strings.HasPrefix(index, dax.PrefixTable+dax.TableKeyDelimiter) {
|
||||
qtid, err := dax.QualifiedTableIDFromKey(index)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getting qtid from key: %s", index)
|
||||
}
|
||||
tableKeyer = qtid
|
||||
} else {
|
||||
tableKeyer = dax.StringTableKeyer(index)
|
||||
}
|
||||
}
|
||||
|
||||
idx, err := o.schemaIndexInfo(ctx, tableKeyer)
|
||||
|
|
@ -3510,6 +3524,11 @@ func (o *orchestrator) schemaFieldInfo(ctx context.Context, tableKeyer dax.Table
|
|||
tbl = &v.Table
|
||||
case *dax.Table:
|
||||
tbl = v
|
||||
case dax.QualifiedTableID:
|
||||
tbl, err = o.schema.TableByID(ctx, v.ID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getting table by id: %s", v.ID)
|
||||
}
|
||||
case dax.StringTableKeyer:
|
||||
tbl, err = o.schema.TableByName(ctx, dax.TableName(v))
|
||||
if err != nil {
|
||||
|
|
@ -3537,6 +3556,11 @@ func (o *orchestrator) schemaIndexInfo(ctx context.Context, tableKeyer dax.Table
|
|||
tbl = &v.Table
|
||||
case *dax.Table:
|
||||
tbl = v
|
||||
case dax.QualifiedTableID:
|
||||
tbl, err = o.schema.TableByID(ctx, v.ID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "getting table by id: %s", v.ID)
|
||||
}
|
||||
case dax.StringTableKeyer:
|
||||
tbl, err = o.schema.TableByName(ctx, dax.TableName(v))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -244,6 +244,28 @@ func (q *Queryer) parseAndQueryPQL(ctx context.Context, qual dax.TableQualifier,
|
|||
return q.QueryPQL(ctx, qual, dax.TableName(table), query)
|
||||
}
|
||||
|
||||
// convertIndex tries to covert any "index" specified in the call.Args map to a
|
||||
// TableKeyer. Note, since the Call.CallIndex() method currently only looks for
|
||||
// strings, we can't just set the value to a TableKeyer; we have to set it to
|
||||
// the equivalent string and then parse it back out later. A TODO would be to
|
||||
// modify Call.CallIndex() to be TableKeyer aware. I didn't do that along with
|
||||
// these changes because I'm not sure if we want to introduce dax types into the
|
||||
// pql package.
|
||||
func (q *Queryer) convertIndex(ctx context.Context, qual dax.TableQualifier, call *featurebase_pql.Call) {
|
||||
if index := call.CallIndex(); index != "" {
|
||||
qtbl, err := q.schemar.TableByName(ctx, qual, dax.TableName(index))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
call.Args["index"] = string(qtbl.Key())
|
||||
}
|
||||
|
||||
// Apply to children.
|
||||
for _, child := range call.Children {
|
||||
q.convertIndex(ctx, qual, child)
|
||||
}
|
||||
}
|
||||
|
||||
func (q *Queryer) QueryPQL(ctx context.Context, qual dax.TableQualifier, table dax.TableName, pql string) (*featurebase.WireQueryResponse, error) {
|
||||
// Parse the pql into a pql.Query containing []pql.Call.
|
||||
qry, err := featurebase_pql.NewParser(strings.NewReader(pql)).Parse()
|
||||
|
|
@ -254,6 +276,9 @@ func (q *Queryer) QueryPQL(ctx context.Context, qual dax.TableQualifier, table d
|
|||
return nil, errors.Errorf("must have exactly 1 query, but got: %+v", qry.Calls)
|
||||
}
|
||||
|
||||
// Replace any "index" arguments within the PQL with a TableKey.
|
||||
q.convertIndex(ctx, qual, qry.Calls[0])
|
||||
|
||||
qtbl, err := q.schemar.TableByName(ctx, qual, dax.TableName(table))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "converting index to qualified table")
|
||||
|
|
@ -267,10 +292,10 @@ func (q *Queryer) QueryPQL(ctx context.Context, qual dax.TableQualifier, table d
|
|||
return nil, errors.Errorf("expected single result but got %+v", results.Results)
|
||||
}
|
||||
|
||||
return PQLResultToQueryResult(results.Results[0])
|
||||
return pqlResultToQueryResult(results.Results[0])
|
||||
}
|
||||
|
||||
func PQLResultToQueryResult(pqlResult interface{}) (*featurebase.WireQueryResponse, error) {
|
||||
func pqlResultToQueryResult(pqlResult interface{}) (*featurebase.WireQueryResponse, error) {
|
||||
toTabler, err := server.ToTablerWrapper(pqlResult)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "wrapping as type ToTabler")
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ var joinTestsOrders = TableTest{
|
|||
"orders",
|
||||
srcHdrs(
|
||||
srcHdr("_id", fldTypeID),
|
||||
srcHdr("userid", fldTypeID),
|
||||
srcHdr("userid", fldTypeInt),
|
||||
srcHdr("price", fldTypeDecimal2),
|
||||
),
|
||||
srcRows(
|
||||
|
|
@ -103,4 +103,18 @@ var joinTests = TableTest{
|
|||
Compare: CompareExactOrdered,
|
||||
},
|
||||
},
|
||||
PQLTests: []PQLTest{
|
||||
{
|
||||
name: "distinctjoin",
|
||||
Table: "users",
|
||||
PQLs: []string{"Intersect(Distinct(Row(price > 10), index=orders, field=userid))"},
|
||||
ExpHdrs: hdrs(
|
||||
hdr("_id", fldTypeID),
|
||||
),
|
||||
ExpRows: rows(
|
||||
row(int64(1)),
|
||||
row(int64(2)),
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue