Skip to content

Commit fd46135

Browse files
committed
* Changed output of sugar.GenerateDeclareSection (added error as second result)
* Specified `sugar.GenerateDeclareSection` for `go1.18` (supports input types `*table.QueryParameters` `[]table.ParameterOption` or `[]sql.NamedArg`) * Added `database/sql` example and docs (WIP)
1 parent 9647f92 commit fd46135

File tree

11 files changed

+252
-85
lines changed

11 files changed

+252
-85
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
* Changed output of `sugar.GenerateDeclareSection` (added error as second result)
2+
* Specified `sugar.GenerateDeclareSection` for `go1.18` (supports input types `*table.QueryParameters` `[]table.ParameterOption` or `[]sql.NamedArg`)
3+
* Added `database/sql` example and docs (WIP)
4+
15
## v3.36.1
26
* Fixed `xsql.Rows` error checking
37

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ if queryErr != nil {
5959
log.Fatal(queryErr)
6060
}
6161
```
62-
* usage with `database/sql`
62+
* usage with `database/sql` (see additional docs in [SQL.md](SQL.md) )
6363
```golang
6464
import (
6565
"context"

SQL.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# `database/sql` driver for `YDB`
2+
3+
## Initialization of `database/sql` driver
4+
5+
### Configure driver with `ydb.Connector` (recommended way)
6+
```
7+
import (
8+
"github.com/ydb-platform/ydb-go-sdk/v3"
9+
)
10+
11+
func main() {
12+
// init native ydb-go-sdk driver
13+
nativeDriver, err := ydb.Open(context.TODO(), "grpcs://localhost:2135/local",
14+
// See many ydb.Option's for configure driver
15+
)
16+
if err != nil {
17+
// fallback on error
18+
}
19+
connector, err := ydb.Connector(nativeDriver,
20+
// See ydb.ConnectorOption's for configure connector
21+
)
22+
if err != nil {
23+
// fallback on error
24+
}
25+
db := sql.OpenDB(connector)
26+
}
27+
```
28+
### Configure driver only with data source name (connection string)
29+
```
30+
import (
31+
_ "github.com/ydb-platform/ydb-go-sdk/v3"
32+
)
33+
34+
func main() {
35+
db, err := sql.Open("ydb", "grpcs://localhost:2135/local")
36+
}
37+
```
38+
Data source name parameters:
39+
* `token` – access token to be used during requests (required)
40+
* static credentials with authority part of URI, like `grpcs://root:password@localhost:2135/local`
41+
* `query_mode=scripting` - you can redefine default `data` query mode
42+
43+
## Execute queries
44+
45+
### On database object
46+
47+
### With transaction
48+
49+
## Query modes
50+
51+
## Specify `YDB` transaction control
52+
53+
## Retryer's for `YDB` `database/sql` driver
54+
55+
### Over `sql.Conn` object
56+
57+
### Over `sql.Tx`

doc.go

Lines changed: 0 additions & 7 deletions
This file was deleted.

example_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,31 @@ func Example_table() {
5555
}
5656
}
5757

