Skip to content

Commit

Permalink
* Added implementation of database/sql driver over query service cl…
Browse files Browse the repository at this point in the history
…ient

* Added `ydb.WithQueryService(bool)` option to explicitly enable `database/sql` driver over query service client
* Added environment parameter `YDB_DATABASE_SQL_OVER_QUERY_SERVICE` to enable `database/sql` driver over query service client without code rewriting
  • Loading branch information
asmyasnikov committed Dec 12, 2024
1 parent 6022f09 commit fd4142d
Show file tree
Hide file tree
Showing 49 changed files with 1,411 additions and 860 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
* Added implementation of `database/sql` driver over query service client
* Added `ydb.WithQueryService(bool)` option to explicitly enable `database/sql` driver over query service client
* Added environment parameter `YDB_DATABASE_SQL_OVER_QUERY_SERVICE` to enable `database/sql` driver over query service client without code rewriting

## v3.94.0
* Refactored golang types mapping into ydb types using `ydb.ParamsFromMap` and `database/sql` query arguments
* Small breaking change: type mapping for `ydb.ParamsFromMap` and `database/sql` type `uuid.UUID` changed from ydb type `Text` to ydb type `UUID`
Expand Down
42 changes: 32 additions & 10 deletions dsn.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/dsn"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/conn/table"
)

const tablePathPrefixTransformer = "table_path_prefix"
Expand Down Expand Up @@ -44,6 +43,22 @@ func UnregisterDsnParser(registrationID int) {
dsnParsers[registrationID] = nil
}

var stringToType = map[string]QueryMode{
"data": DataQueryMode,
"scan": ScanQueryMode,
"scheme": SchemeQueryMode,
"scripting": ScriptingQueryMode,
"query": QueryExecuteQueryMode,
}

func queryModeFromString(s string) QueryMode {
if t, ok := stringToType[s]; ok {
return t
}

return unknownQueryMode
}

