Skip to content

Commit 1e08906

Browse files
authored
Merge pull request #835 from ydb-platform/cross-join
added cross join test + upgraded test helpers
2 parents f0769e9 + 5d0de59 commit 1e08906

File tree

2 files changed

+201
-19
lines changed

2 files changed

+201
-19
lines changed

tests/integration/helpers_test.go

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
package integration
55

66
import (
7+
"bytes"
78
"context"
89
"database/sql"
9-
"fmt"
1010
"os"
1111
"path"
1212
"testing"
13+
"text/template"
1314
"time"
1415

1516
"github.com/rekby/fixenv"
@@ -19,6 +20,7 @@ import (
1920
"github.com/ydb-platform/ydb-go-sdk/v3/log"
2021
"github.com/ydb-platform/ydb-go-sdk/v3/sugar"
2122
"github.com/ydb-platform/ydb-go-sdk/v3/table"
23+
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
2224
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
2325
)
2426

@@ -145,32 +147,80 @@ func (scope *scopeT) Folder() string {
145147
}).(string)
146148
}
147149

148-
// TableName return name (without path) to example table with struct:
149-
// id Int64 NOT NULL,
150-
// val Text
151-
func (scope *scopeT) TableName() string {
152-
return scope.Cache(nil, nil, func() (res interface{}, err error) {
153-
tableName := "table"
150+
type tableNameParams struct {
151+
tableName string
152+
createTableQueryTemplate string
153+
createTableOptions []options.CreateTableOption
154+
}
154155

155-
err = scope.Driver().Table().Do(scope.Ctx, func(ctx context.Context, s table.Session) error {
156-
query := fmt.Sprintf(`PRAGMA TablePathPrefix("%s");
156+
func withTableName(tableName string) func(t *tableNameParams) {
157+
return func(t *tableNameParams) {
158+
t.tableName = tableName
159+
}
160+
}
157161

158-
CREATE TABLE %s (
159-
id Int64 NOT NULL, val Text,
160-
PRIMARY KEY (id)
161-
)
162-
`, scope.Folder(), tableName)
162+
func withCreateTableOptions(opts ...options.CreateTableOption) func(t *tableNameParams) {
163+
return func(t *tableNameParams) {
164+
t.createTableOptions = opts
165+
}
166+
}
163167

164-
scope.Logf("Create table query: %v", query)
165-
return s.ExecuteSchemeQuery(ctx, query)
168+
func withCreateTableQueryTemplate(createTableQueryTemplate string) func(t *tableNameParams) {
169+
return func(t *tableNameParams) {
170+
t.createTableQueryTemplate = createTableQueryTemplate
171+
}
172+
}
173+
174+
// TableName return name (without path) to example table with struct:
175+
// id Int64 NOT NULL,
176+
// val Text
177+
func (scope *scopeT) TableName(opts ...func(t *tableNameParams)) string {
178+
params := tableNameParams{
179+
tableName: "table",
180+
createTableQueryTemplate: `
181+
PRAGMA TablePathPrefix("{{.TablePathPrefix}}");
182+
CREATE TABLE {{.TableName}} (
183+
id Int64 NOT NULL,
184+
val Text,
185+
PRIMARY KEY (id)
186+
)
187+
`,
188+
}
189+
for _, opt := range opts {
190+
opt(&params)
191+
}
192+
return scope.Cache(params.tableName, nil, func() (res interface{}, err error) {
193+
err = scope.Driver().Table().Do(scope.Ctx, func(ctx context.Context, s table.Session) (err error) {
194+
if len(params.createTableOptions) == 0 {
195+
tmpl, err := template.New("").Parse(params.createTableQueryTemplate)
196+
if err != nil {
197+
return err
198+
}
199+
var query bytes.Buffer
200+
err = tmpl.Execute(&query, struct {
201+
TablePathPrefix string
202+
TableName string
203+
}{
204+
TablePathPrefix: scope.Folder(),
205+
TableName: params.tableName,
206+
})
207+
if err != nil {
208+
return err
209+
}
210+
if err != nil {
211+
panic(err)
212+
}
213+
return s.ExecuteSchemeQuery(ctx, query.String())
214+
}
215+
return s.CreateTable(ctx, path.Join(scope.Folder(), params.tableName), params.createTableOptions...)
166216
})
167-
return tableName, err
217+
return params.tableName, err
168218
}).(string)
169219
}
170220

171221
// TablePath return path to example table with struct:
172222
// id Int64 NOT NULL,
173223
// val Text
174-
func (scope *scopeT) TablePath() string {
175-
return path.Join(scope.Folder(), scope.TableName())
224+
func (scope *scopeT) TablePath(opts ...func(t *tableNameParams)) string {
225+
return path.Join(scope.Folder(), scope.TableName(opts...))
176226
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
//go:build integration
2+
// +build integration
3+
4+
package integration
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"testing"
10+
11+
"github.com/stretchr/testify/require"
12+
13+
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
14+
"github.com/ydb-platform/ydb-go-sdk/v3/table"
15+
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
16+
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
17+
)
18+
19+
func TestTableCrossJoin(t *testing.T) {
20+
var (
21+
ctx = xtest.Context(t)
22+
scope = newScope(t)
23+
db = scope.Driver()
24+
table1Path = scope.TablePath(
25+
withTableName("table1"),
26+
withCreateTableOptions(
27+
options.WithColumn("p1", types.Optional(types.TypeText)),
28+
options.WithPrimaryKeyColumn("p1"),
29+
),
30+
)
31+
_ = scope.TablePath(
32+
withTableName("table2"),
33+
withCreateTableOptions(
34+
options.WithColumn("p1", types.Optional(types.TypeText)),
35+
options.WithPrimaryKeyColumn("p1"),
36+
),
37+
)
38+
)
39+
// upsert data into table1
40+
err := db.Table().Do(ctx,
41+
func(ctx context.Context, s table.Session) (err error) {
42+
return s.BulkUpsert(ctx, table1Path, types.ListValue(types.StructValue(
43+
types.StructFieldValue("p1", types.TextValue("foo")),
44+
)))
45+
},
46+
table.WithIdempotent(),
47+
)
48+
scope.Require.NoError(err)
49+
50+
for _, tt := range []struct {
51+
name string
52+
subQuery string
53+
withParams bool
54+
}{
55+
{
56+
name: "Data1FromTable1Data2FromEmptyListWithoutParams",
57+
subQuery: `
58+
$data1 = (SELECT * FROM table1);
59+
$data2 = Cast(AsList() As List<Struct<p2: Utf8>>);
60+
`,
61+
withParams: false,
62+
},
63+
{
64+
name: "Data1FromTable1Data2FromLiteralWithoutParams",
65+
subQuery: `
66+
$data1 = (SELECT * FROM table1);
67+
$data2 = Cast(AsList(AsStruct(CAST("t1" AS Utf8) AS p2)) As List<Struct<p2: Utf8>>);
68+
`,
69+
withParams: false,
70+
},
71+
// failed test-case
72+
//{
73+
// name: "Data1FromTable1DeclareData2WithParams",
74+
// subQuery: `
75+
// DECLARE $data2 AS List<Struct<p2: Utf8>>;
76+
// $data1 = (SELECT * FROM table1);
77+
// `,
78+
// withParams: true,
79+
//},
80+
{
81+
name: "Data1FromLiteralDeclareData2WithParams",
82+
subQuery: `
83+
DECLARE $data2 AS List<Struct<p2: Utf8>>;
84+
$data1 = (SELECT * FROM AS_TABLE(AsList(AsStruct(CAST("foo" AS Utf8?) AS p1))));
85+
`,
86+
withParams: true,
87+
},
88+
} {
89+
t.Run(tt.name, func(t *testing.T) {
90+
query := `--!syntax_v1
91+
PRAGMA TablePathPrefix("` + scope.Folder() + `");
92+
93+
/* sub-query */` + tt.subQuery + `
94+
/* query */
95+
UPSERT INTO table2
96+
SELECT d1.p1 AS p1,
97+
FROM $data1 AS d1
98+
CROSS JOIN AS_TABLE($data2) AS d2;
99+
100+
SELECT COUNT(*) FROM $data1;
101+
`
102+
103+
params := table.NewQueryParameters()
104+
if tt.withParams {
105+
params = table.NewQueryParameters(
106+
table.ValueParam("$data2", types.ZeroValue(types.List(types.Struct(types.StructField("p2", types.TypeUTF8))))),
107+
)
108+
}
109+
110+
var got uint64
111+
err = db.Table().Do(ctx, func(c context.Context, s table.Session) (err error) {
112+
_, res, err := s.Execute(c, table.DefaultTxControl(), query, params)
113+
if err != nil {
114+
return err
115+
}
116+
defer res.Close()
117+
if !res.NextResultSet(ctx) {
118+
return fmt.Errorf("no result set")
119+
}
120+
if !res.NextRow() {
121+
return fmt.Errorf("no rows")
122+
}
123+
if err = res.ScanWithDefaults(&got); err != nil {
124+
return err
125+
}
126+
return res.Err()
127+
}, table.WithIdempotent())
128+
require.NoError(t, err, query)
129+
require.Equal(t, uint64(1), got, query)
130+
})
131+
}
132+
}

0 commit comments

Comments
 (0)