Skip to content

Commit 89ee281

Browse files
authored
feat: add EmptyVirtualTable to Builder interface (#167)
1 parent 63c836e commit 89ee281

File tree

3 files changed

+60
-22
lines changed

3 files changed

+60
-22
lines changed

plan/builders.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ type Builder interface {
124124
// Deprecated: Use VirtualTableFromExpr(...).Remap() instead.
125125
VirtualTableFromExprRemap(fieldNames []string, remap []int32, values ...expr.VirtualTableExpressionValue) (*VirtualTableReadRel, error)
126126
VirtualTableFromExpr(fieldNames []string, values ...expr.VirtualTableExpressionValue) (*VirtualTableReadRel, error)
127+
EmptyVirtualTable(fieldNames []string, types []types.Type) (*VirtualTableReadRel, error)
127128
IcebergTableFromMetadataFile(metadataURI string, snapshot IcebergSnapshot, schema types.NamedStruct) (*IcebergTableReadRel, error)
128129
// Deprecated: Use Sort(...).Remap() instead.
129130
SortRemap(input Rel, remap []int32, sorts ...expr.SortField) (*SortRel, error)
@@ -568,7 +569,7 @@ func (b *builder) VirtualTableFromExpr(fieldNames []string, values ...expr.Virtu
568569

569570
func (b *builder) VirtualTableFromExprRemap(fieldNames []string, remap []int32, values ...expr.VirtualTableExpressionValue) (*VirtualTableReadRel, error) {
570571
if len(values) == 0 {
571-
return nil, fmt.Errorf("%w: must provide at least one set of values for virtual table", substraitgo.ErrInvalidRel)
572+
return nil, fmt.Errorf("%w: must provide at least one set of values. Consider EmptyVirtualTable to construct rowless Virtual Table", substraitgo.ErrInvalidArg)
572573
}
573574

574575
nfields := len(fieldNames)
@@ -619,6 +620,21 @@ func (b *builder) VirtualTable(fields []string, values ...expr.StructLiteralValu
619620
return b.VirtualTableRemap(fields, nil, values...)
620621
}
621622

623+
func (b *builder) EmptyVirtualTable(fieldNames []string, typeList []types.Type) (*VirtualTableReadRel, error) {
624+
baseSchema := types.NamedStruct{
625+
Names: fieldNames,
626+
Struct: types.StructType{
627+
Nullability: types.NullabilityRequired,
628+
Types: typeList,
629+
},
630+
}
631+
return &VirtualTableReadRel{
632+
baseReadRel: baseReadRel{
633+
baseSchema: baseSchema,
634+
},
635+
}, nil
636+
}
637+
622638
func (b *builder) IcebergTableFromMetadataFile(metadataURI string, snapshot IcebergSnapshot, schema types.NamedStruct) (*IcebergTableReadRel, error) {
623639
tableType := &Direct{}
624640
tableType.MetadataUri = metadataURI

plan/plan.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ func RelFromProto(rel *proto.Rel, reg expr.ExtensionRegistry) (Rel, error) {
368368
}
369369
case *proto.ReadRel_VirtualTable_:
370370
if len(readType.VirtualTable.Values) > 0 && len(readType.VirtualTable.Expressions) > 0 {
371-
return nil, fmt.Errorf("VirtualTable Value can't have both liternal and expression")
371+
return nil, fmt.Errorf("VirtualTable cannot declare both Values and Expressions")
372372
}
373373
var values []expr.VirtualTableExpressionValue
374374
for _, v := range readType.VirtualTable.Values {

plan/plan_builder_test.go

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,7 +1651,7 @@ func TestSetRelations(t *testing.T) {
16511651
checkRoundTrip(t, expectedJSON, p)
16521652
}
16531653

1654-
func TestEmptyVirtualTable(t *testing.T) {
1654+
func TestColumnlessVirtualTable(t *testing.T) {
16551655
const expectedJSON = `{
16561656
` + versionStruct + `,
16571657
"relations": [
@@ -1669,24 +1669,7 @@ func TestEmptyVirtualTable(t *testing.T) {
16691669
"expressions": [
16701670
{},
16711671
{},
1672-
{},
1673-
{},
1674-
{},
1675-
{},
1676-
{},
1677-
{},
1678-
{},
1679-
{},
1680-
{},
1681-
{},
1682-
{},
1683-
{},
1684-
{},
1685-
{},
1686-
{},
1687-
{},
1688-
{},
1689-
{}
1672+
{}
16901673
]
16911674
}
16921675
}
@@ -1698,7 +1681,7 @@ func TestEmptyVirtualTable(t *testing.T) {
16981681

16991682
b := plan.NewBuilderDefault()
17001683

1701-
virtual, err := b.VirtualTable(nil, make([]expr.StructLiteralValue, 20)...)
1684+
virtual, err := b.VirtualTable(nil, make([]expr.StructLiteralValue, 3)...)
17021685
require.NoError(t, err)
17031686

17041687
p, err := b.Plan(virtual, []string{})
@@ -1707,6 +1690,45 @@ func TestEmptyVirtualTable(t *testing.T) {
17071690
checkRoundTrip(t, expectedJSON, p)
17081691
}
17091692

1693+
func TestEmptyVirtualTable(t *testing.T) {
1694+
const expectedJSON = `{
1695+
` + versionStruct + `,
1696+
"relations": [
1697+
{
1698+
"root": {
1699+
"input": {
1700+
"read": {
1701+
"common": {"direct":{}},
1702+
"baseSchema": {
1703+
"names": ["i"],
1704+
"struct": {
1705+
"types": [
1706+
{"i32": {"nullability": "NULLABILITY_REQUIRED"}}
1707+
],
1708+
"nullability": "NULLABILITY_REQUIRED"
1709+
}
1710+
},
1711+
"virtualTable": {}
1712+
}
1713+
},
1714+
"names": ["i"]
1715+
}
1716+
}
1717+
]
1718+
}`
1719+
1720+
b := plan.NewBuilderDefault()
1721+
1722+
i32Type := types.Int32Type{Nullability: types.NullabilityRequired}
1723+
virtual, err := b.EmptyVirtualTable([]string{"i"}, []types.Type{&i32Type})
1724+
require.NoError(t, err)
1725+
1726+
p, err := b.Plan(virtual, []string{"i"})
1727+
require.NoError(t, err)
1728+
1729+
checkRoundTrip(t, expectedJSON, p)
1730+
}
1731+
17101732
func TestSetRelErrors(t *testing.T) {
17111733
b := plan.NewBuilderDefault()
17121734

0 commit comments

Comments
 (0)