//nolint:funlen
func parseConnectionString(dataSourceName string) (opts []Option, _ error) {
info, err := dsn.Parse(dataSourceName)
Expand All @@ -60,25 +75,32 @@ func parseConnectionString(dataSourceName string) (opts []Option, _ error) {
opts = append(opts, WithBalancer(balancers.FromConfig(balancer)))
}
if queryMode := info.Params.Get("go_query_mode"); queryMode != "" {
mode := table.QueryModeFromString(queryMode)
if mode == table.UnknownQueryMode {
switch mode := queryModeFromString(queryMode); mode {
case QueryExecuteQueryMode:
opts = append(opts, withConnectorOptions(xsql.WithQueryService(true)))
case unknownQueryMode:
return nil, xerrors.WithStackTrace(fmt.Errorf("unknown query mode: %s", queryMode))
default:
opts = append(opts, withConnectorOptions(xsql.WithDefaultQueryMode(modeToMode(mode))))
}
opts = append(opts, withConnectorOptions(xsql.WithDefaultQueryMode(mode)))
} else if queryMode := info.Params.Get("query_mode"); queryMode != "" {
mode := table.QueryModeFromString(queryMode)
if mode == table.UnknownQueryMode {
switch mode := queryModeFromString(queryMode); mode {
case QueryExecuteQueryMode:
opts = append(opts, withConnectorOptions(xsql.WithQueryService(true)))
case unknownQueryMode:
return nil, xerrors.WithStackTrace(fmt.Errorf("unknown query mode: %s", queryMode))
default:
opts = append(opts, withConnectorOptions(xsql.WithDefaultQueryMode(modeToMode(mode))))
}
opts = append(opts, withConnectorOptions(xsql.WithDefaultQueryMode(mode)))
}
if fakeTx := info.Params.Get("go_fake_tx"); fakeTx != "" {
for _, queryMode := range strings.Split(fakeTx, ",") {
mode := table.QueryModeFromString(queryMode)
if mode == table.UnknownQueryMode {
switch mode := queryModeFromString(queryMode); mode {
case unknownQueryMode:
return nil, xerrors.WithStackTrace(fmt.Errorf("unknown query mode: %s", queryMode))
default:
opts = append(opts, withConnectorOptions(WithFakeTx(mode)))
}
opts = append(opts, withConnectorOptions(xsql.WithFakeTx(mode)))
}
}
if info.Params.Has("go_query_bind") {
Expand Down
42 changes: 21 additions & 21 deletions dsn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/config"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/bind"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/conn/query"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/conn/table"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/legacy"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/propose"
)

func TestParse(t *testing.T) {
Expand All @@ -26,11 +26,11 @@ func TestParse(t *testing.T) {

return c
}
newTableConn := func(opts ...table.Option) *table.Conn {
return table.New(context.Background(), nil, nil, opts...)
newLegacyConn := func(opts ...legacy.Option) *legacy.Conn {
return legacy.New(context.Background(), nil, nil, opts...)
}
newQueryConn := func(opts ...query.Option) *query.Conn {
return query.New(context.Background(), nil, nil, opts...)
newQueryConn := func(opts ...propose.Option) *propose.Conn {
return propose.New(context.Background(), nil, nil, opts...)
}
compareConfigs := func(t *testing.T, lhs, rhs *config.Config) {
require.Equal(t, lhs.Secure(), rhs.Secure())
Expand Down Expand Up @@ -71,7 +71,7 @@ func TestParse(t *testing.T) {
config.WithDatabase("/local"),
},
connectorOpts: []xsql.Option{
xsql.WithDefaultQueryMode(table.ScriptingQueryMode),
xsql.WithDefaultQueryMode(legacy.ScriptingQueryMode),
},
err: nil,
},
Expand All @@ -83,7 +83,7 @@ func TestParse(t *testing.T) {
config.WithDatabase("/local"),
},
connectorOpts: []xsql.Option{
xsql.WithDefaultQueryMode(table.ScriptingQueryMode),
xsql.WithDefaultQueryMode(legacy.ScriptingQueryMode),
xsql.WithQueryBind(bind.TablePathPrefix("path/to/tables")),
},
err: nil,
Expand All @@ -96,7 +96,7 @@ func TestParse(t *testing.T) {
config.WithDatabase("/local"),
},
connectorOpts: []xsql.Option{
xsql.WithDefaultQueryMode(table.ScriptingQueryMode),
xsql.WithDefaultQueryMode(legacy.ScriptingQueryMode),
xsql.WithQueryBind(bind.TablePathPrefix("path/to/tables")),
xsql.WithQueryBind(bind.NumericArgs{}),
},
Expand All @@ -110,7 +110,7 @@ func TestParse(t *testing.T) {
config.WithDatabase("/local"),
},
connectorOpts: []xsql.Option{
xsql.WithDefaultQueryMode(table.ScriptingQueryMode),
xsql.WithDefaultQueryMode(legacy.ScriptingQueryMode),
xsql.WithQueryBind(bind.TablePathPrefix("path/to/tables")),
xsql.WithQueryBind(bind.PositionalArgs{}),
},
Expand All @@ -124,7 +124,7 @@ func TestParse(t *testing.T) {
config.WithDatabase("/local"),
},
connectorOpts: []xsql.Option{
xsql.WithDefaultQueryMode(table.ScriptingQueryMode),
xsql.WithDefaultQueryMode(legacy.ScriptingQueryMode),
xsql.WithQueryBind(bind.TablePathPrefix("path/to/tables")),
xsql.WithQueryBind(bind.AutoDeclare{}),
},
Expand All @@ -138,7 +138,7 @@ func TestParse(t *testing.T) {
config.WithDatabase("/local"),
},
connectorOpts: []xsql.Option{
xsql.WithDefaultQueryMode(table.ScriptingQueryMode),
xsql.WithDefaultQueryMode(legacy.ScriptingQueryMode),
xsql.WithQueryBind(bind.TablePathPrefix("path/to/tables")),
},
err: nil,
Expand All @@ -151,7 +151,7 @@ func TestParse(t *testing.T) {
config.WithDatabase("/local"),
},
connectorOpts: []xsql.Option{
xsql.WithDefaultQueryMode(table.ScriptingQueryMode),
xsql.WithDefaultQueryMode(legacy.ScriptingQueryMode),
xsql.WithQueryBind(bind.TablePathPrefix("path/to/tables")),
xsql.WithQueryBind(bind.PositionalArgs{}),
xsql.WithQueryBind(bind.AutoDeclare{}),
Expand All @@ -166,8 +166,8 @@ func TestParse(t *testing.T) {
config.WithDatabase("/local"),
},
connectorOpts: []xsql.Option{
xsql.WithFakeTx(table.ScriptingQueryMode),
xsql.WithFakeTx(table.SchemeQueryMode),
WithFakeTx(ScriptingQueryMode),
WithFakeTx(SchemeQueryMode),
},
err: nil,
},
Expand All @@ -183,15 +183,15 @@ func TestParse(t *testing.T) {
exp := newConnector(tt.connectorOpts...)
act := newConnector(d.databaseSQLOptions...)
t.Run("tableOptions", func(t *testing.T) {
require.Equal(t, newTableConn(exp.TableOpts...), newTableConn(act.TableOpts...))
require.Equal(t, newLegacyConn(exp.LegacyOpts...), newLegacyConn(act.LegacyOpts...))
})
t.Run("queryOptions", func(t *testing.T) {
require.Equal(t, newQueryConn(exp.QueryOpts...), newQueryConn(act.QueryOpts...))
require.Equal(t, newQueryConn(exp.Options...), newQueryConn(act.Options...))
})
exp.TableOpts = nil
exp.QueryOpts = nil
act.TableOpts = nil
act.QueryOpts = nil
exp.LegacyOpts = nil
exp.Options = nil
act.LegacyOpts = nil
act.Options = nil
require.Equal(t, exp.Bindings(), act.Bindings())
require.Equal(t, exp, act)
compareConfigs(t, config.New(tt.opts...), d.config)
Expand Down
2 changes: 1 addition & 1 deletion internal/stack/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func buildRecordString(
) string {
buffer := xstring.Buffer()
defer buffer.Free()
if optionsHolder.packageAlias != "" {
if optionsHolder.packageAlias != "" { //nolint:nestif
buffer.WriteString(optionsHolder.packageAlias)
} else {
if optionsHolder.packagePath {
Expand Down
Loading

0 comments on commit fd4142d

Please sign in to comment.