58+
func Example_databaseSQL() {
59+
db, err := sql.Open("ydb", "grpcs://localhost:2135/local")
60+
if err != nil {
61+
log.Fatal(err)
62+
}
63+
defer db.Close() // cleanup resources
64+
65+
var (
66+
query = `SELECT 42 as id, "my string" as myStr`
67+
id int32 // required value
68+
myStr string // optional value
69+
)
70+
err = retry.DoTx(context.TODO(), db, func(ctx context.Context, tx *sql.Tx) error {
71+
row := tx.QueryRowContext(ctx, query)
72+
if err = row.Scan(&id, &myStr); err != nil {
73+
return err
74+
}
75+
log.Printf("id=%v, myStr='%s'\n", id, myStr)
76+
return nil
77+
}, retry.WithDoTxRetryOptions(retry.WithIdempotent(true)))
78+
if err != nil {
79+
log.Fatal(err)
80+
}
81+
}
82+
5883
func Example_databaseSql() {
5984
db, err := sql.Open("ydb", "grpcs://localhost:2135/local")
6085
if err != nil {

internal/table/params.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ import (
55
"fmt"
66
"sort"
77

8+
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
89
"github.com/ydb-platform/ydb-go-sdk/v3/table"
910
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
1011
)
1112

13+
var ErrNameRequired = xerrors.Wrap(fmt.Errorf("ydb: only named parameters are supported"))
14+
1215
// GenerateDeclareSection generates DECLARE section text in YQL query by params
1316
//
1417
// Warning: This is an experimental feature and could change at any time
15-
func GenerateDeclareSection(params *table.QueryParameters) string {
18+
func GenerateDeclareSection(params *table.QueryParameters) (string, error) {
1619
var (
1720
buf bytes.Buffer
1821
names []string
@@ -28,7 +31,10 @@ func GenerateDeclareSection(params *table.QueryParameters) string {
2831
})
2932
sort.Strings(names)
3033
for _, name := range names {
34+
if name == "" {
35+
return "", xerrors.WithStackTrace(ErrNameRequired)
36+
}
3137
buf.WriteString(declares[name])
3238
}
33-
return buf.String()
39+
return buf.String(), nil
3440
}

internal/xsql/conn.go

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"database/sql/driver"
77
"fmt"
88
"sync/atomic"
9-
"time"
109

1110
"github.com/ydb-platform/ydb-go-sdk/v3/internal/retry"
1211
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
@@ -15,7 +14,6 @@ import (
1514
"github.com/ydb-platform/ydb-go-sdk/v3/table"
1615
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
1716
"github.com/ydb-platform/ydb-go-sdk/v3/table/result"
18-
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
1917
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
2018
)
2119

@@ -112,56 +110,7 @@ func (c *conn) setClosed() {
112110
}
113111

114112
func (conn) CheckNamedValue(v *driver.NamedValue) (err error) {
115-
if v.Name == "" {
116-
return fmt.Errorf("ydb: only named parameters are supported")
117-
}
118-
119-
if valuer, ok := v.Value.(driver.Valuer); ok {
120-
v.Value, err = valuer.Value()
121-
if err != nil {
122-
return fmt.Errorf("ydb: driver.Valuer error: %w", err)
123-
}
124-
}
125-
126-
switch x := v.Value.(type) {
127-
case types.Value:
128-
// OK.
129-
case bool:
130-
v.Value = types.BoolValue(x)
131-
case int8:
132-
v.Value = types.Int8Value(x)
133-
case uint8:
134-
v.Value = types.Uint8Value(x)
135-
case int16:
136-
v.Value = types.Int16Value(x)
137-
case uint16:
138-
v.Value = types.Uint16Value(x)
139-
case int32:
140-
v.Value = types.Int32Value(x)
141-
case uint32:
142-
v.Value = types.Uint32Value(x)
143-
case int64:
144-
v.Value = types.Int64Value(x)
145-
case uint64:
146-
v.Value = types.Uint64Value(x)
147-
case float32:
148-
v.Value = types.FloatValue(x)
149-
case float64:
150-
v.Value = types.DoubleValue(x)
151-
case []byte:
152-
v.Value = types.StringValue(x)
153-
case string:
154-
v.Value = types.UTF8Value(x)
155-
case [16]byte:
156-
v.Value = types.UUIDValue(x)
157-
case time.Time:
158-
v.Value = types.DateValueFromTime(x)
159-
160-
default:
161-
return xerrors.WithStackTrace(fmt.Errorf("ydb: unsupported type: %T", x))
162-
}
163-
164-
return nil
113+
return checkNamedValue(v)
165114
}
166115

167116
func (c *conn) PrepareContext(ctx context.Context, query string) (_ driver.Stmt, err error) {

internal/xsql/convert.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package xsql
2+
3+
import (
4+
"database/sql"
5+
"database/sql/driver"
6+
"fmt"
7+
internal "github.com/ydb-platform/ydb-go-sdk/v3/internal/table"
8+
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
9+
"time"
10+
11+
"github.com/ydb-platform/ydb-go-sdk/v3/table"
12+
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
13+
)
14+
15+
func toQueryParams(values []driver.NamedValue) *table.QueryParameters {
16+
if len(values) == 0 {
17+
return nil
18+
}
19+
opts := make([]table.ParameterOption, len(values))
20+
for i, arg := range values {
21+
switch v := arg.Value.(type) {
22+
case types.Value:
23+
opts[i] = table.ValueParam(arg.Name, arg.Value.(types.Value))
24+
case table.ParameterOption:
25+
opts[i] = v
26+
case *table.QueryParameters:
27+
if len(values) != 1 {
28+
panic("only one arg with type *table.QueryParameters are supported")
29+
}
30+
return v
31+
default:
32+
panic(fmt.Sprintf("unsupported type: %T", v))
33+
}
34+
}
35+
return table.NewQueryParameters(opts...)
36+
}
37+
38+
func primitiveToValue(v interface{}) (value types.Value, err error) {
39+
if valuer, ok := v.(driver.Valuer); ok {
40+
v, err = valuer.Value()
41+
if err != nil {
42+
return nil, fmt.Errorf("ydb: driver.Valuer error: %w", err)
43+
}
44+
}
45+
46+
switch x := v.(type) {
47+
case types.Value:
48+
return x, nil
49+
case bool:
50+
return types.BoolValue(x), nil
51+
case int8:
52+
return types.Int8Value(x), nil
53+
case uint8:
54+
return types.Uint8Value(x), nil
55+
case int16:
56+
return types.Int16Value(x), nil
57+
case uint16:
58+
return types.Uint16Value(x), nil
59+
case int32:
60+
return types.Int32Value(x), nil
61+
case uint32:
62+
return types.Uint32Value(x), nil
63+
case int64:
64+
return types.Int64Value(x), nil
65+
case uint64:
66+
return types.Uint64Value(x), nil
67+
case float32:
68+
return types.FloatValue(x), nil
69+
case float64:
70+
return types.DoubleValue(x), nil
71+
case []byte:
72+
return types.StringValue(x), nil
73+
case string:
74+
return types.UTF8Value(x), nil
75+
case [16]byte:
76+
return types.UUIDValue(x), nil
77+
case time.Time:
78+
return types.DateValueFromTime(x), nil
79+
default:
80+
return nil, xerrors.WithStackTrace(fmt.Errorf("ydb: unsupported type: %T", x))
81+
}
82+
}
83+
84+
func checkNamedValue(v *driver.NamedValue) (err error) {
85+
if v.Name == "" {
86+
switch v.Value.(type) {
87+
case table.ParameterOption:
88+
return nil
89+
case *table.QueryParameters:
90+
return nil
91+
default:
92+
return xerrors.WithStackTrace(internal.ErrNameRequired)
93+
}
94+
}
95+
96+
value, err := primitiveToValue(v.Value)
97+
if err != nil {
98+
return xerrors.WithStackTrace(err)
99+
}
100+
101+
v.Value = value
102+
103+
return nil
104+
}
105+
106+
// GenerateDeclareSection generates DECLARE section text in YQL query by params
107+
//
108+
// Warning: This is an experimental feature and could change at any time
109+
func GenerateDeclareSection(args []sql.NamedArg) (string, error) {
110+
values := make([]table.ParameterOption, len(args))
111+
for i, arg := range args {
112+
if arg.Name == "" {
113+
return "", xerrors.WithStackTrace(internal.ErrNameRequired)
114+
}
115+
value, err := primitiveToValue(arg.Value)
116+
if err != nil {
117+
return "", xerrors.WithStackTrace(err)
118+
}
119+
values[i] = table.ValueParam(arg.Name, value)
120+
}
121+
return internal.GenerateDeclareSection(table.NewQueryParameters(values...))
122+
}

internal/xsql/xsql.go

Lines changed: 0 additions & 22 deletions
This file was deleted.

sugar/params.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//go:build !go1.18
2+
// +build !go1.18
3+
14
package sugar
25

36
import (
@@ -8,6 +11,6 @@ import (
811
// GenerateDeclareSection generates DECLARE section text in YQL query by params
912
//
1013
// Warning: This is an experimental feature and could change at any time
11-
func GenerateDeclareSection(params *table.QueryParameters) string {
14+
func GenerateDeclareSection(params *table.QueryParameters) (string, error) {
1215
return internal.GenerateDeclareSection(params)
1316
}

0 commit comments

Comments
 (0)